# Learn Rux ::warning Rux is still in active development. As the language matures some syntax and features may change, and the course changes with it — every lesson is checked against the current compiler. :: Welcome to Rux — a fast, compiled, strongly typed, multi-paradigm language that ships as a single small binary. This course takes you from installing the toolchain to writing complete programs. It assumes no Rux at all, and only a little programming: if you know what a variable and a loop are, you are ready. ## How the course works Every lesson teaches **one idea** and is backed by **one small package** in the [Rux Examples repository](https://github.com/rux-lang/Examples){rel=""nofollow""}. The package is a real program: it compiles, it runs, and its comments explain each line. A lesson page walks you through that program, shows what it prints, and points out the mistakes beginners usually make. - **Read** the lesson page, top to bottom. - **Run** the package with `rux run` and compare the output with the page. - **Change** something — a value, a condition, a type — and run it again. Breaking a program on purpose and reading the compiler's message is one of the fastest ways to learn. - **Move on** with the *Next* link at the bottom of the page. Each lesson lists the lessons it needs, so you can also jump around. ```mermaid flowchart LR read["Read the lesson"] --> run["`rux run`"] run --> compare["Compare the output"] compare --> change["Change the code"] change --> check["`rux check`"] check -- "error: read the message" --> change check -- "it compiles" --> run compare -- "understood" --> next["Next lesson"] ``` ## The road map Parts 1–17 build the language step by step and are best read in order. Parts 18–26 tour the standard packages: once the language parts are done, take them in any order. Part 27 holds complete small programs, each one a *checkpoint* you can attempt as soon as you have finished the part marked with its flag. :learn-roadmap ## Start here ::steps{level="3"} ### Install the toolchain Install `rux` on [Windows](https://rux-lang.dev/docs/learn/install/windows), [Linux](https://rux-lang.dev/docs/learn/install/linux), [macOS](https://rux-lang.dev/docs/learn/install/macos) or [FreeBSD](https://rux-lang.dev/docs/learn/install/freebsd) — or [build it from source](https://rux-lang.dev/docs/learn/build) on any other platform. Prebuilt binaries cover x86-64 and AArch64. ### Set up your editor Add Rux syntax highlighting to [Visual Studio Code](https://rux-lang.dev/docs/learn/editors/vscode), [Sublime Text](https://rux-lang.dev/docs/learn/editors/sublime) or [Zed](https://rux-lang.dev/docs/learn/editors/zed). ### Build your first project [Create, build and run a project](https://rux-lang.dev/docs/learn/first-project) of your own, then clone the Examples repository the lessons are built on. ### Take the first lesson Start with [1.1 Hello, World](https://rux-lang.dev/docs/learn/hello) and follow the *Next* links from there. :: ::tip **No install yet?**:br The [Playground](https://rux-lang.dev/play) runs the compiler in your browser. Paste any snippet from a lesson to try it straight away. :: ## Checkpoint projects Each project in Part 27 combines what the earlier parts taught into one complete program. Try to write it yourself first, then compare with the lesson. | After | Projects | | ---------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | 3. Control flow | [Thanks](https://rux-lang.dev/docs/learn/thanks), [FizzBuzz](https://rux-lang.dev/docs/learn/fizz-buzz) | | 4. Functions | [Temperature](https://rux-lang.dev/docs/learn/temperature) | | 5. Sequences | [Prime](https://rux-lang.dev/docs/learn/prime) | | 9. Errors | [Calculator](https://rux-lang.dev/docs/learn/calculator) | | 16. Numbers | [Circle](https://rux-lang.dev/docs/learn/circle), [Quadratic](https://rux-lang.dev/docs/learn/quadratic) | | 17. Collections | [Word count](https://rux-lang.dev/docs/learn/word-count), [Inventory](https://rux-lang.dev/docs/learn/inventory) | | 18. Algorithms | [Statistics](https://rux-lang.dev/docs/learn/statistics) | | 20. Utilities | [Guess](https://rux-lang.dev/docs/learn/guess), [Age](https://rux-lang.dev/docs/learn/age), [Password](https://rux-lang.dev/docs/learn/password), [Launch](https://rux-lang.dev/docs/learn/launch) | | 21. Data formats | [Notes](https://rux-lang.dev/docs/learn/notes) | | 24. Platform | [Melody](https://rux-lang.dev/docs/learn/melody) | | 26. Systems | [Grep](https://rux-lang.dev/docs/learn/grep) | ## Learn with an AI assistant Claude Code, Codex and similar coding assistants make good study partners: they can explain a lesson line by line, quiz you, and review your own version of a program. Rux is a new language, so they need a little context first — [Learn Rux with AI](https://rux-lang.dev/docs/learn/ai) shows how to set that up. Every lesson page also has **Copy page** and **Open in Claude / ChatGPT** buttons that hand the lesson to an assistant for you. ## Going further The course teaches by example. When you want the full rules, the [Rux Reference](https://rux-lang.dev/docs/lang) specifies the language, the [CLI Reference](https://rux-lang.dev/docs/cli) documents every `rux` command, and the [API Reference](https://rux-lang.dev/docs/api) lists the standard packages. The [cheat sheet](https://rux-lang.dev/docs/learn/cheatsheet) puts the syntax from the whole course on one page. # Install on FreeBSD This guide explains how to install the Rux compiler on FreeBSD from the prebuilt release tarball. There is no native `pkg` package yet. ## Prerequisites - FreeBSD 14.4 or newer, on x86-64 or AArch64 - `fetch` or `curl` to download the release - `tar` to extract the archive ## Manual Install Download the tarball for your architecture — `x86_64` for amd64 machines, `aarch64` for arm64: ```sh fetch https://github.com/rux-lang/Rux/releases/latest/download/rux-freebsd-x86_64.tar.gz ``` Extract the archive: ```sh tar -xzf rux-freebsd-x86_64.tar.gz ``` Move the extracted `rux` binary somewhere on your `PATH`: ```sh su -m root -c 'install -m 755 rux /usr/local/bin/rux' ``` ## Verify the Installation ```sh rux version ``` You should see the installed Rux compiler version. ## Other BSDs OpenBSD, NetBSD, and DragonFly BSD have no prebuilt binaries and are not covered by continuous testing. On those systems, [build the compiler from source](https://rux-lang.dev/docs/learn/build). ## Releases All Rux releases are available on [GitHub](https://github.com/rux-lang/Rux/releases){rel=""nofollow""}. # Install on Linux This guide explains how to install the Rux compiler on Linux — using the universal install script, your distribution's package manager, or the prebuilt release tarball. ## Prerequisites - A 64-bit (x86-64) Linux distribution - `curl` or `wget` to download the release - `tar` to extract the archive (for the manual install) ## Quick Install (Script) The fastest way to install on **any** distribution is the per-user install script. It downloads the latest release, installs the `rux` binary into `~/.local/bin` (no root required), and adds that directory to your `PATH`: ```sh curl -fsSL https://rux-lang.dev/install.sh | sh ``` The script accepts a few options — for example, install a specific version or a custom directory: ```sh curl -fsSL https://rux-lang.dev/install.sh | sh -s -- --version 0.3.0 --dir /usr/local/bin ``` Run it with `--help` to see all options. ## Manual Install On Ubuntu, Debian, or any other distribution without a dedicated package, use the prebuilt tarball. Download the latest Linux tarball: ```sh curl -LO https://github.com/rux-lang/Rux/releases/latest/download/rux-linux.tar.gz ``` Extract the archive: ```sh tar -xzf rux-linux.tar.gz ``` Move the extracted `rux` binary somewhere on your `PATH`: ```sh sudo mv rux /usr/local/bin/rux ``` ## Verify the Installation ```sh rux version ``` You should see the installed Rux compiler version. ## Releases All Rux releases are available on [GitHub](https://github.com/rux-lang/Rux/releases){rel=""nofollow""}. # Install on macOS ::warning The macOS release is still in development. Since there is no native installer or package yet, these instructions will change. :: A dedicated macOS package is not available at this time. While native support is being worked on, you can run Rux on macOS by [building the compiler from source](https://rux-lang.dev/docs/learn/build) — the build toolchain works anywhere a supported C++ compiler and CMake are available, including macOS. ## Verify the Installation Once built and on your `PATH`, confirm the compiler is available: ```sh rux version ``` You should see the installed Rux compiler version. ## Releases All Rux releases are available on [GitHub](https://github.com/rux-lang/Rux/releases){rel=""nofollow""}. # Install on Windows This guide explains how to install the Rux compiler on Windows, either with the MSI installer or using [Scoop](https://scoop.sh){rel=""nofollow""}, a command-line package manager for Windows. ## Prerequisites - Windows 11 - Windows Server 2025 ## Install with the MSI Installer The MSI installer is the simplest option if you prefer a graphical installer. 1. Download `rux-windows.msi` from the [Download](https://rux-lang.dev/download) page or the [latest release](https://github.com/rux-lang/Rux/releases/latest){rel=""nofollow""}. 2. Double-click the downloaded `.msi` file to launch the installer. 3. Follow the setup wizard to complete the installation. The installer places the `rux` executable on your system `PATH`, so you can run it from any new terminal window once setup finishes. ::tip You can also install silently from a terminal — useful for scripted or unattended setups: ```sh msiexec /i rux-windows.msi /quiet ``` :: To update later, download the newer `.msi` and run it again; to remove Rux, uninstall it from **Settings → Apps → Installed apps**. ## Install with Scoop ### Add the Rux Bucket Scoop uses buckets to organize packages. Add the official Rux bucket: ```sh scoop bucket add rux-lang https://github.com/rux-lang/Scoop ``` ### Install the Rux Compiler ```sh scoop install rux ``` ## Verify the Installation ```sh rux version ``` You should see the installed Rux compiler version. ## Updating with Scoop To update a Scoop installation to the latest version: ```sh scoop update rux ``` ## Releases All Rux releases are available on [GitHub](https://github.com/rux-lang/Rux/releases){rel=""nofollow""}. # Build From Source This guide explains how to build the Rux compiler from source with [CMake](https://cmake.org){rel=""nofollow""}, [Ninja](https://ninja-build.org){rel=""nofollow""}, and [Clang](https://clang.llvm.org){rel=""nofollow""}. It works on every platform Rux supports, including platforms without a prebuilt package. ## Supported Platforms - BSD - Illumos - Linux - macOS - Windows ## Requirements Rux is built with Clang C++ compiler. We recommend the latest stable release of each tool: - [Clang 22.1](https://clang.llvm.org){rel=""nofollow""} or later - [CMake 4.3](https://cmake.org){rel=""nofollow""} or later - [Ninja 1.13](https://ninja-build.org){rel=""nofollow""} or later - [Git 2.54](https://git-scm.com){rel=""nofollow""} or later ## Install the Build Tools Install Clang, CMake, Ninja, and Git for your platform: ::code-group ```sh [Arch] sudo pacman -S clang cmake ninja git ``` ```sh [BSD] pkg install llvm cmake ninja git ``` ```sh [Debian] sudo apt install clang cmake ninja-build git ``` ```sh [Fedora] sudo dnf install clang cmake ninja-build git ``` ```sh [macOS] brew install llvm cmake ninja git ``` ```sh [Ubuntu] sudo apt install clang cmake ninja-build git ``` ```sh [Windows] scoop install llvm cmake ninja git ``` :: ::tip On macOS, the system `clang` is Apple Clang. To build with Homebrew's LLVM instead, prepend it to your `PATH` — `export PATH="$(brew --prefix llvm)/bin:$PATH"` — before configuring. :: ## Clone the Repository The Rux compiler has two branches: - **main** — the most stable release of the compiler - **dev** — the latest community updates; may be unstable ::code-group ```sh [main] git clone https://github.com/rux-lang/rux cd rux ``` ```sh [dev] git clone -b dev https://github.com/rux-lang/rux rux-dev cd rux-dev ``` :: ## Configure and Build Configure the project with the Ninja generator and Clang, then build: ```sh cmake -G Ninja -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -B build cmake --build build ``` The compiled `rux` binary is written to the `build` directory. ## Add the Binary to Your PATH ::code-group ```sh [BSD / Illumos / macOS / Linux] cp build/rux ~/.local/bin/ ``` ```sh [Windows] # Open Environment Variables and add the build directory to your global Path, # or copy rux.exe into a directory that is already on your PATH. ``` :: On Unix-like systems, make sure `~/.local/bin` is on your `PATH`, adding it in your shell's profile if needed. ## Verify the Installation ```sh rux version ``` You should see the installed Rux compiler version. ## Releases All Rux releases are available on [GitHub](https://github.com/rux-lang/Rux/releases){rel=""nofollow""}. # Visual Studio Code [Visual Studio Code](https://code.visualstudio.com){rel=""nofollow""} is the recommended editor for Rux. The official [Rux Language](https://marketplace.visualstudio.com/items?itemName=rux-lang.vscode-rux){rel=""nofollow""} extension adds syntax highlighting for `.rux` source files. ## Installing the Extension ::code-group ```sh [Quick Open] # Press Ctrl+P in VS Code and paste: ext install rux-lang.vscode-rux ``` ```sh [Command Line] code --install-extension rux-lang.vscode-rux ``` :: Alternatively, open the **Extensions** panel (`Ctrl+Shift+X`), search for **Rux Language**, and click **Install**. ## Features - Syntax highlighting for `.rux` source files - Markdown code fence injection — Rux code blocks in `.md` files are highlighted automatically ## Creating a New Project ```sh rux new MyApp cd MyApp code . ``` # Sublime Text The official [Rux](https://packagecontrol.io/packages/Rux){rel=""nofollow""} package for [Sublime Text](https://www.sublimetext.com){rel=""nofollow""} adds syntax highlighting for `.rux` source files. ## Installing the Package The package is distributed through [Package Control](https://packagecontrol.io){rel=""nofollow""}. If Package Control is not yet installed, add it via **Tools → Install Package Control…** in Sublime Text. Once Package Control is available: 1. Open the Command Palette — `Ctrl+Shift+P` on Windows/Linux, `Cmd+Shift+P` on macOS. 2. Type **Package Control: Install Package** and press `Enter`. 3. Search for **Rux** and press `Enter` to install. ## Features - Syntax highlighting for `.rux` source files ## Creating a New Project ```sh rux new MyApp cd MyApp ``` Then open the `MyApp` folder in Sublime Text via **File → Open Folder…** # Zed Editor [Zed](https://zed.dev){rel=""nofollow""} is a fast, multiplayer code editor for macOS and Linux. The official [Rux extension](https://github.com/rux-lang/Zed){rel=""nofollow""} adds syntax highlighting for `.rux` source files. ## Installing the Extension Open the extensions view from the Command Palette (`Cmd+Shift+P` on macOS, `Ctrl+Shift+P` on Linux) and run **zed: extensions**, then search for **Rux** and click **Install**. ### Install from source If the extension is not yet available in the registry, you can install it directly from its [GitHub repository](https://github.com/rux-lang/Zed){rel=""nofollow""} as a dev extension. 1. Clone the repository: ```sh git clone https://github.com/rux-lang/Zed.git rux-zed ``` 2. Open the extensions view (`zed: extensions`) and click **Install Dev Extension**. 3. Select the cloned `rux-zed` folder. Zed compiles the extension and loads it immediately. It reloads automatically whenever you change the source, which is handy while the extension is still evolving. ## Features - Syntax highlighting for `.rux` source files ## Creating a New Project ```sh rux new MyApp cd MyApp ``` Then open the `MyApp` folder in Zed via **File → Open…**, or from the terminal: ```sh zed MyApp ``` # Your First Project This page takes you from an empty folder to a running program, and then sets up the [Examples repository](https://github.com/rux-lang/Examples){rel=""nofollow""} that every lesson of the course is built on. It assumes `rux` is [installed](https://rux-lang.dev/docs/learn/install/windows) and on your `PATH`; check with: ```sh rux --version ``` ## How a Rux project is built Rux code lives in **packages**. A package is a folder with a manifest, `Rux.toml`, that names the package and lists what it depends on, and a `Src/` folder with the source files. The `rux` tool reads the manifest, compiles the sources together with their dependencies, and writes the program into `Bin/`. ```mermaid flowchart LR new["`rux new Hello`"] --> toml["`Rux.toml`
name, type, dependencies"] new --> src["`Src/Main.rux`
your code"] toml --> build["`rux build`"] src --> build std["Standard packages
`Io`, `Core`, `Text`, …"] --> build build --> exe["`Bin/Debug/<OS>/<Arch>/Hello`"] exe --> run["`rux run`"] ``` ## 1. Create the project ```sh rux new Hello cd Hello ``` `rux new` creates three files: ```text Hello/ ├── .gitignore ignores the Bin/ and Temp/ build folders ├── Rux.toml the package manifest └── Src/ └── Main.rux the program ``` The generated program is the smallest one Rux accepts — a `Main` function that does nothing and reports success: ```rux [Src/Main.rux] func Main() -> int { return 0; } ``` `Main` is the program's [entry point](https://rux-lang.dev/docs/lang/functions/main). The `int` it returns becomes the process exit status, and `0` means *success*. ## 2. Print a line To print you need `PrintLine`, which lives in the standard `Io` package. A package can only use what its manifest lists, so first add `Io` to `Rux.toml`: ```toml [Rux.toml] [Manifest] Version = 1 [Package] Name = "Hello" Version = "0.1.0" Type = "Executable" [Dependencies] Io = { Namespace = "Rux", Version = "*" } ``` `Namespace = "Rux"` marks `Io` as one of the standard packages that ship with the compiler, and `Version = "*"` accepts whichever version is installed. `rux add Rux/Io` writes the same line for you: a package that is already installed is added without asking the registry. Now replace `Src/Main.rux`: ```rux [Src/Main.rux] import Io::PrintLine; func Main() -> int { PrintLine("Hello, World!"); return 0; } ``` `import Io::PrintLine;` brings one function from the `Io` package into scope, so the program can call it by its short name. ## 3. Build and run ```sh rux run ``` ```text Hello, World! ``` `rux run` builds the package if anything changed and then starts the program. To only compile, use `rux build`; it reports where the executable went: ```text Built Hello (Debug, Windows x86-64) in 525 ms Output: Bin\Debug\Windows\x86-64\Hello.exe ``` Two more commands you will use all the time: | Command | What it does | | ------------------- | -------------------------------------------------------------------- | | `rux check` | Compiles without writing a program — the fastest way to find errors. | | `rux run --release` | Builds an optimised program into `Bin/Release/` and runs it. | The [CLI Reference](https://rux-lang.dev/docs/cli) documents every command and flag. ## 4. Read your first error Delete the semicolon after `PrintLine("Hello, World!")` and run `rux check`: ```text Src\Main.rux:5:5: error: expected ';' after expression, but found 'return' 5 | return 0; | ^ note: compiler phase: Parsing ``` Every message names the file, line and column, quotes the line, and points at the spot. Here the compiler reached `return` while still waiting for the `;` that ends the previous statement. Put the semicolon back and the error goes away. ::tip **Make mistakes on purpose.**:br Throughout the course, when a lesson says "the compiler refuses this", try it. Reading real error messages is a large part of learning a language, and the lessons quote the exact messages so you know what to expect. :: ## 5. Get the course examples Every lesson is a package in the [Rux Examples repository](https://github.com/rux-lang/Examples){rel=""nofollow""}. Clone it once: ```sh git clone https://github.com/rux-lang/Examples.git cd Examples ``` The repository is organised by course part, one folder per lesson: ```text Examples/ ├── Basics/ │ ├── Hello/ │ │ ├── README.md the lesson's goal and expected output │ │ ├── Rux.toml │ │ └── Src/ │ │ └── Main.rux the program, explained in its comments │ ├── Comment/ │ └── … ├── ControlFlow/ ├── … ├── Projects/ ├── Run.ps1 check or test every lesson (PowerShell) └── Run.sh the same for POSIX shells ``` To run a lesson, move into its folder and run it: ```sh cd Basics/Hello rux run ``` To check that every lesson compiles with your installed `rux` — useful after upgrading — use the runner script from the repository root: ::code-group ```powershell [Windows] ./Run.ps1 check ./Run.ps1 test -Filter Basics ``` ```sh [Linux / macOS / FreeBSD] sh Run.sh check sh Run.sh test --filter Basics ``` :: `check` type-checks every package; `test` also runs them and reports any that exit with an error. ## Next You are set up. Start the course with [1.1 Hello, World](https://rux-lang.dev/docs/learn/hello) — or, if you would like an AI assistant to study with, read [Learn Rux with AI](https://rux-lang.dev/docs/learn/ai) first. # Learn Rux with AI A coding assistant makes a patient study partner. It can explain a lesson line by line, answer "why?" as often as you ask, quiz you, invent exercises, and review the program you wrote. This page shows how to use one with the course — and how to avoid its one big weakness with a language as new as Rux. ## The one rule: the compiler has the last word Assistants learned to program from millions of examples in older languages, and very few in Rux. Left to guess, they fill gaps with Rust, C or Swift — a `_` default arm where Rux wants `else`, a `fn` where Rux writes `func`, a library function that does not exist. Three habits keep you safe: 1. **Give the assistant Rux context** — the lesson, the Examples repository, the documentation. The setup below does this. 2. **Ask it to run `rux check`** on anything it writes, and to fix what the compiler reports. 3. **Trust the compiler and the docs over the assistant.** When they disagree, the assistant is wrong — and working out *why* teaches you more than the right answer would. ```mermaid flowchart LR you(["You"]) -- "question or exercise" --> ai["Assistant"] docs["Lesson, Examples repo,
rux-lang.dev docs"] -. context .-> ai ai -- "explanation and code" --> check{"`rux check`"} check -- "error" --> ai check -- "compiles" --> run["`rux run`"] run -- "output" --> you ``` ## Option 1: a coding agent in the Examples repository A coding agent runs in your terminal or editor, reads the files in the folder you open it in, and can run commands such as `rux check` and `rux run` itself. Open it in the [Examples repository](https://github.com/rux-lang/Examples){rel=""nofollow""} and every lesson is already in its reach. ### Install an agent ::tabs :::tabs-item{icon="i-simple-icons-anthropic" label="Claude Code"} [Claude Code](https://claude.com/claude-code){rel=""nofollow""} is Anthropic's coding agent. It needs a Claude subscription or a Claude Console account. ::::code-group ```sh [macOS / Linux] curl -fsSL https://claude.ai/install.sh | bash ``` ```powershell [Windows] irm https://claude.ai/install.ps1 | iex ``` :::: Then start it inside the repository with `claude`. Claude Code is also available as a desktop app and as extensions for VS Code and JetBrains IDEs — see the [Claude Code documentation](https://code.claude.com/docs){rel=""nofollow""}. ::: :::tabs-item{icon="i-simple-icons-openai" label="Codex"} [Codex](https://developers.openai.com/codex){rel=""nofollow""} is OpenAI's coding agent. It signs in with a ChatGPT account. ::::code-group ```sh [npm] npm install -g @openai/codex ``` ```sh [macOS / Linux] curl -fsSL https://chatgpt.com/codex/install.sh | sh ``` ```powershell [Windows] powershell -ExecutionPolicy ByPass -c "irm https://chatgpt.com/codex/install.ps1 | iex" ``` :::: Then start it inside the repository with `codex`. Codex also has an IDE extension — see the [Codex documentation](https://developers.openai.com/codex){rel=""nofollow""} and the [source on GitHub](https://github.com/openai/codex){rel=""nofollow""}. ::: :: ### Open the course in it ```sh git clone https://github.com/rux-lang/Examples.git cd Examples claude # or: codex ``` The repository root carries an `AGENTS.md` file — Codex reads it automatically, and Claude Code reads it through the repository's `CLAUDE.md`. It tells the agent what Rux is, how the course is laid out, which syntax differs from the languages it knows, and to verify everything with `rux check`. You do not have to explain any of that yourself. ### Add the Rux skill (optional) The Examples repository also publishes a Rux *skill*: a compact reference an agent loads when it works with Rux code, in any project. Install it once and your agent knows Rux everywhere, not just inside the course: ```sh npx skills add rux-lang/Examples ``` ## Option 2: a chat assistant, straight from a lesson You do not need to install anything to study with a chat assistant. Every lesson page has a **Copy page** button and a menu next to it: - **Open in Claude** or **Open in ChatGPT** starts a conversation that already points the assistant at the lesson and its program, and asks it to explain the lesson and check your understanding. - **Copy page** puts the lesson's Markdown on your clipboard, to paste into any assistant you like. A chat assistant cannot run the compiler for you, so paste what it writes into a lesson package — or the [Playground](https://rux-lang.dev/play) — and check it yourself. ## Prompts that work Copy these into your agent, replacing the lesson name. Each one keeps the assistant tied to the course and the compiler. **Explain a lesson** ```text Read the lesson in ControlFlow/DoWhile (README.md and Src/Main.rux). Explain the program step by step for a beginner, then ask me one question at a time to check I understood. Do not move on until I answer. ``` **Practise** ```text Give me a small exercise that uses only what lessons 1.1 to 3.5 teach. Do not show a solution. When I say I am done, read my code, run rux check and rux run in that folder, and review it. ``` **Understand an error** ```text I ran rux check in Basics/Convert and got the error below. Explain what the compiler means in plain words and give me a hint — not the fix. ``` **Compare with a language you know** ```text I know Python. Compare how Rux handles optional values (lessons in Optionals/) with Python's None. Only use Rux syntax that appears in this repository, and point to the lesson for each claim. ``` **Review your own program** ```text Here is my FizzBuzz solution in Projects/MyFizzBuzz. Run rux check, then review it against Projects/FizzBuzz: what is idiomatic Rux, what is not, and why? ``` ::tip **Ask for hints, not answers.**:br An assistant that writes every exercise for you teaches you to read code, not to write it. Ask it to wait for your attempt, to give the smallest useful hint, and to explain its reasoning — then type the code yourself. :: ## Context for any assistant When you work outside the Examples repository, point your assistant at these: | Source | What it gives the assistant | | ------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------- | | [llms-full.txt](https://rux-lang.dev/llms-full.txt) | The whole site — course, reference, CLI and API — as one Markdown file | | [llms.txt](https://rux-lang.dev/llms.txt) | An index of every page, each linked to its Markdown source | | [Learn Rux](https://rux-lang.dev/docs/learn) | This course, lesson by lesson | | [github.com/rux-lang/Examples](https://github.com/rux-lang/Examples){rel=""nofollow""} | Every lesson as a package that compiles with the current `rux` | | [Rux Reference](https://rux-lang.dev/docs/lang) | The full language rules | | [API Reference](https://rux-lang.dev/docs/api) | The standard packages and their functions | `https://rux-lang.dev/llms-full.txt` is the quickest way to give an assistant that has never heard of Rux the whole language at once: attach it to a chat, or tell an agent to fetch it before it writes any code. It is large, so for a single lesson the lesson's own page is the better fit. ## Next Start the course with [1.1 Hello, World](https://rux-lang.dev/docs/learn/hello), with or without a study partner. # Rux Cheat Sheet The syntax from the whole course on one page. The snippets are cut from programs that compile with the current `rux` — `…` marks a body left out — and each section links to the lessons that explain it. For the complete rules, see the [Rux Reference](https://rux-lang.dev/docs/lang). ## A program ```rux [Src/Main.rux] import Io::{ Print, PrintLine }; // bring names from a package into scope func Main() -> int { // the entry point PrintLine("Hello, {}!", "World"); return 0; // the exit status: 0 means success } ``` ```toml [Rux.toml] [Dependencies] Io = { Namespace = "Rux", Version = "*" } # every package you import from ``` Lessons: [Hello, World](https://rux-lang.dev/docs/learn/hello), [Console](https://rux-lang.dev/docs/learn/console), [Comment](https://rux-lang.dev/docs/learn/comment) ## Bindings and constants ```rux let year = 2026; // immutable, type inferred (int) var score = 10; // mutable score += 5; let small: int8 = 100; // explicit type const Limit = 100; // folded in at compile time const Pi: float32 = 3.1415927f32; ``` Lessons: [Variable](https://rux-lang.dev/docs/learn/variable), [Mutable](https://rux-lang.dev/docs/learn/mutable), [Const](https://rux-lang.dev/docs/learn/const) ## Types | Kind | Types | Literals | | ------------------ | ----------------------------------------------- | -------------------------------------- | | Signed integers | `int8` … `int512`, `int` (pointer-sized) | `42`, `-7`, `5i64` | | Unsigned integers | `uint8` … `uint512`, `uint`, `byte` (= `uint8`) | `200u8`, `0xFF`, `0b1010`, `1_000_000` | | Floating point | `float8` … `float512`, `float` (= `float64`) | `0.75f32`, `2.998e8` | | Boolean | `bool` | `true`, `false` | | Character | `char` (= `char32`), `char8` … `char512` | `'R'`, `'\u{263A}'`, `c8'R'` | | Text | `char8[..]` — a slice of UTF-8 bytes | `"hello"` | | Array, slice | `T[N]`, `T[..]`, `var T[..]` | `[2, 3, 5]`, `[0; 16]` | | Tuple | `(A, B)` | `(3, true)` | | Optional | `T?` | `none` | | Fallible | `T ! E`, `! E` | — | | Sum | `A | B` | — | | Reference, pointer | `&T`, `&var T`, `*T`, `*var T` | `@x`, `null` | | Function | `func(int32) -> int32` | a function's name | ```rux let big = small as int32; // convert with `as` ``` Lessons: [Integer](https://rux-lang.dev/docs/learn/integer), [Float](https://rux-lang.dev/docs/learn/float), [Character](https://rux-lang.dev/docs/learn/character), [Literal](https://rux-lang.dev/docs/learn/literal), [Convert](https://rux-lang.dev/docs/learn/convert) ## Control flow ```rux if score > 10 { // braces always, parentheses optional PrintLine("big"); } else if score > 5 { PrintLine("medium"); } else { PrintLine("small"); } let label = n % 2 == 0 ? "even" : "odd"; while n > 0 { n -= 1; } do { n += 1; } while n < 3; // runs at least once — note the `;` loop { break; } // until a `break` for i in 0..3 { } // 0, 1, 2 for i in 1..=3 { } // 1, 2, 3 outer: for a in 1..10 { // a labelled loop for b in a..10 { if a * b == 12 { break outer; } } } ``` Lessons: [If](https://rux-lang.dev/docs/learn/if), [Ternary](https://rux-lang.dev/docs/learn/ternary), [While](https://rux-lang.dev/docs/learn/while), [Do-while](https://rux-lang.dev/docs/learn/do-while), [Loop](https://rux-lang.dev/docs/learn/loop), [For](https://rux-lang.dev/docs/learn/for), [Label](https://rux-lang.dev/docs/learn/label) ## match ```rux let kind = match score { 0 => "none", 1..=9 => "few", // a range pattern n if n > 1000 => "huge", // a guard else => "many" // the default arm is `else`, never `_` }; ``` Lessons: [Match](https://rux-lang.dev/docs/learn/match), [Match expression](https://rux-lang.dev/docs/learn/match-expression), [Guard](https://rux-lang.dev/docs/learn/guard), [Range pattern](https://rux-lang.dev/docs/learn/range-pattern), [Exhaustive](https://rux-lang.dev/docs/learn/exhaustive) ## Functions ```rux func Add(left: int, right: int) -> int { return left + right; } func Clamp(value: int, low: int = 0, high: int = 100) -> int { … } // default arguments func Sum(args: int32...) -> int32 { … } // variadic func Divide(a: int32, b: int32) -> (int32, int32) { // several results return (a / b, a % b); } let (q, r) = Divide(17, 5); // destructure func Larger(a: T, b: T) -> T { // generic return a > b ? a : b; } ``` Lessons: [Function](https://rux-lang.dev/docs/learn/function), [Default argument](https://rux-lang.dev/docs/learn/default-argument), [Variadic](https://rux-lang.dev/docs/learn/variadic), [Tuple](https://rux-lang.dev/docs/learn/tuple), [Destructure](https://rux-lang.dev/docs/learn/destructure), [Generic](https://rux-lang.dev/docs/learn/generic) ## Arrays and slices ```rux let primes: int32[4] = [2, 3, 5, 7]; let zeros: int32[8] = [0; 8]; // repeat a value let part = primes[1..3]; // a slice: a view of elements 1 and 2 PrintLine("{}", primes.length); for p in primes { } ``` Lessons: [Array](https://rux-lang.dev/docs/learn/array), [Array repeat](https://rux-lang.dev/docs/learn/array-repeat), [Slice](https://rux-lang.dev/docs/learn/slice), [Writable slice](https://rux-lang.dev/docs/learn/writable-slice) ## Structs and methods ```rux struct Point { x: int; y: int; } extend Point { func Point(x: int, y: int) -> Point { // a constructor: named after the type return Point { x: x, y: y }; } func Length2(self: &Point) -> int { // reads its receiver return self.x * self.x + self.y * self.y; } func Move(self: &var Point, dx: int) { // changes its receiver self.x += dx; } } var p = Point(3, 4); p.Move(1); ``` Lessons: [Struct](https://rux-lang.dev/docs/learn/struct), [Method](https://rux-lang.dev/docs/learn/method), [Mutating method](https://rux-lang.dev/docs/learn/mutating-method), [Constructor](https://rux-lang.dev/docs/learn/constructor), [Reference](https://rux-lang.dev/docs/learn/reference) ## Enums and variants ```rux enum Direction { North, East, South, West } enum Status: uint16 { Ok = 200, NotFound = 404 } variant Shape { Circle(float64), Rectangle { width: float64; height: float64; }, Empty } func Area(shape: Shape) -> float64 { return match shape { .Circle(r) => 3.14 * r * r, .Rectangle { width, height } => width * height, .Empty => 0.0 }; } ``` Lessons: [Enum](https://rux-lang.dev/docs/learn/enum), [Enum value](https://rux-lang.dev/docs/learn/enum-value), [Variant](https://rux-lang.dev/docs/learn/variant), [Variant match](https://rux-lang.dev/docs/learn/variant-match), [Struct pattern](https://rux-lang.dev/docs/learn/struct-pattern) ## Optionals ```rux func FirstEven(values: int[..]) -> int? { for v in values { if v % 2 == 0 { return v; } } return none; } let found = FirstEven(numbers) ?? -1; // a fallback match FirstEven(numbers) { value? => PrintLine("{}", value), none => PrintLine("none") } ``` Lessons: [Optional](https://rux-lang.dev/docs/learn/optional), [Presence](https://rux-lang.dev/docs/learn/presence), [Coalesce](https://rux-lang.dev/docs/learn/coalesce), [Coalesce exit](https://rux-lang.dev/docs/learn/coalesce-exit), [Optional propagate](https://rux-lang.dev/docs/learn/optional-propagate) ## Errors ```rux variant ParseError { Empty, Bad(int) } func Half(n: int) -> int ! ParseError { // a value, or an error if n == 0 { fail ParseError::Empty; } if n % 2 != 0 { fail ParseError::Bad(n); } return n / 2; } func Quarter(n: int) -> int ! ParseError { let half = Half(n)?; // pass a failure to the caller return Half(half)?; } match Quarter(8) { .Success(v) => PrintLine("{}", v), .Failure(e) => PrintLine("failed") } let safe = Half(3) catch { else => 0 }; // a default on failure ``` Lessons: [Fallible](https://rux-lang.dev/docs/learn/fallible), [Fail](https://rux-lang.dev/docs/learn/fail), [Propagate](https://rux-lang.dev/docs/learn/propagate), [Catch](https://rux-lang.dev/docs/learn/catch), [Catch fallback](https://rux-lang.dev/docs/learn/catch-fallback) ## Sum types ```rux type Setting = int32 | bool; func Describe(s: Setting) -> char8[..] { return match s { n: int32 => "number", flag: bool => "flag" }; } if limit is bool { } ``` Lessons: [Sum type](https://rux-lang.dev/docs/learn/sum-type), [Typed pattern](https://rux-lang.dev/docs/learn/typed-pattern), [The is operator](https://rux-lang.dev/docs/learn/is) ## Interfaces ```rux interface Named { func Name() -> char8[..]; } extend Point : Named { func Name(self: &Point) -> char8[..] { return "point"; } } ``` Lessons: [Interface](https://rux-lang.dev/docs/learn/interface), [Interface value](https://rux-lang.dev/docs/learn/interface-value), [Generic bound](https://rux-lang.dev/docs/learn/generic-bound) ## Ownership ```rux let b <- a; // move: `a` can no longer be used Take(<-b); // move into a call extend Token { func ~Token(self: &var Token) { … } // a destructor, run when the value goes away } defer PrintLine("done"); // runs when the scope ends ``` Lessons: [Copy](https://rux-lang.dev/docs/learn/copy), [Move](https://rux-lang.dev/docs/learn/move), [Destructor](https://rux-lang.dev/docs/learn/destructor), [Defer](https://rux-lang.dev/docs/learn/defer) ## Pointers ```rux var score = 10; let reader: *int = @score; // `@` takes an address let writer: *var int = @score; *writer = 25; // `*` reads or writes through it ``` Lessons: [Pointer](https://rux-lang.dev/docs/learn/pointer), [Out parameter](https://rux-lang.dev/docs/learn/out-parameter), [Optional pointer](https://rux-lang.dev/docs/learn/optional-pointer) ## Formatting | Placeholder | Result | | --------------------------------------- | -------------------------------------------------- | | `{}` | the value | | `{{}}` | a literal `{}` | | `{:>6}`, `{:<6}`, `{:^6}`, `{:*^8}` | right, left, centre aligned; with a fill character | | `{:.2}` | two decimals | | `{:x}`, `{:X}`, `{:o}`, `{:b}`, `{:#x}` | hexadecimal, octal, binary; with a prefix | | `{:08}`, `{:+}`, `{:e}` | zero padded, with a sign, in scientific notation | Lessons: [Console](https://rux-lang.dev/docs/learn/console), [Format](https://rux-lang.dev/docs/learn/format), [Format number](https://rux-lang.dev/docs/learn/format-number) ## The rux tool | Command | What it does | | ------------------ | --------------------------------------------------------------------- | | `rux new Name` | Create a package in a new folder; `rux init` makes one in this folder | | `rux check` | Compile without building — the fastest error check | | `rux build` | Build into `Bin/Debug///`; `--jobs N` caps the threads | | `rux run` | Build and run; `--release` for an optimised build | | `rux fmt` | Format the sources | | `rux lint` | Report style problems | | `rux test` | Run the `#Test()` functions and the packages under `Tests/` | | `rux test -- Name` | Run only the tests whose names contain `Name` | | `rux doc` | Generate documentation from `///` comments | | `rux add NS/Name` | Add a registry dependency; `rux install` fetches it | | `rux clean` | Delete the build output and `Temp/` | An unchanged package is not rebuilt: a second `rux build`, `rux run` or `rux test` reuses the last artifact and says `(up to date)`. `--no-cache` compiles anyway. Lessons: [Your first project](https://rux-lang.dev/docs/learn/first-project), [Tooling](https://rux-lang.dev/docs/learn/tooling) · Reference: [CLI](https://rux-lang.dev/docs/cli) # Part 1: Basics Your first programs: printing, naming values, and the types those values have. By the end of this part you can write a program that prints a formatted report of numbers, characters and text — and you will have met the compiler's error messages often enough to read them without fear. ## What you will learn - The shape of every Rux program: `import`, `func Main() -> int`, and the exit status. - Comments of all three kinds, including documentation comments. - Naming values with `let`, `var` and `const`, and when to use each. - The primitive types — integers, floats, booleans and characters — and how literals get their types. - Printing values with `Print`, `PrintLine` and `{}` placeholders. - Converting between types with `as`, and what happens when a value does not fit. ## The primitive types at a glance ```mermaid flowchart TB v(["A value"]) --> num["Numbers"] v --> b["Booleans
`bool` (= `bool8`), `bool16` … `bool512`"] v --> c["Characters
`char` (= `char32`), `char8`, `char16`
`char64` … `char512`"] num --> i["Integers"] num --> f["Floats
`float64` (= `float`), `float32`
`float8` … `float512`"] i --> s["Signed
`int8` … `int512`, `int`"] i --> u["Unsigned
`uint8` … `uint512`, `uint`, `byte`"] ``` ## Lessons | | Lesson | What you will learn | | ---- | ------------------------------------------------------ | --------------------------------------------------------------------------------------- | | 1.1 | [Hello, World](https://rux-lang.dev/docs/learn/hello) | print "Hello, World!", the minimal Rux application | | 1.2 | [Comment](https://rux-lang.dev/docs/learn/comment) | explain code with `//` and `/* */` comments, which can nest | | 1.3 | [Variable](https://rux-lang.dev/docs/learn/variable) | name a value with `let`, and let the compiler infer its type | | 1.4 | [Mutable](https://rux-lang.dev/docs/learn/mutable) | declare a binding with `var` so it can be reassigned | | 1.5 | [Integer](https://rux-lang.dev/docs/learn/integer) | whole numbers: signed and unsigned widths, `int` and `uint` | | 1.6 | [Float](https://rux-lang.dev/docs/learn/float) | fractional numbers: `float32`, `float64`, and why `0.1 + 0.2` is not `0.3` | | 1.7 | [Boolean](https://rux-lang.dev/docs/learn/boolean) | `true`, `false` and the `bool` type | | 1.8 | [Character](https://rux-lang.dev/docs/learn/character) | single characters, character literals and the `char` type | | 1.9 | [Literal](https://rux-lang.dev/docs/learn/literal) | write numbers in other bases, with separators and suffixes | | 1.10 | [Console](https://rux-lang.dev/docs/learn/console) | write to the console with `Print` and `PrintLine`, and fill `{}` placeholders | | 1.11 | [Const](https://rux-lang.dev/docs/learn/const) | name a value the compiler folds in, and see where it differs from `let` | | 1.12 | [Convert](https://rux-lang.dev/docs/learn/convert) | convert between numeric types with `as`, and see what a value that does not fit becomes | ## Before you start You need `rux` installed and the Examples repository cloned — [Your first project](https://rux-lang.dev/docs/learn/first-project) covers both. Each lesson's package is in the repository's `Basics/` folder: ```sh cd Examples/Basics/Hello rux run ``` ## After this part [Part 2: Operators](https://rux-lang.dev/docs/learn/operators) combines the values you can now name into new ones, and [Part 3: Control flow](https://rux-lang.dev/docs/learn/control-flow) makes programs choose and repeat. After Part 3 you are ready for the first checkpoint projects, [Thanks](https://rux-lang.dev/docs/learn/thanks) and [FizzBuzz](https://rux-lang.dev/docs/learn/fizz-buzz). For the full rules behind this part, see [Variables](https://rux-lang.dev/docs/lang/bindings/overview), [Literals](https://rux-lang.dev/docs/lang/lexical/literals) and the [primitive types](https://rux-lang.dev/docs/lang/appendix/primitives) in the Rux Reference. # Hello, World ::note **You'll need**: nothing — this is the first lesson. :: Every programming course starts by printing one line, and for good reason: it proves the whole toolchain works — the compiler, the standard library and your terminal — before you write anything harder. This lesson's program is only four lines, but each one shows something you will use in every Rux program you write. ## Anatomy of a program ```rux import Io::PrintLine; func Main() -> int { PrintLine("Hello, World!"); return 0; } ``` | Line | What it does | | ----------------------------- | ------------------------------------------------------------------------------- | | `import Io::PrintLine;` | Brings the name `PrintLine` from the standard `Io` package into this file. | | `func Main() -> int {` | Declares the function `Main`, where every program starts. It returns an `int`. | | `PrintLine("Hello, World!");` | Calls `PrintLine` with one piece of text. It prints the text and ends the line. | | `return 0;` | Ends `Main` and hands `0` back to the operating system: *success*. | Statements end with a semicolon, and a function's body sits between braces. ## Imports and dependencies `PrintLine` is not built into the language. It lives in `Io`, one of the standard packages that ship with the compiler. Two things make it usable: 1. The package's manifest, `Rux.toml`, lists `Io` under `[Dependencies]`: ```toml [Dependencies] Io = { Namespace = "Rux", Version = "*" } ``` 2. The source file imports the name it needs with `import Io::PrintLine;`. The `::` separates the package from the name inside it. Together they keep every dependency visible: the manifest says which packages a program uses, and each file says which names it takes from them. ## Main and the exit status When the program starts, the operating system calls `Main`. When `Main` returns, the number it returns becomes the program's **exit status** — the value scripts and other programs see. By convention `0` means the program succeeded and anything else means it failed. ```mermaid sequenceDiagram participant OS as Operating system participant Main participant Io as Io::PrintLine OS->>Main: start the program Main->>Io: `PrintLine("Hello, World!")` Io-->>OS: `"Hello, World!"` on the console Main-->>OS: `return 0` (success) ``` You can see the exit status yourself. Run the program, then ask the shell for it — `echo $?` in Bash or zsh, `$LASTEXITCODE` in PowerShell. Change `return 0;` to `return 3;`, run again, and the shell reports 3. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Basics/Hello){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // The smallest complete Rux program: an import, an entry point and one line of output. Running // `rux run` in this directory builds the program and then runs it. // // `import` brings a name from another package into this file. `PrintLine` lives in `Io`, the // standard input and output package, and the `[Dependencies]` table in Rux.toml is what makes // `Io` available to import from. import Io::PrintLine; // `Main` is where every program starts. The `int` it returns is the exit status, and zero means // the program finished successfully. func Main() -> int { // `PrintLine` writes the text in the quotes and then ends the line. PrintLine("Hello, World!"); return 0; } ``` ## Run it ```sh cd Examples/Basics/Hello rux run ``` ```text Hello, World! ``` ## Common mistakes ::mistake **Forgetting the dependency.**:br Remove the `Io = …` line from `Rux.toml` and the import has nothing to import from. The compiler says the package `Io` is not listed in `[Dependencies]` and suggests adding it. :: ::mistake **Leaving out a semicolon.**:br`PrintLine("Hello, World!")` with no `;` makes the compiler stop at the next line: ```text error: expected ';' after expression, but found 'return' ``` The error points at the token *after* the gap, so look one line up. :: ## Try it yourself 1. Print your own name on a second line, with a second `PrintLine` call. 2. Make `Main` return `1`, run the program and read the exit status in your shell. 3. Change `import Io::PrintLine;` to `import Io::Print;` and replace both calls with `Print`. What happens to the line breaks? The [Console](https://rux-lang.dev/docs/learn/console) lesson explains it. ## Learn more - [The `Main` function](https://rux-lang.dev/docs/lang/functions/main) in the Rux Reference - [Imports](https://rux-lang.dev/docs/lang/modules/imports) and [modules](https://rux-lang.dev/docs/lang/modules/overview) - [Your first project](https://rux-lang.dev/docs/learn/first-project) — create this package yourself with `rux new` # Comment ::note **You'll need**: [Hello, World](https://rux-lang.dev/docs/learn/hello) :: A comment is text the compiler skips. It is written for people — the next person to read the code, or you in three months — and good comments explain *why* the code is the way it is, which the code itself cannot say. Rux has three kinds, and this lesson's program uses all of them. | Kind | Syntax | Used for | | --------------------- | ------------------------------------------ | ------------------------------------------- | | Line comment | `// …` to the end of the line | Everyday notes, and switching a line off | | Block comment | `/* … */`, may span lines and nest | Longer notes, or a note inside a statement | | Documentation comment | `/// …` or `/** … */` before a declaration | Describing a function or type for `rux doc` | ## Line comments Two slashes start a comment that runs to the end of the line. It can have a line to itself or follow code: ```rux // A comment can have a line of its own, or follow code on the same line. PrintLine("Comments never reach the program."); // This one sits beside a statement. ``` Putting `//` in front of a line of code is the quickest way to switch it off without deleting it: ```rux // PrintLine("This line never runs."); ``` ## Block comments — and why nesting matters A block comment starts with `/*` and ends with `*/`. It can cover several lines or sit in the middle of one, even inside a call: ```rux PrintLine(/* the message */ "A block comment can sit inside a call."); ``` Unlike C, Java or JavaScript, Rux block comments **nest**: every `/*` needs its own `*/`. That means you can wrap a block comment around code that already contains one, and it still works: ```rux /* Block comments nest, which is less common than it sounds. … /* an inner comment */ so this line is still inside the outer comment. */ ``` ```mermaid flowchart LR open1["`/*` outer opens"] --> open2["`/*` inner opens"] --> close2["`*/` inner closes"] --> text["…still a comment…"] --> close1["`*/` outer closes"] ``` In a language without nesting, the first `*/` would end the whole comment and leave the rest as broken code. ## Documentation comments Three slashes start a **documentation comment**. It describes the declaration right after it, and tools read it: `rux doc` turns these comments into a package's reference pages. ```rux /// A documentation comment starts with three slashes. It describes the declaration that follows /// it — here `Main` — and tools read it: … func Main() -> int { ``` `/** … */` is the block form of the same thing. You will write many more of these in the [Documentation](https://rux-lang.dev/docs/learn/documentation) lesson. ## Comment markers inside text Between double quotes, `//` and `/*` are just characters. The program prints them like any other text: ```rux PrintLine("// is not a comment here"); PrintLine("/* and neither is this */"); ``` ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Basics/Comment){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // A comment is text the compiler skips. It is there for the people who read the code, and Rux has // three kinds of it. This file uses all three. // // A line comment, like this one, starts with two slashes and runs to the end of the line. It is // the everyday kind: use it to say why the code is the way it is. import Io::PrintLine; /* A block comment starts with a slash and a star and ends with a star and a slash. It can cover several lines, or sit in the middle of one. */ /* Block comments nest, which is less common than it sounds. In many languages the first closing star-slash below would end the whole comment and leave the line after it as broken code. In Rux every opening pair needs its own closing pair: /* an inner comment */ so this line is still inside the outer comment. */ /// A documentation comment starts with three slashes. It describes the declaration that follows /// it — here `Main` — and tools read it: `rux doc` turns these comments into a package's /// reference pages. `/** ... */` is the block form of the same thing. func Main() -> int { // A comment can have a line of its own, or follow code on the same line. PrintLine("Comments never reach the program."); // This one sits beside a statement. // A block comment can even sit inside a statement, between any two pieces of it. PrintLine(/* the message */ "A block comment can sit inside a call."); // Inside quotes, the comment markers are only characters, and they print like any others. PrintLine("// is not a comment here"); PrintLine("/* and neither is this */"); // Putting `//` in front of a line switches it off without deleting it: // PrintLine("This line never runs."); // A documentation comment must document a declaration. Written inside a body, as in // // /// Prints the total. // PrintLine("total"); // // it is refused, because there is no declaration for it to describe: // // error: documentation comment inside a block is not attached to a declaration // // Inside a function, use `//`. return 0; } ``` ## Run it ```sh cd Examples/Basics/Comment rux run ``` ```text Comments never reach the program. A block comment can sit inside a call. // is not a comment here /* and neither is this */ ``` ## Common mistakes ::mistake **A documentation comment with nothing to document.**:br`///` must sit directly before a declaration. Inside a function body there is none, and the compiler refuses it: ```text error: documentation comment inside a block is not attached to a declaration ``` Inside a function, use `//`. :: ::mistake **An unclosed block comment.**:br Because block comments nest, a stray `/*` inside a comment needs its own `*/`. If the rest of your file suddenly seems to vanish, count the openers and closers. :: ## Try it yourself 1. Comment out the second `PrintLine` with `//` and run again: one line fewer. 2. Wrap three lines of `Main` in a single `/* … */`, then add a nested `/* … */` inside it. Does the program still compile? 3. Move the `///` comment above `func Main` so it sits inside the body instead, and read the compiler's message. ## Learn more - [Comments](https://rux-lang.dev/docs/lang/lexical/comments) in the Rux Reference - [Documentation](https://rux-lang.dev/docs/learn/documentation) — writing `///` comments for `rux doc` # Variable ::note **You'll need**: [Hello, World](https://rux-lang.dev/docs/learn/hello), [Comment](https://rux-lang.dev/docs/learn/comment) :: A variable gives a value a name. Once named, the value can be printed, combined with others, or passed around — and the name makes the code say what the value *means*. In Rux, `let` makes a variable that never changes after it is set. That sounds limiting, but it is the right default: a name that cannot change is one less thing to keep track of while you read. ## Declaring a variable with let A declaration is `let`, a name, `=`, and a value: ```rux let year = 2026; let price = 4.99; let language = "Rux"; let ready = true; ``` ## Type inference None of those lines names a type, yet every variable has one. The compiler **infers** it from the value: | Value | Inferred type | | -------------------------------------- | ---------------------- | | `2026` — a whole number | `int` | | `4.99` — a number with a decimal point | `float64` | | `"Rux"` — text in double quotes | a string (`char8[..]`) | | `true` or `false` | `bool` | You can also write the type yourself, after a colon. Then the value has to fit it: ```rux let small: int8 = 100; let large: int64 = 100; ``` `100` fits in an `int8`, which holds −128 to 127; `300` would not, and the compiler would refuse it. The [Integer](https://rux-lang.dev/docs/learn/integer) lesson covers every integer type. ## Printing a value Each `{}` in the text passed to `PrintLine` is replaced by the next value after it: ```rux PrintLine("year {}", year); ``` The [Console](https://rux-lang.dev/docs/learn/console) lesson covers placeholders in detail — for now, this is how a value gets printed. ## Values built from other variables The value can be any expression, including one that uses earlier variables: ```rux let nextYear = year + 1; ``` ## One name, one meaning Rux refuses two things you may be used to from other languages. A `let` variable cannot be assigned again, and a name cannot be declared twice in the same scope: ```mermaid flowchart TD decl["`let total = 5;`"] --> assign{"`total = 6;`"} assign -- "refused" --> err1["`cannot modify immutable variable 'total'`
`help: declare 'total' with 'var'`"] decl2["`let name = 1;`"] --> redecl{"`let name = 2;`"} redecl -- "refused" --> err2["`variable 'name' is already`
`declared in this scope`"] ``` The second rule matters if you come from a language where declaring a name again quietly hides the old one ("shadowing"). In Rux a name means one thing for the whole scope it lives in. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Basics/Variable){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // A variable gives a value a name. `let` makes one: a name, an `=` and a value, and from then on // the name stands for that value. A `let` variable never changes — the next lesson, Mutable, // introduces the kind that does. Reach for `let` first: a name that cannot change is one less // thing to keep track of while reading the code. import Io::PrintLine; func Main() -> int { // With no type written, the compiler infers one from the value. A whole number makes an // `int`, a number with a decimal point makes a `float64`, text in double quotes makes a // string, and `true` or `false` makes a `bool`. let year = 2026; let price = 4.99; let language = "Rux"; let ready = true; // Each `{}` in the text is replaced by the next value after it. The Console lesson has the // details; until then, this is how a value gets printed. PrintLine("year {}", year); PrintLine("price {}", price); PrintLine("language {}", language); PrintLine("ready {}", ready); // A type can also be written after the name, following a colon. Then the value has to fit // that type: 100 fits in an `int8`, which holds -128 to 127, but 300 would not. let small: int8 = 100; let large: int64 = 100; PrintLine("small {}", small); PrintLine("large {}", large); // The value can be any expression, including one that uses earlier variables. let nextYear = year + 1; PrintLine("next year {}", nextYear); // Two things the compiler refuses. Neither can appear in a program that builds, so they are // written here rather than run: // // let total = 5; // total = 6; // error: cannot modify immutable variable 'total' // help: declare 'total' with 'var' to make it mutable // // let name = 1; // let name = 2; // error: variable 'name' is already declared in this scope // // The second is worth meeting early if you come from a language where declaring a name again // quietly hides the old one. In Rux a name means one thing for the whole scope it lives in. return 0; } ``` ## Run it ```sh cd Examples/Basics/Variable rux run ``` ```text year 2026 price 4.99 language Rux ready true small 100 large 100 next year 2027 ``` ## Common mistakes ::mistake **Assigning to a `let`.**:br`let total = 5;` followed by `total = 6;` fails with: ```text error: cannot modify immutable variable 'total' ``` The compiler suggests `var` — the subject of the [next lesson](https://rux-lang.dev/docs/learn/mutable). :: ::mistake **Declaring the same name twice.**:br`let name = 1; let name = 2;` fails with: ```text error: variable 'name' is already declared in this scope ``` Pick a second name that says how the two values differ. :: ::mistake **A value that does not fit its type.**:br`let small: int8 = 300;` is refused: an `int8` holds only −128 to 127. :: ## Try it yourself 1. Add a variable `month` and print a line like `2026-10`. 2. Write `let celsius = 21.5;` and a second variable `fahrenheit` computed from it (`celsius * 9.0 / 5.0 + 32.0`). Print both. 3. Try each refused line from this lesson and read the messages. ## Learn more - [Variables](https://rux-lang.dev/docs/lang/bindings/overview) and [`let`](https://rux-lang.dev/docs/lang/bindings/overview#let) in the Rux Reference - [Mutable](https://rux-lang.dev/docs/learn/mutable) — variables that can change # Mutable ::note **You'll need**: [Variable](https://rux-lang.dev/docs/learn/variable) :: A `let` variable keeps its first value for good. A `var` variable may change: after it is declared, `=` gives it a new value as often as the program needs. That is the whole difference — and the reason `let` is the default. Writing `var` tells the reader "watch this name, it moves". ## Declaring and assigning `var` is declared exactly like `let`, with the type inferred the same way. Assignment then replaces the value: ```rux var score = 10; score = 25; score = score + 5; ``` The right-hand side is worked out first, so `score = score + 5` reads the old value (25) and stores the new one (30). ## Declaring now, assigning later A `var` may be declared with a type and no value — as long as it gets one before anything reads it: ```rux var bonus: int; bonus = score * 2; ``` ## Assignment copies the value `saved` takes the value `level` holds *at that moment*. Changing `level` afterwards does not reach back into it: ```rux var level = 1; let saved = level; level = 2; ``` ```mermaid flowchart LR subgraph before ["after `let saved = level;`"] l1["`level: 1`"] s1["`saved: 1`"] end subgraph after ["after `level = 2;`"] l2["`level: 2`"] s2["`saved: 1`"] end before --> after ``` Each variable owns its own copy. Later, the [Ownership](https://rux-lang.dev/docs/learn/copy) part shows what happens with larger values, and how to *move* one instead of copying it. ## let or var? | Use | When | | ----- | ---------------------------------------------------------------- | | `let` | The value is set once — most variables. | | `var` | The value has to change: a counter, a running total, a position. | Start with `let`. If the compiler tells you a variable needs to change, switch that one to `var`. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Basics/Mutable){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // A `let` variable keeps its first value for good. A `var` variable may change: after it is // declared, `=` gives it a new value, as often as the program needs. That is the whole difference, // and it is why `let` is the default — `var` says "watch this name, it moves". import Io::PrintLine; func Main() -> int { // `var` is declared exactly like `let`, and its type is inferred the same way. var score = 10; PrintLine("score {}", score); // Assignment replaces the value. The right-hand side is worked out first, so it may use the // variable's own old value. score = 25; PrintLine("score {}", score); score = score + 5; PrintLine("score {}", score); // A `var` may be declared with a type and no value, so long as it is given one before // anything reads it. var bonus: int; bonus = score * 2; PrintLine("bonus {}", bonus); // Assigning copies the value. `saved` took the 1 that `level` held at that moment, and // changing `level` afterwards does not reach back into it. var level = 1; let saved = level; level = 2; PrintLine("level {}", level); PrintLine("saved {}", saved); // What may change is the value, never the type. `score` became an `int` when it was declared // and stays one, and a variable cannot be read before it has a value: // // score = 2.5; // error: cannot assign 'float64' to 'int' // // var total: int; // PrintLine("{}", total); // error: variable 'total' is used before it is initialized return 0; } ``` ## Run it ```sh cd Examples/Basics/Mutable rux run ``` ```text score 10 score 25 score 30 bonus 60 level 2 saved 1 ``` ## Common mistakes ::mistake **Changing the type.**:br The value of a `var` may change; its type never does. `score` became an `int` when it was declared, so `score = 2.5;` fails with: ```text error: cannot assign 'float64' to 'int' ``` :: ::mistake **Reading a variable before it has a value.**:br`var total: int;` followed by `PrintLine("{}", total);` fails with: ```text error: variable 'total' is used before it is initialized ``` :: ## Try it yourself 1. Start a `var count = 0;`, add 1 to it three times, and print it after each step. 2. Declare `var message: char8[..];` with no value, assign it on the next line, and print it. 3. Change `var score` back to `let score` and read the message the compiler gives for the first assignment. ## Learn more - [`var`](https://rux-lang.dev/docs/lang/bindings/overview#var) and [mutability](https://rux-lang.dev/docs/lang/bindings/overview#mutability) in the Rux Reference - [Assignment](https://rux-lang.dev/docs/learn/assignment) — `+=`, `++` and the other ways to update a variable # Integer ::note **You'll need**: [Variable](https://rux-lang.dev/docs/learn/variable) :: An integer is a whole number stored in a fixed number of bits, and in Rux the type's name says how many. Choosing a width is a trade between range and space — and choosing *signed* or *unsigned* decides whether negative numbers are allowed. ## Signed and unsigned | Family | Types | Range | | -------- | ---------------------------------------------------------------------- | ------------------------- | | Signed | `int8`, `int16`, `int32`, `int64`, `int128`, `int256`, `int512` | negative and positive | | Unsigned | `uint8`, `uint16`, `uint32`, `uint64`, `uint128`, `uint256`, `uint512` | zero and up, twice as far | An unsigned type spends the bit a signed type uses for the sign on reaching twice as far. Each extra byte of width multiplies the range by 256: | Type | Smallest | Largest | | ------- | ----------------- | ---------------- | | `int8` | −128 | 127 | | `uint8` | 0 | 255 | | `int16` | −32 768 | 32 767 | | `int32` | −2 147 483 648 | 2 147 483 647 | | `int64` | about −9.2 × 10¹⁸ | about 9.2 × 10¹⁸ | The wide types — `int128` up to `uint512` — are for numbers no machine register holds, such as the ones cryptography and exact arithmetic work with. They are ordinary integers all the same, with the same operators and the same `Min` and `Max`. Their limits get long quickly: `int128::Max` has 39 digits, `int256::Max` 77 and `uint512::Max` 155, as the program's output shows. [Wide integer](https://rux-lang.dev/docs/learn/wide-integer) in Part 16 puts them to work. ## Asking a type for its limits Every integer type knows its own limits as `Min` and `Max`, and its size as `Bits`. Those names come from the standard `Core` package, so the lesson imports each type it asks about: ```rux import Core::{ int, int128, int16, int256, int32, int512, int64, int8 }; import Core::{ uint, uint128, uint16, uint256, uint32, uint512, uint64, uint8 }; ``` ```rux PrintLine("int8 {} to {}", int8::Min, int8::Max); PrintLine("int256 max {}", int256::Max); ``` and lists `Core` next to `Io` in `Rux.toml`. ## int, uint and byte `int` and `uint` have no number in their name because the target machine picks their width: they are as wide as a memory address — 64 bits on today's desktop systems. A whole number with no type written is an `int`, which is why `Main` returns one. ```rux PrintLine("int {} bits", int::Bits); ``` `byte` is another name for `uint8`, used when a value is raw storage rather than a number: ```rux let level: byte = 200; ``` ## Which one should I use? ```mermaid flowchart TD start{"What is the number?"} --> count["A count, an index,
everyday arithmetic"] --> intT["`int`"] start --> neg{"Its size matters:
a file format, hardware"} neg -- "never negative" --> uintN["`uint8` … `uint64`"] neg -- "can be negative" --> intN["`int8` … `int64`"] start --> raw["Raw bytes of data"] --> byteT["`byte`"] start --> huge["Larger than 64 bits"] --> wide["`int128` … `uint512`"] ``` When in doubt, use `int`. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Basics/Integer){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // An integer is a whole number stored in a fixed number of bits, and the type's name says how // many. `int8`, `int16`, `int32`, `int64`, `int128`, `int256` and `int512` are signed: they hold // negative and positive numbers. `uint8` through `uint512` are unsigned: they hold only zero and // up, and spend the bit a signed type uses for the sign on reaching twice as far. // // Every integer type knows its own limits, as `Min` and `Max`. Those two names are declared in the // standard `Core` package, so this lesson imports each type it asks about, and its Rux.toml lists // `Core` as a dependency next to `Io`. import Core::{ int, int128, int16, int256, int32, int512, int64, int8 }; import Core::{ uint, uint128, uint16, uint256, uint32, uint512, uint64, uint8 }; import Io::PrintLine; func Main() -> int { // Signed: each extra byte of width multiplies the range by 256. PrintLine("int8 {} to {}", int8::Min, int8::Max); PrintLine("int16 {} to {}", int16::Min, int16::Max); PrintLine("int32 {} to {}", int32::Min, int32::Max); PrintLine("int64 {} to {}", int64::Min, int64::Max); // Unsigned: the same widths, starting at zero. PrintLine("uint8 {} to {}", uint8::Min, uint8::Max); PrintLine("uint16 {} to {}", uint16::Min, uint16::Max); PrintLine("uint32 {} to {}", uint32::Min, uint32::Max); PrintLine("uint64 {} to {}", uint64::Min, uint64::Max); // The wide types are for numbers no machine register holds, such as the ones cryptography // and exact arithmetic work with. They are ordinary integers all the same. // Their numbers get long quickly: each doubling of the width roughly doubles the digits. PrintLine("int128 max {}", int128::Max); PrintLine("uint128 max {}", uint128::Max); PrintLine("int256 max {}", int256::Max); PrintLine("uint256 max {}", uint256::Max); PrintLine("int512 min {}", int512::Min); PrintLine("uint512 max {}", uint512::Max); // `int` and `uint` have no number in their name because the target machine picks their // width: they are as wide as a memory address, 64 bits on today's desktop systems. A whole // number with no type written is an `int`, which is why `Main` returns one. PrintLine("int {} bits", int::Bits); PrintLine("uint {} bits", uint::Bits); // `byte` is another name for `uint8`, used when a value is raw storage rather than a number. let level: byte = 200; PrintLine("byte {}", level); // A value has to fit the type it is given, and the compiler checks every literal: // // let tooBig: uint8 = 256; // error: integer literal is out of range for type 'uint8' // // And `Min`, `Max` and `Bits` exist only once their type is imported from `Core`. Without // the import the compiler reports "'Max' not found in extend for type 'int8'". return 0; } ``` Besides `Io`, its `Rux.toml` lists `Core` under `[Dependencies]`. ## Run it ```sh cd Examples/Basics/Integer rux run ``` ```text int8 -128 to 127 int16 -32768 to 32767 int32 -2147483648 to 2147483647 int64 -9223372036854775808 to 9223372036854775807 uint8 0 to 255 uint16 0 to 65535 uint32 0 to 4294967295 uint64 0 to 18446744073709551615 int128 max 170141183460469231731687303715884105727 uint128 max 340282366920938463463374607431768211455 int256 max 57896044618658097711785492504343953926634992332820282019728792003956564819967 uint256 max 115792089237316195423570985008687907853269984665640564039457584007913129639935 int512 min -6703903964971298549787012499102923063739682910296196688861780721860882015036773488400937149083451713845015929093243025426876941405973284973216824503042048 uint512 max 13407807929942597099574024998205846127479365820592393377723561443721764030073546976801874298166903427690031858186486050853753882811946569946433649006084095 int 64 bits uint 64 bits byte 200 ``` The `int` and `uint` lines show 64 bits on a 64-bit target. ## Common mistakes ::mistake **A literal that does not fit.**:br The compiler checks every literal against its type: `let tooBig: uint8 = 256;` fails with: ```text error: integer literal is out of range for type 'uint8' ``` :: ::mistake **Asking for limits without importing the type.**:br`Min`, `Max` and `Bits` exist only once the type is imported from `Core`. Without the import the compiler reports: ```text 'Max' not found in extend for type 'int8' ``` :: ## Try it yourself 1. Print the limits of `int16` and `uint16` side by side. 2. Add `uint128` to the imports and print its `Max`. How many digits does it have? 3. Declare `let level: byte = 255;`, then try `256` and read the error. ## Learn more - [Signed integers](https://rux-lang.dev/docs/lang/types/integers) and [unsigned integers](https://rux-lang.dev/docs/lang/types/integers) in the Rux Reference - [Literal](https://rux-lang.dev/docs/learn/literal) — writing numbers in hexadecimal, binary and with separators - [Number limit](https://rux-lang.dev/docs/learn/number-limit) and [Wide integer](https://rux-lang.dev/docs/learn/wide-integer) — more in Part 16 # Float ::note **You'll need**: [Variable](https://rux-lang.dev/docs/learn/variable), [Integer](https://rux-lang.dev/docs/learn/integer) :: A floating-point number — a *float* — has a fractional part and an enormous range. The price is exactness: a float is stored in binary with a fixed number of significant digits, so most decimal fractions are kept as the *nearest value it can represent*, not the value you wrote. ## Two everyday widths | Type | Size | Significant digits | Literal | | ------------------------ | ------- | ------------------ | ------------------ | | `float64` (also `float`) | 8 bytes | about 16 | `4.99`, `384400.0` | | `float32` | 4 bytes | about 7 | `0.75f32` | A number with a decimal point is a `float64` unless something says otherwise: ```rux let price = 4.99; let ratio: float = 0.75; let distance: float64 = 384400.0; ``` A `float32` value is written with the `f32` suffix. Without it the literal is a `float64` — and a `float64` is never squeezed into a `float32` behind your back, because digits would be lost: ```rux let single: float32 = 0.75f32; ``` ## Six more widths Everyday code uses the two above. Rux has six more, two narrower and four wider, each with its own suffix: | Type | Size | Significant digits | Suffix | | ---------- | -------- | ------------------ | ------ | | `float8` | 1 byte | about 1 | `f8` | | `float16` | 2 bytes | about 3 | `f16` | | `float80` | 16 bytes | about 19 | `f80` | | `float128` | 16 bytes | about 34 | `f128` | | `float256` | 32 bytes | about 71 | `f256` | | `float512` | 64 bytes | about 147 | `f512` | The narrow ones trade digits for space. They suit huge tables of approximate numbers — the weights of a neural network, say — where size matters more than any single value; a `float8` cannot even count past 240. The wide ones keep far more digits than a `float64`, for work where rounding errors must stay out of sight. `float80` is the x87 extended format: its 80 bits are stored in 16 bytes, so six of them sit unused. Only `float32` and `float64` run on the processor's float instructions. The compiler computes the other six with integer code it generates, so they are slower. And `{}` does not print the four wide ones directly — finding their digits needs an allocator, which [Floating-Point](https://rux-lang.dev/docs/lang/types/floating-point#printing-the-wide-widths) in the Rux Reference shows how to pass. Their sizes, like any other number, print fine: ```rux PrintLine("float80 {} bits in {} bytes", float80::Bits, float80::Bytes); ``` `Bits`, `Bytes` and `Max` come from the `Core` package, so the lesson imports the types it asks about. ## Precision you can see A third has no exact binary form, so each type stops where its digits run out: ```rux let third64 = 1.0 / 3.0; let third32 = 1.0f32 / 3.0f32; let third16 = 1.0f16 / 3.0f16; let third8 = 1.0f8 / 3.0f8; ``` ```text 1/3 0.3333333333333333 as float64 1/3 0.33333334 as float32 1/3 0.3333 as float16 1/3 0.34 as float8 ``` Each prints the shortest decimal that reads back as the same value *at its own width*. The `float8` nearest to a third is really 0.34375 — its neighbours are 0.3125 and 0.375 — and `0.34` is the shortest decimal that still picks it out. ## Why 0.1 + 0.2 is not 0.3 Neither 0.1 nor 0.2 is exact in binary, and their two tiny errors add up to a sum that is not quite 0.3: ```rux let sum = 0.1 + 0.2; ``` ```text 0.1 + 0.2 0.30000000000000004 ``` ```mermaid flowchart LR a["`0.1` as written"] --> a2["stored as
`0.1000000000000000055…`"] b["`0.2` as written"] --> b2["stored as
`0.2000000000000000111…`"] a2 --> sum["sum ≈ `0.3000000000000000444…`"] b2 --> sum sum --> shown["printed as
`0.30000000000000004`"] ``` This is how floats behave in every language that uses them, not a Rux quirk. It is why money is usually counted in whole cents, with an integer. ## Floats always look like floats A float always prints with a decimal point, even when the value is whole, so it cannot be mistaken for an integer: `let whole = 2.0;` prints `2.0`. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Basics/Float){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // A floating-point number, or float, has a fractional part and an enormous range. The price is // exactness: a float is stored in binary with a fixed number of significant digits, so most // decimal fractions are kept as the nearest value it can represent, not the value written. // // Rux has eight float types. This lesson mostly uses `float64`, with about 16 significant digits, // and `float32`, with about 7 in half the space. `float` names `float64`, which a number with a // decimal point becomes when nothing says otherwise. Two narrower types, `float16` and `float8`, // save space at the cost of digits, and four wider ones, `float80`, `float128`, `float256` and // `float512`, keep far more digits than a `float64`. import Core::{ float128, float16, float256, float512, float8, float80 }; import Io::PrintLine; func Main() -> int { // Three ways to end up with a float64. let price = 4.99; let ratio: float = 0.75; let distance: float64 = 384400.0; PrintLine("price {}", price); PrintLine("ratio {}", ratio); PrintLine("distance {}", distance); // A float32 value is written with the `f32` suffix. Without it the literal is a float64, and // a float64 is never squeezed into a float32 behind your back, because digits would be lost. let single: float32 = 0.75f32; PrintLine("single {}", single); // The same division at both widths shows the difference in precision. A third has no exact // binary form, so each type stops where its digits run out. let third64 = 1.0 / 3.0; let third32 = 1.0f32 / 3.0f32; PrintLine("1/3 {} as float64", third64); PrintLine("1/3 {} as float32", third32); // `f16` and `f8` make the narrow types. A `float16` keeps about three digits, and a `float8` // barely one: its largest value is 240. They suit huge tables of approximate numbers, such // as the weights of a neural network, where size matters more than any single value. let third16 = 1.0f16 / 3.0f16; let third8 = 1.0f8 / 3.0f8; PrintLine("1/3 {} as float16", third16); PrintLine("1/3 {} as float8", third8); PrintLine("largest {} as float16, {} as float8", float16::Max, float8::Max); // The wide types have the suffixes `f80`, `f128`, `f256` and `f512`. Their arithmetic runs in // code the compiler generates, so it is slower, and `{}` does not print them directly; the // Rux Reference shows how to render one. Their sizes print like any other number, and show // that a `float80` is stored in 16 bytes, with six of them unused. PrintLine("float80 {} bits in {} bytes", float80::Bits, float80::Bytes); PrintLine("float128 {} bits in {} bytes", float128::Bits, float128::Bytes); PrintLine("float256 {} bits in {} bytes", float256::Bits, float256::Bytes); PrintLine("float512 {} bits in {} bytes", float512::Bits, float512::Bytes); // Neither 0.1 nor 0.2 is exact in binary either, and their two tiny errors add up to a sum // that is not quite 0.3. This is how floats behave in every language that uses them, not a // Rux quirk. It is why money is usually counted in whole cents with an integer. let sum = 0.1 + 0.2; PrintLine("0.1 + 0.2 {}", sum); // A float always prints with a decimal point, even when the value is whole, so it cannot be // mistaken for an integer. let whole = 2.0; PrintLine("whole {}", whole); // A float and an integer are different types even when they hold the same number: // // let count: int = 2.0; // error: cannot assign 'float64' to 'int' // // let single: float32 = 0.75; // error: cannot assign 'float64' to 'float32' return 0; } ``` Besides `Io`, its `Rux.toml` lists `Core` under `[Dependencies]`. ## Run it ```sh cd Examples/Basics/Float rux run ``` ```text price 4.99 ratio 0.75 distance 384400.0 single 0.75 1/3 0.3333333333333333 as float64 1/3 0.33333334 as float32 1/3 0.3333 as float16 1/3 0.34 as float8 largest 65500.0 as float16, 240.0 as float8 float80 80 bits in 16 bytes float128 128 bits in 16 bytes float256 256 bits in 32 bytes float512 512 bits in 64 bytes 0.1 + 0.2 0.30000000000000004 whole 2.0 ``` ## Common mistakes ::mistake **Mixing floats and integers.**:br They are different types even when they hold the same number: `let count: int = 2.0;` fails with: ```text error: cannot assign 'float64' to 'int' ``` Write `2`, or convert with [`as`](https://rux-lang.dev/docs/learn/convert). :: ::mistake **Forgetting the `f32` suffix.**:br`let single: float32 = 0.75;` fails with: ```text error: cannot assign 'float64' to 'float32' ``` Write `0.75f32`. :: ::mistake **Comparing floats for exact equality.**:br After arithmetic, `0.1 + 0.2 == 0.3` is false. Compare against a small tolerance instead — Part 16 covers [special float values](https://rux-lang.dev/docs/learn/float-special) and limits such as `Epsilon`. :: ## Try it yourself 1. Compute the area of a circle with radius `2.5`, using `3.14159` for π. 2. Repeat the `1/3` experiment with `2.0 / 3.0`. Where does each width round? 3. Add `0.1` to a `var total = 0.0;` ten times and print it. Is it exactly `1.0`? ## Learn more - [`float64`](https://rux-lang.dev/docs/lang/types/floating-point) and [`float32`](https://rux-lang.dev/docs/lang/types/floating-point) in the Rux Reference - [Float special](https://rux-lang.dev/docs/learn/float-special) — infinity, NaN and negative zero - [Math](https://rux-lang.dev/docs/learn/math) — square roots, powers and trigonometry # Boolean ::note **You'll need**: [Variable](https://rux-lang.dev/docs/learn/variable), [Integer](https://rux-lang.dev/docs/learn/integer) :: A boolean holds one of exactly two values: `true` or `false`. It is the answer to a yes-or-no question — is the file open, has the player won — and the rest of the course leans on it constantly: every comparison produces one, and `if` and `while` choose what to run by one. ## true and false `true` and `false` are the only boolean literals, and either one makes a `bool`: ```rux let ready = true; let finished = false; let visible: bool = true; ``` ## The boolean family `bool` is the everyday spelling. It is another name for `bool8`, a boolean stored in one byte. The wider types hold the same two values in more space: | Type | Size | Use | | --------------------- | -------------- | ---------------------------------- | | `bool` = `bool8` | 1 byte | Everyday code | | `bool16` | 2 bytes | Talking to code in other languages | | `bool32` | 4 bytes | The Windows API's `BOOL`, for one | | `bool64` | 8 bytes | Matching other 8-byte layouts | | `bool128` … `bool512` | 16 to 64 bytes | Matching wider layouts | ```rux let flag32: bool32 = true; ``` They exist for [interoperating with C and operating-system APIs](https://rux-lang.dev/docs/learn/c-interop), where a boolean's size is part of the agreement. In your own code, use `bool`. ## Where booleans come from You will rarely write `true` or `false` by hand. Most booleans are produced by questions the program asks: ```mermaid flowchart LR cmp["`score > 10`
(a comparison)"] --> b(("`bool`")) logic["`ready && !finished`
(logic)"] --> b b --> ifs["`if … { }`"] b --> wh["`while … { }`"] b --> tern["`cond ? a : b`"] ``` [Comparison](https://rux-lang.dev/docs/learn/comparison) and [Logical](https://rux-lang.dev/docs/learn/logical) show how to produce them; [If](https://rux-lang.dev/docs/learn/if) and [While](https://rux-lang.dev/docs/learn/while) show how to use them. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Basics/Boolean){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // A boolean holds one of exactly two values, `true` or `false`. It is the answer to a yes-or-no // question — is the file open, has the player won — and later parts lean on it constantly: a // comparison produces one, and `if` and `while` choose what to run by one. // // `bool` is the everyday spelling. It is another name for `bool8`, a boolean stored in one byte. // `bool16`, `bool32` and `bool64` hold the same two values in two, four and eight bytes, and // `bool128`, `bool256` and `bool512` in 16, 32 and 64. They exist to match the layout of data // shared with code written in other languages: the Windows API, for one, uses a four-byte // boolean, which is a `bool32` here. import Io::PrintLine; func Main() -> int { // `true` and `false` are the only boolean literals, and either one makes a `bool`. let ready = true; let finished = false; PrintLine("ready {}", ready); PrintLine("finished {}", finished); // The type can be written out, as with any variable. let visible: bool = true; PrintLine("visible {}", visible); // The wider types print the same way. Only their size differs. let flag8: bool8 = true; let flag16: bool16 = false; let flag32: bool32 = true; let flag64: bool64 = false; PrintLine("bool8 {}", flag8); PrintLine("bool16 {}", flag16); PrintLine("bool32 {}", flag32); PrintLine("bool64 {}", flag64); let flag128: bool128 = true; let flag256: bool256 = false; let flag512: bool512 = true; PrintLine("bool128 {}", flag128); PrintLine("bool256 {}", flag256); PrintLine("bool512 {}", flag512); // A boolean is not a number. Some languages treat 0 as false and 1 as true; Rux does not mix // them up on its own: // // let on: bool = 1; // error: cannot assign 'int' to 'bool8' // // The message names `bool8` because that is what `bool` is. Turning a number into a boolean, // or back, is a conversion you ask for, and the Convert lesson shows how. return 0; } ``` ## Run it ```sh cd Examples/Basics/Boolean rux run ``` ```text ready true finished false visible true bool8 true bool16 false bool32 true bool64 false bool128 true bool256 false bool512 true ``` ## Common mistakes ::mistake **Using a number as a boolean.**:br Some languages treat 0 as false and 1 as true; Rux does not mix them up on its own. `let on: bool = 1;` fails with: ```text error: cannot assign 'int' to 'bool8' ``` The message names `bool8` because that is what `bool` is. Converting is something you ask for with `as`, as the [Convert](https://rux-lang.dev/docs/learn/convert) lesson shows. :: ## Try it yourself 1. Declare `let raining = true;` and `let umbrella = false;` and print a sentence using both. 2. Try `let on: bool = 1;` and read the message. 3. Look ahead: in the [Comparison](https://rux-lang.dev/docs/learn/comparison) lesson, find the line that produces a `bool` without writing `true` or `false`. ## Learn more - [`bool`](https://rux-lang.dev/docs/lang/types/booleans) in the Rux Reference - [Logical](https://rux-lang.dev/docs/learn/logical) — combining booleans with `&&`, `||` and `!` # Character ::note **You'll need**: [Variable](https://rux-lang.dev/docs/learn/variable), [Integer](https://rux-lang.dev/docs/learn/integer) :: A character is one Unicode *code point*: a letter, a digit, a symbol, an emoji. A character literal is written in **single** quotes, `'A'`. Double quotes make a string instead — a sequence of characters, and a topic of its own in [Part 14](https://rux-lang.dev/docs/learn/text). ## The char type `char` is the everyday type. It is another name for `char32`: four bytes, enough for every code point there is. Any character fits: ```rux let letter = 'A'; let accented = 'é'; let greek: char = 'π'; let emoji = '😀'; ``` ## Escapes A backslash starts an escape, for characters that are awkward to type between quotes: | Escape | Character | | ------------ | ----------------------------------------------------- | | `'\''` | a single quote | | `'\\'` | a backslash | | `'\n'` | a line break | | `'\t'` | a tab | | `'\u{263A}'` | any code point, by its number in hexadecimal — here ☺ | ```rux let quote = '\''; let backslash = '\\'; let smile = '\u{263A}'; ``` ## Code units and code points A prefix picks another character type, and two of them are different in kind: ```rux let unit8 = c8'R'; let unit16 = c16'Ж'; let scalar32 = c32'€'; let scalar64 = c64'😀'; let scalar512 = c512'🦀'; ``` | Prefix | Type | Holds | | --------------- | --------------------- | --------------------------------------- | | `c8` | `char8` | One **byte** of UTF-8 text | | `c16` | `char16` | One **unit** of UTF-16 text | | `c32` (or none) | `char32` = `char` | One whole code point | | `c64` | `char64` | One whole code point, in eight bytes | | `c128` … `c512` | `char128` … `char512` | One whole code point, in 16 to 64 bytes | A `char8` or `char16` is a *piece* of an encoding, and a piece is a whole character only when the code point is small enough to fit in one: ```mermaid flowchart LR R["`'R'` — U+0052"] --> r8["UTF-8: 1 byte
fits a `char8`"] E["`'é'` — U+00E9"] --> e8["UTF-8: 2 bytes
does not fit a `char8`"] E --> e16["UTF-16: 1 unit
fits a `char16`"] S["`'😀'` — U+1F600"] --> s16["UTF-16: 2 units
does not fit a `char16`"] S --> s32["fits a `char32`"] ``` Plain ASCII fits a `char8`; most living scripts fit a `char16`; everything fits a `char`. The [Encoding](https://rux-lang.dev/docs/learn/encoding) and [UTF-8](https://rux-lang.dev/docs/learn/utf8) lessons go deeper. ## A literal takes its binding's type Without a prefix, a literal is a `char32` — unless its binding names a narrower type, which it then takes. So `let initial: char8 = 'R';` works too, as long as the character fits in one unit. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Basics/Character){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // A character is one Unicode code point: a letter, a digit, a symbol, an emoji. A character // literal is written in single quotes, 'A'. Double quotes make a string instead, which is a // sequence of characters and a topic of its own. // // `char` is the everyday type. It is another name for `char32`, four bytes, enough for every code // point there is, and it is the type a quoted character gets when nothing says otherwise. import Io::PrintLine; func Main() -> int { // Any code point fits in a `char`, from plain ASCII to an emoji. let letter = 'A'; let accented = 'é'; let greek: char = 'π'; let emoji = '😀'; PrintLine("letter {}", letter); PrintLine("accented {}", accented); PrintLine("greek {}", greek); PrintLine("emoji {}", emoji); // A backslash starts an escape, for characters that are awkward to type between quotes: // '\'' is a single quote, '\\' a backslash, '\n' a line break and '\t' a tab. `\u{...}` // names any code point by its number in hexadecimal. let quote = '\''; let backslash = '\\'; let smile = '\u{263A}'; PrintLine("quote {}", quote); PrintLine("backslash {}", backslash); PrintLine("smile {}", smile); // A prefix picks another width. `c32` spells the default out, and `c64`, `c128`, `c256` and // `c512` hold the same code points in 8, 16, 32 and 64 bytes. `c8` and `c16` are different in kind: a `char8` holds one byte of // UTF-8 text and a `char16` one unit of UTF-16 text. Those are pieces of an encoding, and a // piece is a whole character only for the code points small enough to fit in one: plain // ASCII for `char8`, and most living scripts for `char16`. let unit8 = c8'R'; let unit16 = c16'Ж'; let scalar32 = c32'€'; let scalar64 = c64'😀'; PrintLine("char8 {}", unit8); PrintLine("char16 {}", unit16); PrintLine("char32 {}", scalar32); PrintLine("char64 {}", scalar64); let scalar128 = c128'ß'; let scalar256 = c256'λ'; let scalar512 = c512'🦀'; PrintLine("char128 {}", scalar128); PrintLine("char256 {}", scalar256); PrintLine("char512 {}", scalar512); // Without a prefix, a literal is a `char32` unless its binding names a narrower type; then it // takes that type, so `let initial: char8 = 'R';` works too. Either way the character has to // fit in one unit, and one that does not is refused: // // let accent = c8'é'; // error: character 'é' (U+00E9) does not fit one 'char8' code unit // help: write a string literal such as c8"é", or a byte such as 0xE9u8 // // é takes two bytes of UTF-8, and one `char8` holds only one of them. Text that needs several // units is a string, which has a lesson of its own. return 0; } ``` ## Run it ```sh cd Examples/Basics/Character rux run ``` ```text letter A accented é greek π emoji 😀 quote ' backslash \ smile ☺ char8 R char16 Ж char32 € char64 😀 char128 ß char256 λ char512 🦀 ``` ## Common mistakes ::mistake **A character too big for its code unit.**:br`let accent = c8'é';` fails with: ```text error: character 'é' (U+00E9) does not fit one 'char8' code unit ``` The compiler suggests a string literal such as `c8"é"` instead. é takes two bytes of UTF-8, and one `char8` holds only one of them. :: ::mistake **Double quotes for a character.**:br`"A"` is a string, not a character. Use single quotes for one character. :: ## Try it yourself 1. Print the first letter of your name, a digit and an emoji, each as a `char`. 2. Print a tab character between two letters using `'\t'`. 3. Find a code point in a table (for example U+2665, a heart) and print it with `'\u{…}'`. 4. Try `c8'ж'` and read the message. Which prefix makes it fit? ## Learn more - [`char`](https://rux-lang.dev/docs/lang/types/characters) and [`char8`](https://rux-lang.dev/docs/lang/types/characters) in the Rux Reference - [Character pattern](https://rux-lang.dev/docs/learn/character-pattern) — matching characters with `match` - [Encoding](https://rux-lang.dev/docs/learn/encoding) and [UTF-8](https://rux-lang.dev/docs/learn/utf8) — characters inside text # Literal ::note **You'll need**: [Integer](https://rux-lang.dev/docs/learn/integer), [Float](https://rux-lang.dev/docs/learn/float) :: A *literal* is a value written straight into the source: `42`, `2.5`, `'A'`, `true`. This lesson is about the numeric ones — the many ways one number can be spelled — and about a rule that surprises people: how a literal gets its **type**. ## Four bases A prefix picks the base. The base is only how the source spells the value, so all four variables hold the same 255: ```rux let decimal = 255; let hex = 0xFF; let octal = 0o377; let binary = 0b11111111; ``` | Prefix | Base | Typical use | | ------ | ---- | -------------------------------------- | | none | 10 | Everyday numbers | | `0x` | 16 | Colours, memory addresses, byte values | | `0o` | 8 | File permissions | | `0b` | 2 | Bit flags and masks | ## Digit separators An underscore between digits is ignored. It groups them the way a comma does on paper: ```rux let population = 8_100_000_000; let mask = 0xFFFF_0000; let flags = 0b1010_0101; ``` ## Exponents A float literal may carry an exponent: `e8` means "times ten to the eighth". ```rux let light = 2.998e8; let charge = 1.6e-19; ``` ## Suffixes A suffix fixes the type inside the literal itself: ```rux let small = 200u8; let wide = 5i64; let single = 0.5f32; let half = 0.5f16; ``` `u8` makes a `uint8`, `i64` an `int64`, `f32` a `float32` and `f16` a `float16`; plain `u` and `i` mean `uint` and `int`. Every width has one: | Signed | Unsigned | Floating-point | | ------------- | -------------- | -------------------------------------------------------- | | `i8` … `i512` | `u8` … `u512` | `f8`, `f16`, `f32`, `f64`, `f80`, `f128`, `f256`, `f512` | | `i` for `int` | `u` for `uint` | | A literal of any width is read exactly, however long. This one is too big for 64 bits, so without its suffix it would be refused as out of range for `int`: ```rux let huge = 340_282_366_920_938_463_463_374_607_431_768_211_455u128; ``` ## How a literal gets its type This is the part worth slowing down for: ```mermaid flowchart LR lit["An unsuffixed literal,
such as `100`"] --> q{"Is it next to a value
that already has a type?"} q -- "no — it stands alone
or beside another literal" --> def["`int`, or `float64` for `2.5`"] q -- "yes" --> partner["It takes that value's type"] partner --> fit{"Does it fit that type?"} fit -- "yes" --> ok["Compiled in that type"] fit -- "no" --> err["`error: integer literal is`
`out of range for type …`"] ``` Here `100` sits next to `level`, a `uint8`, so it becomes a `uint8` too, and the sum is worked out in eight bits. 300 does not fit in eight bits: the result wraps around past 255 and lands on 44. ```rux let level: uint8 = 200; let raised = level + 100; ``` Two literals together have no typed partner, so both are `int` and the sum is plain 300: ```rux let plain = 200 + 100; ``` Wrapping is covered properly in [Arithmetic](https://rux-lang.dev/docs/learn/arithmetic) and [Wrapping arithmetic](https://rux-lang.dev/docs/learn/wrapping-arithmetic). ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Basics/Literal){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // A literal is a value written straight into the source: 42, 2.5, 'A', true. This lesson is about // the numeric ones — the many ways one number can be spelled, and how a literal gets its type. import Io::PrintLine; func Main() -> int { // The same number in four bases. A prefix picks the base: `0x` for hexadecimal, `0o` for // octal and `0b` for binary. The base is only how the source spells the value, so all four // variables hold the same 255 and print it the same way. let decimal = 255; let hex = 0xFF; let octal = 0o377; let binary = 0b11111111; PrintLine("bases {} {} {} {}", decimal, hex, octal, binary); // An underscore between digits is ignored. It groups them the way a comma does on paper. let population = 8_100_000_000; let mask = 0xFFFF_0000; let flags = 0b1010_0101; PrintLine("separators {} {} {}", population, mask, flags); // A float literal may carry an exponent: `e8` means "times ten to the eighth". let light = 2.998e8; let charge = 1.6e-19; PrintLine("exponents {} {}", light, charge); // A suffix fixes the type inside the literal itself: `u8` makes a uint8, `i64` an int64 and // `f32` a float32. Plain `u` and `i` mean `uint` and `int`. Every width has its suffix, from // `i8` to `i512`, `u8` to `u512` and `f8` to `f512`, and a literal of any width is read // exactly: the one below is too big for 64 bits but fits a uint128. let small = 200u8; let wide = 5i64; let single = 0.5f32; let half = 0.5f16; PrintLine("suffixes {} {} {} {}", small, wide, single, half); let huge = 340_282_366_920_938_463_463_374_607_431_768_211_455u128; PrintLine("u128 {}", huge); // With no suffix, a literal standing alone is an `int` or a `float64`. Next to a value that // already has a type, it takes that value's type instead. Here 100 becomes a uint8, the sum // is worked out in eight bits, and 300 does not fit in eight bits: the result wraps around // past 255 and lands on 44. let level: uint8 = 200; let raised = level + 100; PrintLine("uint8 {}", raised); // Two literals together have no typed partner, so both are `int` and the sum is plain 300. let plain = 200 + 100; PrintLine("int {}", plain); // Because the literal takes the other side's type, it must also fit that type. These two are // refused rather than quietly turned into something else: // // let over = level + 300; // error: integer literal is out of range for type 'uint8' // // let count: uint = 3; // let missing = count == -1; // error: integer literal is out of range for type 'uint' return 0; } ``` ## Run it ```sh cd Examples/Basics/Literal rux run ``` ```text bases 255 255 255 255 separators 8100000000 4294901760 165 exponents 299800000.0 1.6e-19 suffixes 200 5 0.5 0.5 u128 340282366920938463463374607431768211455 uint8 44 int 300 ``` ## Common mistakes ::mistake **A literal that does not fit its partner's type.**:br Because the literal takes the other side's type, it must also fit it. When `level` is a `uint8`, `level + 300` fails with: ```text error: integer literal is out of range for type 'uint8' ``` 300 is not a `uint8`. :: ::mistake **A negative literal next to an unsigned value.**:br With `let count: uint = 3;`, the comparison `count == -1` fails the same way: `-1` would have to be a `uint`, and no `uint` is negative. :: ## Try it yourself 1. Print `0b1111_0000`, `0xF0` and `0o360`. Are they the same number? 2. Write the speed of light in km/s as `2.998e5` and the mass of an electron as `9.109e-31`. 3. Change `level + 100` to `level + 300` and read the error. Then make it compile by giving `level` a wider type. ## Learn more - [Literals](https://rux-lang.dev/docs/lang/lexical/literals) in the Rux Reference - [Integer](https://rux-lang.dev/docs/learn/integer) and [Float](https://rux-lang.dev/docs/learn/float) — the types literals become - [Format number](https://rux-lang.dev/docs/learn/format-number) — printing numbers in hexadecimal and binary # Console ::note **You'll need**: [Hello, World](https://rux-lang.dev/docs/learn/hello), [Variable](https://rux-lang.dev/docs/learn/variable), [Literal](https://rux-lang.dev/docs/learn/literal) :: Every lesson so far has printed with `PrintLine`. This one looks at it closely, together with its partner `Print` — and at the `{}` placeholders that put values inside text. ## Print and PrintLine The difference is one thing: `PrintLine` ends the line it writes, and `Print` leaves the cursor where it stopped, so the next output carries on the same line. ```rux Print("one "); Print("two "); PrintLine("three"); ``` ```text one two three ``` A `\n` inside the text is a line break too, so `PrintLine` is `Print` with one added: ```rux Print("four\nfive\n"); ``` With nothing to print, `PrintLine` writes only the line ending — a blank line: ```rux PrintLine(); ``` Both live in `Io`, and the lesson imports them together with braces: ```rux import Io::{ Print, PrintLine }; ``` ## Printing values A value can be printed on its own, with no text around it — `PrintLine(42);`, `PrintLine(2.5);`, `PrintLine(true);`. More often the value goes inside a message. Each `{}` is filled by the next argument, in the order they are written: ```rux let name = "Rux"; let major = 0; let minor = 4; PrintLine("{} version {}.{}", name, major, minor); ``` ```mermaid flowchart LR fmt["`{} version {}.{}`"] --> out["`Rux version 0.4`"] a1["`name` → `Rux`"] -- "1st `{}`" --> fmt a2["`major` → `0`"] -- "2nd `{}`" --> fmt a3["`minor` → `4`"] -- "3rd `{}`" --> fmt ``` `Print` takes placeholders as well, so a line can be built from pieces: ```rux Print("{} + {} = ", 2, 3); PrintLine("{}", 2 + 3); ``` ## Printing a brace To print a brace itself in text that has placeholders, double it. Text passed with *no* arguments is printed exactly as written, so there a single brace is fine: ```rux PrintLine("{{}} marks a place for {}", "a value"); PrintLine("{} with nothing to fill it"); ``` ```text {} marks a place for a value {} with nothing to fill it ``` Width, alignment and decimal places inside `{}` — such as `{:>6}` or `{:.2}` — come in the [Format](https://rux-lang.dev/docs/learn/format) lesson. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Basics/Console){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // Every lesson so far has printed with `PrintLine`. This one looks at it closely, together with its // partner `Print`. The difference between them is one thing: `PrintLine` ends the line it writes, // and `Print` leaves the cursor where it stopped, so the next output carries on the same line. import Io::{ Print, PrintLine }; func Main() -> int { // Three calls, one line, because only the last call ends it. Print("one "); Print("two "); PrintLine("three"); // A `\n` inside the text is a line break too, so `PrintLine` is `Print` with one added. Print("four\nfive\n"); // With nothing to print, `PrintLine` writes only the line ending: a blank line. PrintLine(); // A value can be printed on its own, with no text around it. PrintLine(42); PrintLine(2.5); PrintLine(true); // More often the value goes inside a message. Each `{}` is filled by the next argument, in // the order they are written, and any kind of value can fill one. let name = "Rux"; let major = 0; let minor = 4; PrintLine("{} version {}.{}", name, major, minor); // `Print` takes placeholders as well, so a line can be built from pieces. Print("{} + {} = ", 2, 3); PrintLine("{}", 2 + 3); // To print a brace itself in text that has placeholders, double it. Text passed with no // arguments at all is printed exactly as written, so there a brace is single. PrintLine("{{}} marks a place for {}", "a value"); PrintLine("{} with nothing to fill it"); // Watch the count. Once a call has arguments, the compiler matches them against the // placeholders, and a placeholder with no argument, or an argument with no placeholder, is // refused: // // PrintLine("{} and {}", 1); // error: format string has 2 placeholders, but 1 argument was provided // help: pass one argument for each '{}' placeholder // // Width, alignment and decimal places inside `{}` wait for the Format lesson. return 0; } ``` ## Run it ```sh cd Examples/Basics/Console rux run ``` ```text one two three four five 42 2.5 true Rux version 0.4 2 + 3 = 5 {} marks a place for a value {} with nothing to fill it ``` ## Common mistakes ::mistake **Placeholders and arguments that do not match.**:br Once a call has arguments, the compiler counts them against the placeholders. `PrintLine("{} and {}", 1);` fails with: ```text error: format string has 2 placeholders, but 1 argument was provided ``` Pass one argument for each `{}`. :: ## Try it yourself 1. Print a small receipt: three items with their prices, each on its own line, and a total on the last. 2. Use `Print` in three calls to build `1, 2, 3` on one line, then end it with `PrintLine()`. 3. Print the text `{name}` literally, followed by a placeholder filled with your name. ## Learn more - [`Print`](https://rux-lang.dev/docs/api/io/print) in the API Reference - [Format](https://rux-lang.dev/docs/learn/format) and [Format number](https://rux-lang.dev/docs/learn/format-number) — width, alignment, precision and bases - [Input](https://rux-lang.dev/docs/learn/input) — the other direction: reading what the user types # Const ::note **You'll need**: [Variable](https://rux-lang.dev/docs/learn/variable), [Literal](https://rux-lang.dev/docs/learn/literal), [Console](https://rux-lang.dev/docs/learn/console) :: `let` names a value while the program **runs**. `const` names one while the program is being **compiled**: the compiler works the value out once, and every use of the name is replaced by the answer. Nothing is left to compute at run time. ## Declaring constants A constant is declared like a variable, with `const`, and its type is inferred the same way — or written out when the inferred `int` is not the type wanted: ```rux const Limit = 100; const Greeting = "Hello from a constant"; const MaxPlayers: uint8 = 4; const Pi: float32 = 3.1415927f32; ``` Constants are named in **PascalCase**, like types, so they stand out from variables. ## Constants built from constants A constant may be built from other constants, because all of them are known while compiling. `Doubled` costs nothing when the program runs — the compiler has already stored 200: ```rux const Doubled = Limit * 2; const Half = Limit / 2; ``` ## Where a constant can live Constants can be declared **outside any function**, at the top of the file, where the whole file can use them. They can also live inside a function, where only that function sees them: ```rux const SecondsPerHour = 60 * 60; ``` In an expression, a constant is used like any other value — here beside a run-time `let`: ```rux let hours = 3; let seconds = hours * SecondsPerHour; ``` ## const or let? ```mermaid flowchart TD q{"Is the value known
before the program runs?"} q -- "yes: a fixed number, a limit,
a name, a conversion factor" --> c["`const` — computed once by the compiler,
usable anywhere in the file"] q -- "no: it depends on input,
a calculation, a variable" --> l["`let` — computed while the program runs"] ``` Because a constant's value is known before the program runs, it can go where the compiler itself needs a value: the length of an array (`bool[Limit]`, in [Part 5](https://rux-lang.dev/docs/learn/array)) and the condition of a compile-time [`when`](https://rux-lang.dev/docs/learn/when). ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Basics/Const){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // `let` names a value while the program runs. `const` names one while the program is being // compiled: the compiler works the value out once, and every use of the name is replaced by the // answer. Nothing is left to compute at run time. // // That buys two things. A constant can be declared outside any function, at the top of the file, // where all of the file can use it. And because its value is known before the program runs, it // can go where the compiler itself needs a value: the length of an array, as in `bool[Limit]`, // once arrays arrive in Part 5, and the condition of a `when`, which comes later still. import Io::PrintLine; // The type is inferred, exactly as with `let`. const Limit = 100; const Greeting = "Hello from a constant"; // Or written out, when the inferred `int` is not the type wanted. const MaxPlayers: uint8 = 4; const Pi: float32 = 3.1415927f32; // A constant may be built from other constants, because all of them are known while compiling. // `Doubled` costs nothing when the program runs: the compiler has already stored 200. const Doubled = Limit * 2; const Half = Limit / 2; func Main() -> int { PrintLine("Limit {}", Limit); PrintLine("Greeting {}", Greeting); PrintLine("MaxPlayers {}", MaxPlayers); PrintLine("Pi {}", Pi); PrintLine("Doubled {}", Doubled); PrintLine("Half {}", Half); // A constant can also live inside a function, where only that function sees it. const SecondsPerHour = 60 * 60; // In an expression a constant is used like any other value, here beside a run-time `let`. let hours = 3; let seconds = hours * SecondsPerHour; PrintLine("3 hours {} seconds", seconds); // Build a constant only from literals and other constants. A `let` or a `var` gets its // value while the program runs, which is too late for a `const`: // // let hours = 3; // const Seconds = hours * 3600; // error: 'hours' is not a compile-time constant // help: declare 'Seconds' with 'let' to compute it at run time // // Constants are named in PascalCase, like types, so they stand out from variables. return 0; } ``` ## Run it ```sh cd Examples/Basics/Const rux run ``` ```text Limit 100 Greeting Hello from a constant MaxPlayers 4 Pi 3.1415927 Doubled 200 Half 50 3 hours 10800 seconds ``` ## Common mistakes ::mistake **Building a constant from a variable.**:br A `let` or `var` gets its value while the program runs, which is too late for a `const`. `let hours = 3; const Seconds = hours * 3600;` fails with: ```text error: 'hours' is not a compile-time constant ``` The compiler suggests declaring `Seconds` with `let` instead. :: ## Try it yourself 1. Add `const MinutesPerDay = 24 * 60;` at the top of the file and print it. 2. Make a `const TaxRate = 0.2;` and use it with a `let price = 50.0;` to print the tax. 3. Try building a `const` from a `let` and read the error. ## Learn more - [Constants](https://rux-lang.dev/docs/lang/bindings/constants) in the Rux Reference - [When](https://rux-lang.dev/docs/learn/when) — choosing code at compile time # Convert ::note **You'll need**: [Integer](https://rux-lang.dev/docs/learn/integer), [Float](https://rux-lang.dev/docs/learn/float), [Boolean](https://rux-lang.dev/docs/learn/boolean), [Character](https://rux-lang.dev/docs/learn/character) :: Rux converts between types on its own only when nothing can be lost. Every other conversion has to be asked for with `as` — because every other conversion can change the value. Writing `as` is how you tell the compiler, and the next reader, that the change is intended. ## Widening happens on its own Widening within one family and one signedness — `int8` to `int32`, `float32` to `float64` — can never lose anything, so the compiler does it silently: ```rux let small: int8 = 100; let widened: int32 = small; ``` ## Everything else needs as ```mermaid flowchart TD src["A value of type `A`, needed as type `B`"] --> w{"Same family and signedness,
and `B` is wider?"} w -- "yes" --> auto["Converted automatically"] w -- "no" --> as["Write `value as B`"] as --> n["Narrower integer:
keeps the low bits"] as --> s["Other signedness:
same bits, read differently"] as --> f2i["Float to integer:
truncates toward zero, saturates"] as --> i2f["Integer to float, char to number,
bool to number and back"] ``` ### Narrowing keeps the low bits 300 needs nine bits; an `int8` has eight, and what survives is 300 − 256 = 44: ```rux let big: int32 = 300; let narrowed = big as int8; ``` ### Changing signedness re-reads the bits −1 has every bit set, and eight set bits read as an unsigned number are 255: ```rux let negative: int32 = -1; let reinterpreted = negative as uint8; ``` ### Floats and integers Integers and floats are different families, so crossing between them always needs `as`. Float to integer drops the fraction — it truncates toward zero rather than rounding: ```rux let ratio = 3.9; let negativeRatio = -3.9; ``` `ratio as int32` is `3`, and `negativeRatio as int32` is `-3`. A float too large for the integer type does not keep low bits the way narrowing does: it **saturates** to the largest (or smallest) value the type holds, so `1e10 as int32` is `2147483647`. A narrower float keeps fewer digits, so `float64` to `float32` needs `as` as well: `3.141592653589793` becomes `3.1415927`. ### Characters and booleans A character is a number underneath — its code point — and `as` shows it: `'A' as uint32` is `65`. A boolean becomes `1` or `0`; in the other direction, zero is `false` and anything else is `true`. ## as never fails None of these conversions reports a problem. A conversion with `as` always produces a value, and when the original does not fit, that value is simply a different one. To find out first whether a value fits, compare it with the target type's limits — or use the checked conversions of [Checked convert](https://rux-lang.dev/docs/learn/checked-convert). | Conversion | Example | Result | | -------------------- | -------------------------- | ---------- | | Widen | `int8` 100 → `int32` | 100 | | Narrow | `int32` 300 `as int8` | 44 | | Signedness | `int32` −1 `as uint8` | 255 | | Float → int | 3.9 `as int32` | 3 | | Float → int, too big | 1e10 `as int32` | 2147483647 | | Int → float | 7 `as float64` | 7.0 | | Char → int | 'A' `as uint32` | 65 | | Bool ↔ int | `true as int`, `5 as bool` | 1, true | ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Basics/Convert){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // A conversion happens on its own only when nothing can be lost: widening within one family and // one signedness, such as `int8` to `int32` or `float32` to `float64`. Every other conversion is // asked for with `as`, because every other conversion can change the value. Writing `as` is how // you tell the compiler, and the next reader, that the change is intended. import Io::PrintLine; func Main() -> int { // Widening needs no `as`. Every `int8` is also an `int32`, so the compiler converts silently. let small: int8 = 100; let widened: int32 = small; PrintLine("widen int8 {} becomes int32 {}", small, widened); // Narrowing must be asked for, and keeps only the low bits that fit. 300 needs nine bits, an // `int8` has eight, and what survives is 300 - 256. let big: int32 = 300; let narrowed = big as int8; PrintLine("narrow int32 {} becomes int8 {}", big, narrowed); // Changing signedness keeps the bits and reads them differently: -1 has every bit set, and // eight set bits read as an unsigned number are 255. let negative: int32 = -1; let reinterpreted = negative as uint8; PrintLine("sign int32 {} becomes uint8 {}", negative, reinterpreted); // Integers and floats are different families, so crossing between them always needs `as`. // Float to integer drops the fraction: it truncates toward zero rather than rounding. let ratio = 3.9; let negativeRatio = -3.9; PrintLine("float->int {} becomes {}", ratio, ratio as int32); PrintLine("float->int {} becomes {}", negativeRatio, negativeRatio as int32); // A float too large for the integer type does not keep low bits the way narrowing does. It // saturates: it becomes the largest value the type holds, or the smallest, below the range. let huge = 1e10; PrintLine("float->int {} becomes {}", huge, huge as int32); let count: int32 = 7; PrintLine("int->float {} becomes {}", count, count as float64); // A narrower float keeps fewer digits, so float64 to float32 needs `as` as well. let pi = 3.141592653589793; PrintLine("narrow float {} becomes {}", pi, pi as float32); // A character is a number underneath, its code point, and `as` shows it. let letter = 'A'; PrintLine("char->int {} becomes {}", letter, letter as uint32); // A boolean becomes 1 or 0. In the other direction, zero is false and anything else is true. let yes = true; let five = 5; PrintLine("bool->int {} becomes {}", yes, yes as int); PrintLine("int->bool {} becomes {}", five, five as bool); // None of the conversions above reported a problem. A conversion with `as` never fails: it // always produces a value, and when the original does not fit, that value is simply a // different one. To find out first whether a value fits, compare it with the target type's // limits — comparisons are the next part, and choosing what to do with the answer the one // after. return 0; } ``` ## Run it ```sh cd Examples/Basics/Convert rux run ``` ```text widen int8 100 becomes int32 100 narrow int32 300 becomes int8 44 sign int32 -1 becomes uint8 255 float->int 3.9 becomes 3 float->int -3.9 becomes -3 float->int 10000000000.0 becomes 2147483647 int->float 7 becomes 7.0 narrow float 3.141592653589793 becomes 3.1415927 char->int A becomes 65 bool->int true becomes 1 int->bool 5 becomes true ``` ## Common mistakes ::mistake **Expecting rounding.**:br`2.99 as int32` is `2`, not `3`: conversion truncates toward zero. Round first if that is what you mean — the [Math](https://rux-lang.dev/docs/learn/math) lesson has `Round`. :: ::mistake **Expecting an error on overflow.**:br`as` never fails. `300 as int8` quietly becomes `44`. When the value might not fit, check it first or use [Checked convert](https://rux-lang.dev/docs/learn/checked-convert). :: ## Try it yourself 1. Convert `-1 as uint16` and `-1 as uint32`. Predict the results before you run. 2. Print the code points of the letters in `R`, `u`, `x` with `as uint32`. 3. Convert `-1e10` to `int32` and check that it saturates to the smallest value. ## Learn more - [Type casts](https://rux-lang.dev/docs/lang/expressions/casts) in the Rux Reference - [Checked convert](https://rux-lang.dev/docs/learn/checked-convert) — conversions that report whether the value fits - [Wrapping arithmetic](https://rux-lang.dev/docs/learn/wrapping-arithmetic) — what happens when arithmetic overflows # Part 2: Operators Part 1 gave you values and names for them. This part combines them: adding and dividing numbers, comparing them, joining yes-or-no answers into bigger conditions, and updating a variable in place. It is a short part — five lessons — but every program you write from here on is built from these operators, and the comparisons and conditions are exactly what [Part 3](https://rux-lang.dev/docs/learn/control-flow) needs to make decisions. ## What you will learn - Arithmetic with `+ - * / %`, and why `17 / 5` is 3 for integers but 3.4 for floats. - Comparing values with `== != < <= > >=`, and why exact `==` between floats is risky. - Combining conditions with `&&`, `||` and `!`, and how short-circuiting lets one side guard the other. - Updating a variable with `+=`, `-=` and friends, and stepping it with `++` and `--`. - Which operator applies first, how same-rank operators group, and when to add parentheses. ## What each kind of operator produces ```mermaid flowchart LR n["Numbers"] -- "`+ - * / %`" --> n2["A number"] n -- "`== != < <= > >=`" --> b["A `bool`"] b -- "`&& || !`" --> b2["A `bool`"] v["A `var`"] -- "`+= -= ++ --`" --> v2["The same `var`,
updated in place"] b2 --> cf["Conditions for
Part 3: Control flow"] b --> cf ``` ## Lessons | | Lesson | What you will learn | | --- | -------------------------------------------------------- | ------------------------------------------------------------ | | 2.1 | [Arithmetic](https://rux-lang.dev/docs/learn/arithmetic) | add, subtract, multiply, divide and take the remainder | | 2.2 | [Comparison](https://rux-lang.dev/docs/learn/comparison) | compare two values with `==`, `!=`, `<`, `<=`, `>` and `>=` | | 2.3 | [Logical](https://rux-lang.dev/docs/learn/logical) | combine conditions with `&&`, `||` and `!` | | 2.4 | [Assignment](https://rux-lang.dev/docs/learn/assignment) | update a variable in place with `+=`, `-=`, `++` and friends | | 2.5 | [Precedence](https://rux-lang.dev/docs/learn/precedence) | which operator binds first, and how parentheses change it | ## Before you start Finish [Part 1: Basics](https://rux-lang.dev/docs/learn/basics) first — especially [Variable](https://rux-lang.dev/docs/learn/variable), [Mutable](https://rux-lang.dev/docs/learn/mutable), the number types and [Convert](https://rux-lang.dev/docs/learn/convert). Each lesson's package is in the Examples repository's `Operators/` folder: ```sh cd Examples/Operators/Arithmetic rux run ``` ## After this part [Part 3: Control flow](https://rux-lang.dev/docs/learn/control-flow) puts the conditions you can now write to work, making programs choose between paths and repeat. After it come the first checkpoint projects, [Thanks](https://rux-lang.dev/docs/learn/thanks) and [FizzBuzz](https://rux-lang.dev/docs/learn/fizz-buzz) — FizzBuzz in particular is built on `%`, `==` and `+=` from this part. For the full rules, see [Operations](https://rux-lang.dev/docs/lang/expressions/overview) — [arithmetic](https://rux-lang.dev/docs/lang/expressions/arithmetic), [comparison](https://rux-lang.dev/docs/lang/expressions/comparison) and [logical](https://rux-lang.dev/docs/lang/expressions/logical) — and the [operator list](https://rux-lang.dev/docs/lang/lexical/operators) in the Rux Reference. # Arithmetic ::note **You'll need**: [Variable](https://rux-lang.dev/docs/learn/variable), [Integer](https://rux-lang.dev/docs/learn/integer), [Float](https://rux-lang.dev/docs/learn/float), [Console](https://rux-lang.dev/docs/learn/console), [Convert](https://rux-lang.dev/docs/learn/convert) :: Arithmetic is the first thing most programs do with their values: add up a bill, split it between friends, work out what is left over. Rux has five arithmetic operators, and they look the way they do in maths. The one surprise is division — dividing two whole numbers gives a whole number, and the fraction is quietly dropped. ## The five operators | Operator | Meaning | `17` and `5` give | | -------- | -------------- | ----------------- | | `+` | Addition | `22` | | `-` | Subtraction | `12` | | `*` | Multiplication | `85` | | `/` | Division | `3` | | `%` | Remainder | `2` | Each one takes a value on either side and produces a new value. Neither operand changes — `a + b` reads `a` and `b` and hands back their sum: ```rux let a: int32 = 17; let b: int32 = 5; PrintLine("{} + {} = {}", a, b, a + b); ``` ## Integer division drops the fraction On paper, 17 divided by 5 is 3.4. Two integers cannot hold 3.4, so integer division **truncates**: it keeps the whole part and throws the rest away. The `%` operator gives back the part that was dropped, the remainder: ```rux PrintLine("{} / {} = {}", a, b, a / b); PrintLine("{} % {} = {}", a, b, a % b); ``` 17 is three fives and two left over, so `/` says `3` and `%` says `2`. The pair is useful far beyond maths homework — `%` is how a program asks "is this number even?" (`n % 2 == 0`) or "which minute of the hour is it?" (`seconds / 60 % 60`). Truncation goes **towards zero**, so −3.4 becomes −3 rather than −4. The remainder keeps the sign of the number being divided: ```rux PrintLine("{} / {} = {}", -a, b, -a / b); PrintLine("{} % {} = {}", -a, b, -a % b); ``` ## Floats keep the fraction Divide two floats and the fraction stays. `%` works on floats too, and gives what is left after taking out as many whole fives as fit: ```rux let x: float64 = 17.0; let y: float64 = 5.0; PrintLine("{} / {} = {}", x, y, x / y); PrintLine("{} % {} = {}", x, y, x % y); ``` What `/` does depends only on the types of its two operands: ```mermaid flowchart LR div["`left / right`"] --> q{"What are the
two operand types?"} q -- "both integers" --> int["Whole number:
`17 / 5` is `3`"] q -- "both floats" --> fl["Keeps the fraction:
`17.0 / 5.0` is `3.4`"] q -- "one of each" --> err["`error: operator '/' cannot combine`
`left operand 'int32' with`
`right operand 'float64'`"] err --> fix["Convert one side with `as`,
then divide"] ``` ## Both sides must have the same type Rux never mixes an `int32` and a `float64` on its own, because either choice could lose something. To divide two integers and keep the fraction, convert them first with `as` — the operator from [Convert](https://rux-lang.dev/docs/learn/convert): ```rux PrintLine("{} / {} as floats = {}", a, b, (a as float64) / (b as float64)); ``` Converting *after* the division is too late: `(a / b) as float64` is `3.0`, because the fraction was already gone. [Precedence](https://rux-lang.dev/docs/learn/precedence) looks at that case again. ## Overflow wraps around Every integer type has a largest value. A `uint8` holds 0 to 255, and a sum that goes past the top wraps around and starts again from 0 — with no warning: ```rux let level: uint8 = 250; PrintLine("uint8 {} + 10 = {}", level, level + 10); ``` 250 + 10 is 260, and 260 − 256 lands on 4. The `10` is a `uint8` here because an unsuffixed literal takes the type of the value beside it, as [Literal](https://rux-lang.dev/docs/learn/literal) showed. Choosing a type wide enough for your numbers is the everyday fix; [Wrapping arithmetic](https://rux-lang.dev/docs/learn/wrapping-arithmetic) and [Checked arithmetic](https://rux-lang.dev/docs/learn/checked-arithmetic) cover the tools for when it is not enough. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Operators/Arithmetic){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // The five arithmetic operators: `+`, `-`, `*`, `/` and `%`. They work on // integers and floats alike, but division means something different for each: // two integers give a whole-number answer and throw the fraction away, while two // floats keep it. import Io::PrintLine; func Main() -> int { let a: int32 = 17; let b: int32 = 5; PrintLine("{} + {} = {}", a, b, a + b); PrintLine("{} - {} = {}", a, b, a - b); PrintLine("{} * {} = {}", a, b, a * b); // Integer division truncates: 17 / 5 is 3, not 3.4. The `%` operator gives // back the part that division dropped, the remainder. PrintLine("{} / {} = {}", a, b, a / b); PrintLine("{} % {} = {}", a, b, a % b); // Truncation goes towards zero, so -3.4 becomes -3 rather than -4, and the // remainder keeps the sign of the number being divided. PrintLine("{} / {} = {}", -a, b, -a / b); PrintLine("{} % {} = {}", -a, b, -a % b); // Floats keep the fraction. `%` works on them too. let x: float64 = 17.0; let y: float64 = 5.0; PrintLine("{} / {} = {}", x, y, x / y); PrintLine("{} % {} = {}", x, y, x % y); // Both operands must have the same type: `a / y` is rejected, an `int32` // divided by a `float64`. To divide integers and keep the fraction, convert // them first with `as`. PrintLine("{} / {} as floats = {}", a, b, (a as float64) / (b as float64)); // An integer that outgrows its type wraps around without any warning. A // `uint8` holds 0 to 255, so 250 + 10 lands on 4. let level: uint8 = 250; PrintLine("uint8 {} + 10 = {}", level, level + 10); return 0; } ``` ## Run it ```sh cd Examples/Operators/Arithmetic rux run ``` ```text 17 + 5 = 22 17 - 5 = 12 17 * 5 = 85 17 / 5 = 3 17 % 5 = 2 -17 / 5 = -3 -17 % 5 = -2 17.0 / 5.0 = 3.4 17.0 % 5.0 = 2.0 17 / 5 as floats = 3.4 uint8 250 + 10 = 4 ``` ## Common mistakes ::mistake **Mixing an integer and a float.**:br When `a` is an `int32` and `y` is a `float64`, `a / y` fails with: ```text error: operator '/' cannot combine left operand 'int32' with right operand 'float64' ``` Convert one side with `as` so both have the same type. :: ::mistake **Expecting a fraction from two integers.**:br`17 / 5` is `3`, not `3.4`, and `(a / b) as float64` is `3.0`. Convert the operands *before* dividing, not the result after. :: ::mistake **Dividing an integer by zero.**:br The compiler does not catch it. The program stops while running, with the line it happened on and this message: ```text Panic: division by zero ``` When the divisor might be zero, test it first — [Logical](https://rux-lang.dev/docs/learn/logical) shows a neat way to do that. :: ## Try it yourself 1. Turn `1000` seconds into minutes and seconds using `/` and `%`, and print a line like `16 min 40 s`. 2. Change `a` and `b` to `-17` and `-5`. Predict both `/` and `%` before you run. 3. Work out the average of three `int32` scores, `7`, `8` and `10`, once as an integer and once as a `float64`. 4. Change the `uint8` example to `level - 251`. Which number does it wrap around to? ## Learn more - [Arithmetic operations](https://rux-lang.dev/docs/lang/expressions/arithmetic) in the Rux Reference - [Precedence](https://rux-lang.dev/docs/learn/precedence) — the order in which mixed operators apply - [Wrapping arithmetic](https://rux-lang.dev/docs/learn/wrapping-arithmetic) and [Checked arithmetic](https://rux-lang.dev/docs/learn/checked-arithmetic) — taking control of overflow - [Math](https://rux-lang.dev/docs/learn/math) — powers, roots and rounding # Comparison ::note **You'll need**: [Arithmetic](https://rux-lang.dev/docs/learn/arithmetic), [Boolean](https://rux-lang.dev/docs/learn/boolean), [Character](https://rux-lang.dev/docs/learn/character) :: Programs constantly ask questions about their values. Is the user old enough? Is the tank empty? Did the score beat the record? A comparison asks one such question about two values, and the answer is always a `bool` — `true` or `false`. That answer is what the next part, [Control flow](https://rux-lang.dev/docs/learn/control-flow), uses to decide what runs. ## Six questions | Operator | Asks | `17` and `5` give | | -------- | ---------------------- | ----------------- | | `==` | equal? | `false` | | `!=` | not equal? | `true` | | `<` | less than? | `false` | | `<=` | less than or equal? | `false` | | `>` | greater than? | `true` | | `>=` | greater than or equal? | `true` | Equality is written with **two** equals signs. A single `=` is assignment, which changes a variable rather than asking about it. ```rux let a: int32 = 17; let b: int32 = 5; PrintLine("{} == {} is {}", a, b, a == b); PrintLine("{} != {} is {}", a, b, a != b); ``` ## A comparison is a value The answer is an ordinary `bool`, so it can be printed, passed along, or kept in a variable with a name that says what it means: ```rux let age: int32 = 18; let adult = age >= 18; PrintLine("age {} is adult: {}", age, adult); ``` `adult` is a `bool`, inferred from the comparison. Naming a condition this way often makes the code that later tests it read like a sentence. ## Both sides must agree Like arithmetic, a comparison needs operands of compatible types. Two integers of the same signedness may differ in width — an `int8` compares with an `int64`, because the narrower one widens without loss. Everything else is refused: | Left | Right | Result | | ------- | --------- | ------------------------------------------- | | `int32` | `int32` | compared | | `int8` | `int64` | compared — the `int8` widens | | `int32` | `uint32` | refused — the operands differ in signedness | | `int32` | `float64` | refused — convert one side with `as` first | ## Characters compare by code point A character is a number underneath, as [Convert](https://rux-lang.dev/docs/learn/convert) showed, and comparing characters compares those numbers. Every capital letter comes before every lowercase one, so `'Z'` sorts ahead of `'a'`: ```rux let upper: char32 = 'Z'; let lower: char32 = 'a'; PrintLine("'{}' < '{}' is {}", upper, lower, upper < lower); ``` That is alphabetical order only within one case — worth remembering before sorting names. ## Floats and exact equality [Float](https://rux-lang.dev/docs/learn/float) showed that `0.1 + 0.2` is not exactly `0.3`. `==` sees the difference, however tiny: ```rux let sum: float64 = 0.1 + 0.2; PrintLine("0.1 + 0.2 == 0.3 is {}", sum == 0.3); PrintLine("0.1 + 0.2 > 0.3 is {}", sum > 0.3); ``` The sum lands just above 0.3, so `==` says `false` and `>` says `true`. Ordering comparisons on floats are fine; be wary of exact `==` between floats that came out of arithmetic. Ask instead whether two values are *close enough* — whether their difference is below some small tolerance you choose. ## Comparisons do not chain In maths, `1 < age < 30` means "age is between 1 and 30". In Rux, it does not: ```mermaid flowchart LR expr["`1 < age < 30`"] --> first["`1 < age`
is worked out first"] first --> b["a `bool`:
`true` or `false`"] b --> second["that `bool` `< 30`"] second --> err["`error: operator '<' cannot compare`
`left operand 'bool8'`
`with right operand 'int'`"] ``` The first comparison produces a `bool`, and a `bool` cannot be compared with a number. Asking two questions at once takes `&&` — `1 < age && age < 30` — the subject of the [next lesson](https://rux-lang.dev/docs/learn/logical). ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Operators/Comparison){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // The six comparison operators ask a yes-or-no question about two values: // `==` equal, `!=` not equal, `<` less, `<=` less or equal, `>` greater and // `>=` greater or equal. Whatever the operands are, the answer is a `bool`, so // it can be printed or kept in a variable like any other value. import Io::PrintLine; func Main() -> int { let a: int32 = 17; let b: int32 = 5; PrintLine("{} == {} is {}", a, b, a == b); PrintLine("{} != {} is {}", a, b, a != b); PrintLine("{} < {} is {}", a, b, a < b); PrintLine("{} <= {} is {}", a, b, a <= b); PrintLine("{} > {} is {}", a, b, a > b); PrintLine("{} >= {} is {}", a, b, a >= b); // A comparison is an ordinary expression, and its result is a value. let age: int32 = 18; let adult = age >= 18; PrintLine("age {} is adult: {}", age, adult); // Characters compare by code point. Every capital letter comes before every // lowercase one, so 'Z' sorts ahead of 'a'. let upper: char32 = 'Z'; let lower: char32 = 'a'; PrintLine("'{}' < '{}' is {}", upper, lower, upper < lower); // Floats are stored approximately, so a sum that looks exact on paper can // miss by a hair, and `==` sees the hair: this sum lands just above 0.3. Be // wary of exact `==` between floats that came out of arithmetic. let sum: float64 = 0.1 + 0.2; PrintLine("0.1 + 0.2 == 0.3 is {}", sum == 0.3); PrintLine("0.1 + 0.2 > 0.3 is {}", sum > 0.3); // Comparisons do not chain the way they do in maths. `1 < age < 30` would // compare `1 < age`, a `bool`, against 30, and the compiler rejects that. // Asking two questions at once needs `&&`, the subject of the next lesson. return 0; } ``` ## Run it ```sh cd Examples/Operators/Comparison rux run ``` ```text 17 == 5 is false 17 != 5 is true 17 < 5 is false 17 <= 5 is false 17 > 5 is true 17 >= 5 is true age 18 is adult: true 'Z' < 'a' is true 0.1 + 0.2 == 0.3 is false 0.1 + 0.2 > 0.3 is true ``` ## Common mistakes ::mistake **Chaining comparisons.**:br`1 < age < 30` fails with: ```text error: operator '<' cannot compare left operand 'bool8' with right operand 'int' ``` The left half is already a `bool`. Write `1 < age && age < 30`. :: ::mistake **Comparing an integer with a float.**:br When `age` is an `int32` and `limit` is a `float64`, `age > limit` fails with: ```text error: operator '>' cannot compare left operand 'int32' with right operand 'float64' ``` Convert one side with `as`. :: ::mistake **Comparing signed with unsigned.**:br An `int32` and a `uint32` are refused too, with this note: ```text note: the operands differ in signedness, so neither converts to the other's type ``` The compiler's help suggests converting one operand with `as`. :: ::mistake **Testing floats for exact equality.**:br`0.1 + 0.2 == 0.3` is `false`. Compare the difference against a small tolerance instead. :: ## Try it yourself 1. Compare `'a'` with `'b'`, and `'9'` with `'A'`. Print the code points with `as uint32` to see why. 2. Declare `let temperature: int32 = 21;` and a `bool` named `comfortable` that is `true` from 18 to 24. You will need `&&` from the next lesson. 3. Print `0.1 + 0.2 - 0.3` to see how far the sum misses. 4. Write `1 < age < 30` and read the error, then fix it. ## Learn more - [Comparison operations](https://rux-lang.dev/docs/lang/expressions/comparison) in the Rux Reference - [Logical](https://rux-lang.dev/docs/learn/logical) — combining several comparisons into one condition - [Equatable](https://rux-lang.dev/docs/learn/equatable) and [Comparable](https://rux-lang.dev/docs/learn/comparable) — making your own types comparable # Logical ::note **You'll need**: [Comparison](https://rux-lang.dev/docs/learn/comparison), [Boolean](https://rux-lang.dev/docs/learn/boolean) :: One comparison answers one question. Real conditions are rarely that simple: "it is raining **and** cold", "the user is an admin **or** the owner", "the file is **not** empty". The logical operators combine `bool` values into new ones, so several small questions become one answer. ## And, or, not ```rux let raining = true; let cold = false; PrintLine("raining && cold is {}", raining && cold); PrintLine("raining || cold is {}", raining || cold); PrintLine("!raining is {}", !raining); ``` `&&` (and) is `true` only when both sides are. `||` (or) is `true` when at least one side is. `!` (not) takes a single `bool` and flips it. Every combination fits in one table: | `a` | `b` | `a && b` | `a || b` | `!a` | | ------- | ------- | -------- | -------- | ------- | | `false` | `false` | `false` | `false` | `true` | | `false` | `true` | `false` | `true` | `true` | | `true` | `false` | `false` | `true` | `false` | | `true` | `true` | `true` | `true` | `false` | The operands must be `bool`s. Rux has no "truthy" numbers, so `items && true` with an `int32` `items` is an error — write the comparison you mean, `items != 0`. ## Short-circuiting The table has a pattern: once the left side of `&&` is `false`, the answer is `false` whatever the right side is. Once the left side of `||` is `true`, the answer is `true`. So both operators work out the left side first, and **skip the right side** when the left one has already settled the answer: ```mermaid flowchart LR and["`left && right`"] --> l1{"`left`?"} l1 -- "`false`" --> f["`false` —
`right` never runs"] l1 -- "`true`" --> r1["the answer is `right`"] or["`left || right`"] --> l2{"`left`?"} l2 -- "`true`" --> t["`true` —
`right` never runs"] l2 -- "`false`" --> r2["the answer is `right`"] ``` The program makes this visible with a small helper. `Side` is a *function* — a named piece of work, which [Part 4](https://rux-lang.dev/docs/learn/functions) teaches properly. For now, all you need to know is that calling it prints which side is being evaluated, then hands back the answer it was given: ```rux func Side(name: char8[..], answer: bool) -> bool { PrintLine(" evaluated {}", name); return answer; } ``` ```rux PrintLine("false && true:"); PrintLine(" result {}", Side("left", false) && Side("right", true)); ``` For `false && true` the output shows only `evaluated left`: the right side never ran. For `true && false` both sides run, because a `true` on the left does not decide an `&&`. ## A guard on the left Short-circuiting is not just a speed-up. It lets the left side **protect** the right one. Dividing an integer by zero stops the program, so the average below must not be computed when there are no items: ```rux let items: int32 = 0; let total: int32 = 120; PrintLine("average above 10: {}", items != 0 && total / items > 10); ``` `items != 0` is `false`, so `&&` already knows its answer and `total / items` is never reached. Put the guard first; written the other way round, the division would run before the check. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Operators/Logical){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // The logical operators combine bools. `a && b` is true when both are true, // `a || b` when at least one is, and `!a` flips a single bool. // // They also short-circuit: they evaluate the left side first, and skip the right // side when the left one has already settled the answer. `false && anything` is // false and `true || anything` is true, so in those cases the right side never // runs at all. import Io::PrintLine; // A preview of functions, which Part 4 teaches: calling `Side` prints which side // is being evaluated, then hands back the answer it was given unchanged. func Side(name: char8[..], answer: bool) -> bool { PrintLine(" evaluated {}", name); return answer; } func Main() -> int { let raining = true; let cold = false; PrintLine("raining && cold is {}", raining && cold); PrintLine("raining || cold is {}", raining || cold); PrintLine("!raining is {}", !raining); // Watch which sides get evaluated. The right side runs only when the left // one could not decide the answer alone. PrintLine("false && true:"); PrintLine(" result {}", Side("left", false) && Side("right", true)); PrintLine("true && false:"); PrintLine(" result {}", Side("left", true) && Side("right", false)); PrintLine("true || false:"); PrintLine(" result {}", Side("left", true) || Side("right", false)); PrintLine("false || true:"); PrintLine(" result {}", Side("left", false) || Side("right", true)); // This is what makes short-circuiting useful: the left side can guard the // right. An integer division by zero stops the program on the spot, with // "Panic: division by zero" and the line it happened on. With no items, the // guard settles the answer first and the division is never reached. let items: int32 = 0; let total: int32 = 120; PrintLine("average above 10: {}", items != 0 && total / items > 10); return 0; } ``` ## Run it ```sh cd Examples/Operators/Logical rux run ``` ```text raining && cold is false raining || cold is true !raining is false false && true: evaluated left result false true && false: evaluated left evaluated right result false true || false: evaluated left result true false || true: evaluated left evaluated right result true average above 10: false ``` ## Common mistakes ::mistake **Using a number as a condition.**:br`items && true` fails with: ```text error: operator '&&' requires a bool left operand, but found 'int32' ``` And `!items` fails with: ```text error: operator '!' requires a bool operand, but found 'int32' ``` Compare explicitly: `items != 0`. :: ::mistake **Writing `&` or `|` instead of `&&` or `||`.**:br The single-character forms compile on `bool`s, but they are the *bitwise* operators of [Bitwise](https://rux-lang.dev/docs/learn/bitwise), and they always evaluate both sides. Swap `&&` for `&` in the guard above and the program stops with: ```text Panic: division by zero ``` :: ::mistake **Putting the guard second.**:br`total / items > 10 && items != 0` divides before it checks. The guard only protects what comes after it. :: ## Try it yourself 1. Add `let windy = true;` and print whether it is raining and windy but not cold. 2. Swap the two `Side` calls in each pair and predict which lines of `evaluated` appear. 3. Set `items` to `8` and run again. Which part of the condition decides the answer now? 4. Write a `bool` named `weekend` that is `true` when an `int32` `day` is `6` or `7`. ## Learn more - [Logical operations](https://rux-lang.dev/docs/lang/expressions/logical) in the Rux Reference - [Precedence](https://rux-lang.dev/docs/learn/precedence) — how `&&`, `||` and `!` bind next to comparisons - [Bitwise](https://rux-lang.dev/docs/learn/bitwise) — `&`, `|` and `^` on the bits of integers # Assignment ::note **You'll need**: [Mutable](https://rux-lang.dev/docs/learn/mutable), [Arithmetic](https://rux-lang.dev/docs/learn/arithmetic) :: A running total, a countdown, a score: many variables change by building on their own current value. Writing `score = score + 5` works, but it names `score` twice and makes the reader check that both names really are the same. Rux, like most languages, has a shorter form for "change this variable by this much". ## Compound assignment `score += 5` means exactly `score = score + 5`. Every arithmetic operator has a compound form: ```rux var score: int32 = 10; PrintLine("start {}", score); score += 5; PrintLine("+= 5 {}", score); score -= 3; PrintLine("-= 3 {}", score); ``` | Short form | Means | `score` goes from 10 to | | ------------ | ------------------- | ----------------------- | | `score += 5` | `score = score + 5` | 15 | | `score -= 3` | `score = score - 3` | 7 | | `score *= 4` | `score = score * 4` | 40 | | `score /= 5` | `score = score / 5` | 2 | | `score %= 5` | `score = score % 5` | 0 | The program applies them one after another, so each line starts from the result of the one before: 10, 15, 12, 48, 9, 4. The bitwise operators of a later lesson have compound forms too. ## Stepping by one Adding or taking away exactly one is so common that it is shorter still. `score++` adds one, `score--` takes one away: ```rux score++; PrintLine("++ {}", score); score--; score--; PrintLine("-- twice {}", score); ``` These are the steps loops take on every pass, and you will see them throughout [Part 3](https://rux-lang.dev/docs/learn/control-flow). ## Floats too Compound assignment follows the rules of the operator inside it. On a `float64`, `/=` is float division, so it keeps the fraction, and `++` adds `1.0`: ```rux var price: float64 = 10.0; price /= 4.0; price++; PrintLine("price {}", price); ``` 10.0 / 4.0 is 2.5, plus one is 3.5. The two sides must still agree on type: `score += 1.5` on an `int32` is refused just as `score + 1.5` would be. ## Before or after On a line of its own, `count++` and `++count` do the same thing. Inside a larger expression, where you write the `++` decides which value the expression hands back: ```rux var count: int32 = 1; let before = count++; PrintLine("count++ gave {}, count is now {}", before, count); let after = ++count; PrintLine("++count gave {}, count is now {}", after, count); ``` ```mermaid flowchart LR post["`count++`"] --> p1["hands back the old value"] --> p2["then `count` is one higher"] pre["`++count`"] --> q1["`count` is one higher"] --> q2["hands back the new value"] ``` Either way the variable ends up one higher. Code that depends on the difference is easy to misread, so most Rux code keeps `++` and `--` on lines of their own. ## They all need a var Every one of these operators *writes* to the variable, so the variable must be declared with `var`, as in [Mutable](https://rux-lang.dev/docs/learn/mutable). On a `let` binding the compiler refuses them, just as it refuses a plain `=`. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Operators/Assignment){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // Changing a variable based on its own value is so common that it has a short // form. `score += 5` means `score = score + 5`, and every arithmetic operator // has one: `+=`, `-=`, `*=`, `/=` and `%=` (the bitwise operators of a later // lesson have them too). Stepping by exactly one is shorter still: `score++` // adds one and `score--` takes one away. // // All of these write to the variable, so they need a `var`. On a `let` binding // the compiler refuses them, just as it refuses a plain `=`. import Io::PrintLine; func Main() -> int { var score: int32 = 10; PrintLine("start {}", score); score += 5; PrintLine("+= 5 {}", score); score -= 3; PrintLine("-= 3 {}", score); score *= 4; PrintLine("*= 4 {}", score); score /= 5; PrintLine("/= 5 {}", score); score %= 5; PrintLine("%= 5 {}", score); score++; PrintLine("++ {}", score); score--; score--; PrintLine("-- twice {}", score); // They work on floats too. `/=` follows the type's own division, so here it // keeps the fraction. var price: float64 = 10.0; price /= 4.0; price++; PrintLine("price {}", price); // `++` can also stand inside a larger expression, and then where you write // it matters. After the variable, `count++` steps it and hands back the // value from before. Before the variable, `++count` steps it and hands back // the new value. Either way the variable ends up one higher. var count: int32 = 1; let before = count++; PrintLine("count++ gave {}, count is now {}", before, count); let after = ++count; PrintLine("++count gave {}, count is now {}", after, count); return 0; } ``` ## Run it ```sh cd Examples/Operators/Assignment rux run ``` ```text start 10 += 5 15 -= 3 12 *= 4 48 /= 5 9 %= 5 4 ++ 5 -- twice 3 price 3.5 count++ gave 1, count is now 2 ++count gave 3, count is now 3 ``` ## Common mistakes ::mistake **Updating a `let`.**:br`let score: int32 = 10;` followed by `score += 5;` or `score++;` fails with: ```text error: cannot modify immutable variable 'score' ``` The compiler's help says to declare `score` with `var`. :: ::mistake **Mixing types.**:br`score += 1.5` on an `int32` fails with: ```text error: operator '+=' cannot combine left operand 'int32' with right operand 'float64' ``` Compound assignment follows the same type rules as the operator inside it. :: ::mistake **Writing `=-` instead of `-=`.**:br`score =- 3;` is not a typo the compiler can catch: it reads as `score = -3`, which is valid, and `score` silently becomes `-3`. (`=+` is refused, because Rux has no unary `+`.) The operator always goes before the `=`. :: ## Try it yourself 1. Start a `var balance: int32 = 100;`, apply `-= 30`, `*= 2` and `%= 7`, and predict each step before you run. 2. Halve a `var temperature: float64 = 37.0;` with `/=` and print it. 3. Print `count++` and `++count` directly inside a `PrintLine`, and check the results against the diagram. 4. Change `var score` to `let score` and read every error the compiler reports. ## Learn more - [Assignment operators](https://rux-lang.dev/docs/lang/lexical/operators) in the Rux Reference - [`var`](https://rux-lang.dev/docs/lang/bindings/overview#var) and [mutability](https://rux-lang.dev/docs/lang/bindings/overview#mutability) - [Precedence](https://rux-lang.dev/docs/learn/precedence) — assignment is the loosest operator of all # Precedence ::note **You'll need**: [Arithmetic](https://rux-lang.dev/docs/learn/arithmetic), [Comparison](https://rux-lang.dev/docs/learn/comparison), [Logical](https://rux-lang.dev/docs/learn/logical), [Convert](https://rux-lang.dev/docs/learn/convert) :: `2 + 3 * 4` could mean 20 or 14, depending on which operator goes first. Maths settled this long ago — multiplication before addition — and Rux follows the same idea for every operator it has. The rules that decide the order are called **precedence**, and knowing the few that matter lets you read an expression the way the compiler does. ## The ranking From tightest to loosest, the operators of this part rank like this: | Rank | Operators | Kind | | -------- | --------------------- | ------------------ | | tightest | `x++` `x--` | step after reading | | | `-x` `!x` `++x` `--x` | unary | | | `as` | conversion | | | `*` `/` `%` | multiplication | | | `+` `-` | addition | | | `<` `<=` `>` `>=` | ordering | | | `==` `!=` | equality | | | `&&` | and | | | `||` | or | | loosest | `=` `+=` `-=` … | assignment | A tighter operator grabs its operands first. Parentheses override all of it. ```rux PrintLine("2 + 3 * 4 = {}", 2 + 3 * 4); PrintLine("(2 + 3) * 4 = {}", (2 + 3) * 4); ``` `*` ranks above `+`, so `3 * 4` happens first and the answer is 14. Wrap `2 + 3` in parentheses and it is 20. `%` ranks with `*`, not with `+`, so `7 + 10 % 4` is `7 + 2`, which is 9. ## Same rank, left to right When operators share a rank, they group from the left: ```rux PrintLine("100 / 10 / 5 = {}", 100 / 10 / 5); PrintLine("100 / (10 / 5) = {}", 100 / (10 / 5)); PrintLine("10 - 3 - 2 = {}", 10 - 3 - 2); ``` `100 / 10 / 5` is `(100 / 10) / 5`, which is 2. Grouping it the other way gives 50. For `+` and `*` the grouping never changes the answer, but for `-` and `/` it does. ## as converts only its neighbour `as` binds tighter than any arithmetic, so it converts the single operand right next to it — not the whole expression on its left: ```rux let a: int32 = 17; let b: int32 = 5; PrintLine("(a / b) as float64 = {}", (a / b) as float64); PrintLine("a as float64 / b as float64 = {}", a as float64 / b as float64); ``` The first line divides two integers, losing the fraction, and only then converts: `3.0`. The second converts each integer first and divides two floats: `3.4`. Here is how the compiler groups both: ```mermaid flowchart LR e1["`(a / b) as float64`"] --> d1["`a / b` = `3`
integer division"] --> c1["`3 as float64`
= `3.0`"] e2["`a as float64 / b as float64`"] --> c2["`17.0` and `5.0`
converted first"] --> d2["`17.0 / 5.0`
= `3.4`"] ``` Writing `a / b as float64` would convert only `b`, and then `/` would have an `int32` on one side and a `float64` on the other — which the compiler refuses. ## Conditions read naturally Arithmetic ranks above comparison, and comparison above `&&` and `||`. That order is chosen so that the usual conditions need no parentheses at all: ```rux let age: int32 = 25; PrintLine("age >= 18 && age < 65 is {}", age >= 18 && age < 65); ``` The comparisons are worked out first, then `&&` combines their answers. Between the two logical operators, `&&` binds tighter than `||`, the same way `*` binds tighter than `+`: ```rux PrintLine("true || false && false is {}", true || false && false); PrintLine("(true || false) && false is {}", (true || false) && false); ``` The first is `true || (false && false)`, which is `true`. And `!` applies only to the operand right next to it, so `!ready && busy` is `(!ready) && busy` — use parentheses, `!(ready && busy)`, to negate the whole thing. ## When in doubt, add parentheses Precedence decides what the compiler does; parentheses decide what the reader sees. `a * b + c` is clear to anyone, but `x || y && z` makes most people stop and think. Parentheses that match the default grouping change nothing in the program and save the next reader that pause. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Operators/Precedence){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // When an expression mixes operators, precedence decides which applies first, // the way multiplication comes before addition in maths. From tightest to // loosest, the operators seen so far rank like this: // // x++ x-- step after reading // -x !x ++x --x unary // as conversion // * / % multiplication // + - addition // < <= > >= ordering // == != equality // && and // || or // = += -= ... assignment, loosest of all // // Operators on the same rank group from left to right. Parentheses override // all of it, and are worth adding wherever a reader would have to stop and think. import Io::PrintLine; func Main() -> int { // Multiplication before addition, unless parentheses say otherwise. PrintLine("2 + 3 * 4 = {}", 2 + 3 * 4); PrintLine("(2 + 3) * 4 = {}", (2 + 3) * 4); // `%` ranks with `*`, not with `+`. PrintLine("7 + 10 % 4 = {}", 7 + 10 % 4); // Same rank, left to right: 100 / 10 first, then / 5. Grouping the other // way round gives a different answer. PrintLine("100 / 10 / 5 = {}", 100 / 10 / 5); PrintLine("100 / (10 / 5) = {}", 100 / (10 / 5)); PrintLine("10 - 3 - 2 = {}", 10 - 3 - 2); // `as` binds tighter than arithmetic, so it converts only its neighbour. // Converting the result of an integer division is too late: the fraction // was already gone. let a: int32 = 17; let b: int32 = 5; PrintLine("(a / b) as float64 = {}", (a / b) as float64); PrintLine("a as float64 / b as float64 = {}", a as float64 / b as float64); // Arithmetic happens before comparing, and comparing before `&&`, so a // range check needs no parentheses at all. let age: int32 = 25; PrintLine("age >= 18 && age < 65 is {}", age >= 18 && age < 65); // `&&` binds tighter than `||`, the same way `*` binds tighter than `+`. PrintLine("true || false && false is {}", true || false && false); PrintLine("(true || false) && false is {}", (true || false) && false); // `!` applies only to the operand right next to it. let ready = true; let busy = false; PrintLine("!ready && busy is {}", !ready && busy); PrintLine("!(ready && busy) is {}", !(ready && busy)); return 0; } ``` ## Run it ```sh cd Examples/Operators/Precedence rux run ``` ```text 2 + 3 * 4 = 14 (2 + 3) * 4 = 20 7 + 10 % 4 = 9 100 / 10 / 5 = 2 100 / (10 / 5) = 50 10 - 3 - 2 = 5 (a / b) as float64 = 3.0 a as float64 / b as float64 = 3.4 age >= 18 && age < 65 is true true || false && false is true (true || false) && false is false !ready && busy is false !(ready && busy) is true ``` ## Common mistakes ::mistake **Converting too late.**:br`(a / b) as float64` is `3.0`, not `3.4`: the integer division has already dropped the fraction. Convert each operand before dividing. :: ::mistake **Expecting `as` to cover the whole expression.**:br`a / b as float64` converts only `b`, and fails with: ```text error: operator '/' cannot combine left operand 'int32' with right operand 'float64' ``` :: ::mistake **Negating more than the next operand.**:br`!count == 0` is `(!count) == 0`, and when `count` is an `int32` it fails with: ```text error: operator '!' requires a bool operand, but found 'int32' ``` Write `count != 0`, or wrap what you mean in parentheses. :: ## Try it yourself 1. Predict, then print, `2 * 3 + 4 * 5`, `20 - 4 - 6` and `8 / 2 * 4`. 2. Add parentheses to `true || false && false` that do not change its value, and then some that do. 3. Write the condition "age is under 13 or over 65, and has a ticket" with an `int32` `age` and a `bool` `ticket`. Which parentheses are required? ## Learn more - [Operator precedence](https://rux-lang.dev/docs/lang/lexical/operators) in the Rux Reference - [Arithmetic](https://rux-lang.dev/docs/learn/arithmetic), [Comparison](https://rux-lang.dev/docs/learn/comparison) and [Logical](https://rux-lang.dev/docs/learn/logical) — the operators being ranked - [Ternary](https://rux-lang.dev/docs/learn/ternary) — the conditional operator, which ranks just above assignment # Part 3: Control flow So far every program has run each line once, top to bottom. This part makes programs **choose** — run one block or another depending on a condition — and **repeat** — run a block again and again until the job is done. With these two abilities and the operators of Part 2, you can write real little programs: the part ends with the first checkpoint projects. ## What you will learn - Choosing with `if`, `else` and `else if` chains, and why the order of a chain matters. - Choosing a value inside an expression with the conditional `? :`. - Repeating with `while`, `do`-`while` and `loop`, and where each one tests its condition. - Leaving a loop early with `break` and skipping a pass with `continue`, including from nested loops with labels. - Describing a run of numbers with ranges `..` and `..=`, and walking one with `for`. - Selecting a branch by value with `match`, and using `match` as an expression that produces a value. ## Choosing and repeating ```mermaid flowchart LR cf(["Control flow"]) --> choose["Choose"] cf --> repeat["Repeat"] choose --> by_cond["by condition
`if` · `else if` · `? :`"] choose --> by_value["by value
`match` · `match` expression"] repeat --> by_test["while a condition holds
`while` · `do-while` · `loop`"] repeat --> by_range["over a range
`..` · `..=` · `for`"] by_test --> jump["leave or skip
`break` · `continue` · labels"] by_range --> jump ``` ## Lessons | | Lesson | What you will learn | | ---- | -------------------------------------------------------------------- | ---------------------------------------------------------------- | | 3.1 | [If](https://rux-lang.dev/docs/learn/if) | run code only when a condition holds, with `if` and `else` | | 3.2 | [Else if](https://rux-lang.dev/docs/learn/else-if) | choose one of several branches with an `else if` chain | | 3.3 | [Ternary](https://rux-lang.dev/docs/learn/ternary) | pick one of two values inside an expression with `? :` | | 3.4 | [While](https://rux-lang.dev/docs/learn/while) | repeat while a condition holds — possibly zero times | | 3.5 | [Do-while](https://rux-lang.dev/docs/learn/do-while) | run the body first and test afterwards, so it runs at least once | | 3.6 | [Loop](https://rux-lang.dev/docs/learn/loop) | repeat forever with `loop` until a `break` leaves | | 3.7 | [Break](https://rux-lang.dev/docs/learn/break) | leave a loop early when the answer is found | | 3.8 | [Continue](https://rux-lang.dev/docs/learn/continue) | skip the rest of one iteration and carry on with the next | | 3.9 | [Range](https://rux-lang.dev/docs/learn/range) | describe a run of numbers with `..` and `..=` | | 3.10 | [For](https://rux-lang.dev/docs/learn/for) | walk a range with `for` | | 3.11 | [Label](https://rux-lang.dev/docs/learn/label) | name a loop, so `break` can leave an outer one | | 3.12 | [Match](https://rux-lang.dev/docs/learn/match) | select a branch by value with `match`, and default with `else` | | 3.13 | [Match expression](https://rux-lang.dev/docs/learn/match-expression) | use `match` as a value, not only as a statement | ## Before you start Finish [Part 1: Basics](https://rux-lang.dev/docs/learn/basics) and [Part 2: Operators](https://rux-lang.dev/docs/learn/operators) first — every condition in this part is a comparison or a logical expression from Part 2. Each lesson's package is in the Examples repository's `ControlFlow/` folder: ```sh cd Examples/ControlFlow/If rux run ``` ## After this part You are ready for the first checkpoint projects: [Thanks](https://rux-lang.dev/docs/learn/thanks), which prints a banner using loops and `match` expressions, and [FizzBuzz](https://rux-lang.dev/docs/learn/fizz-buzz), the classic test of getting an `else if` chain in the right order. Then [Part 4: Functions](https://rux-lang.dev/docs/learn/functions) gives a piece of work a name, so you can reuse it instead of repeating it. For the full rules behind this part, see [Statements](https://rux-lang.dev/docs/lang/statements/overview) — [`if`](https://rux-lang.dev/docs/lang/statements/if), [`match`](https://rux-lang.dev/docs/lang/patterns/match), [`while`](https://rux-lang.dev/docs/lang/statements/loops#while), [`for`](https://rux-lang.dev/docs/lang/statements/loops#for), [`loop`](https://rux-lang.dev/docs/lang/statements/loops#loop) and [`break` / `continue`](https://rux-lang.dev/docs/lang/statements/break-continue) — and [Ranges](https://rux-lang.dev/docs/lang/ranges/overview) in the Rux Reference. # If ::note **You'll need**: [Comparison](https://rux-lang.dev/docs/learn/comparison), [Logical](https://rux-lang.dev/docs/learn/logical) :: Until now, every program has run every line, top to bottom, every time. Real programs react: they print a warning only when something is wrong, charge a fee only when it applies, take a different path when the input is different. `if` is the simplest way to make that choice — run a block of code only when a condition holds. ## Run a block, or skip it An `if` is the keyword, a condition, and a block in braces: ```rux let temperature: int32 = 18; if temperature > 15 { PrintLine("warm enough for a walk"); } if temperature > 25 { PrintLine("hot enough for a swim"); } ``` 18 is above 15, so the first block runs. It is not above 25, so the second block is skipped. Either way, the program carries on with whatever comes after the closing brace. ## Parentheses optional, braces required Parentheses around the condition are allowed but never needed: ```rux if (temperature < 20) { PrintLine("bring a jacket"); } ``` The braces are the opposite: always needed, even around a single statement. `if ready PrintLine("go");` is an error. Because the braces are always there, there is never any doubt about which lines belong to the `if`. ## else: one of two Add `else`, and exactly one of two blocks runs — the first when the condition holds, the second when it does not: ```rux let raining = true; if raining { PrintLine("take an umbrella"); } else { PrintLine("leave the umbrella at home"); } ``` ```mermaid flowchart LR c{"`raining`?"} -- "`true`" --> a["`take an umbrella`"] c -- "`false`" --> b["`leave the umbrella at home`"] a --> next["the next statement"] b --> next ``` The two paths always meet again after the `if`. There is no way for both blocks to run, and no way for neither to. ## The condition is a bool A condition must be a `bool`: a comparison, a logical expression from [Logical](https://rux-lang.dev/docs/learn/logical), or a `bool` variable. Anything that produces a `bool` will do: ```rux let windy = true; if raining && !windy { PrintLine("the umbrella will do"); } else { PrintLine("wear a hood instead"); } ``` Rux has no "truthy" numbers, so a number is not a shortcut for "not zero". `if count { }` is refused; write the comparison you mean, `if count != 0 { }`. ## Blocks and the variables around them A block may read and change variables declared before it: ```rux var budget: int32 = 12; let price: int32 = 9; if price <= budget { budget -= price; PrintLine("bought it, {} left", budget); } else { PrintLine("cannot afford it"); } ``` `budget` lives outside the `if`, so the change survives after the closing brace. A variable declared *inside* a block is different: it belongs to the block, and it is gone once the block ends. To use a value after the `if`, declare its variable before it. `if` decides while the program runs. Rux also has `when`, which decides while the program is being compiled — that one comes much later, in [When](https://rux-lang.dev/docs/learn/when). ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/ControlFlow/If){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // `if` runs a block only when its condition is true. Add `else`, and exactly one of two blocks // runs: the first when the condition holds, the second when it does not. // // The condition must be a `bool`: a comparison, a logical expression, or a `bool` binding. Rux has // no "truthy" numbers, so a number is not a shortcut for "not zero": // // if count { } // error: condition for 'if' must have type 'bool', but found 'int' // // Write the comparison you mean instead, `if count != 0 { }`. // // `if` decides while the program runs. Rux also has `when`, which decides while the program is // being compiled; that one comes much later, in the When lesson. import Io::PrintLine; func Main() -> int { let temperature: int32 = 18; // Without `else`, the block either runs or is skipped, and the program carries on after it. if temperature > 15 { PrintLine("warm enough for a walk"); } if temperature > 25 { PrintLine("hot enough for a swim"); } // Parentheses around the condition are allowed but never needed. The braces are always // needed, even around a single statement: `if ready PrintLine("go");` is an error. if (temperature < 20) { PrintLine("bring a jacket"); } // With `else`, one of the two blocks always runs. let raining = true; if raining { PrintLine("take an umbrella"); } else { PrintLine("leave the umbrella at home"); } // Any `bool` expression is a condition, including ones built with `&&`, `||` and `!`. let windy = true; if raining && !windy { PrintLine("the umbrella will do"); } else { PrintLine("wear a hood instead"); } // A block may change variables declared before it. A binding declared inside the block, // though, belongs to the block and is gone after its closing brace. var budget: int32 = 12; let price: int32 = 9; if price <= budget { budget -= price; PrintLine("bought it, {} left", budget); } else { PrintLine("cannot afford it"); } return 0; } ``` ## Run it ```sh cd Examples/ControlFlow/If rux run ``` ```text warm enough for a walk bring a jacket take an umbrella wear a hood instead bought it, 3 left ``` ## Common mistakes ::mistake **Using a number as a condition.**:br`if count { }` fails with: ```text error: condition for 'if' must have type 'bool', but found 'int' ``` Write the test you mean: `if count != 0 { }`. :: ::mistake **Leaving out the braces.**:br`if ready PrintLine("go");` fails with: ```text error: expected '{' to start the 'if' body before 'PrintLine' ``` Every `if` and `else` body is a block in braces. :: ::mistake **Using a block's variable after the block.**:br A `let change = 10 - price;` declared inside the `if` cannot be printed after it: ```text error: name 'change' is not defined in this scope ``` Declare the variable before the `if` — a `var`, if each branch assigns it. :: ::mistake **Writing `=` for `==`.**:br`if age = 18 { }` is an assignment, not a question, and it is refused with: ```text error: condition for 'if' must have type 'bool', … ``` Comparison takes two equals signs. :: ## Try it yourself 1. Change `temperature` to `30`, then to `10`, and predict which lines print each time. 2. Add an `if` that prints `"freezing"` when the temperature is below 0. 3. Make the shop example buy two items in a row, each with its own `if`, and print what is left. 4. Write `if raining { … } else { … }` using `!raining` instead, with the blocks swapped. Does the output change? ## Learn more - [`if` / `else`](https://rux-lang.dev/docs/lang/statements/if) in the Rux Reference - [Else if](https://rux-lang.dev/docs/learn/else-if) — choosing among more than two cases - [Ternary](https://rux-lang.dev/docs/learn/ternary) — choosing between two *values* inside an expression # Else if ::note **You'll need**: [If](https://rux-lang.dev/docs/learn/if) :: `if` and `else` choose between two paths. Many decisions have more than two: a grade is an A, a B, a C or a fail; a temperature is a heat warning, a frost warning or nothing at all. `else if` adds another condition to an `if`, and a chain of them chooses among as many cases as you need. ## A chain of conditions ```rux let score: int32 = 85; if score >= 90 { PrintLine("{} earns an A", score); } else if score >= 80 { PrintLine("{} earns a B", score); } else if score >= 70 { PrintLine("{} earns a C", score); } else { PrintLine("{} needs another try", score); } ``` The chain tests its conditions from the top, runs the block of the **first** one that holds, and skips everything after it. A final plain `else` catches whatever no condition matched. So at most one block in a chain runs — exactly one, when the chain ends with `else`. ```mermaid flowchart LR s(["`score = 85`"]) --> a{"`score >= 90?`"} a -- "yes" --> A["an A"] a -- "no" --> b{"`score >= 80?`"} b -- "yes" --> B["a B"] b -- "no" --> c{"`score >= 70?`"} c -- "yes" --> C["a C"] c -- "no" --> E["another try"] ``` 85 fails the first test and passes the second, so the chain prints `85 earns a B` and never looks at `>= 70`. ## Each test may assume the ones above it failed By the time the chain reaches `score >= 80`, the score is already known to be below 90 — otherwise the first block would have run. So the chain needs no `score >= 80 && score < 90`. Each condition only has to draw the next line, not repeat the ones above it. ## Order is part of the meaning Because the first match wins, the order of a chain changes what it does. Here are the same conditions, loosest first: ```rux if score >= 70 { PrintLine("reordered chain: a C"); } else if score >= 80 { PrintLine("reordered chain: a B"); } else if score >= 90 { PrintLine("reordered chain: an A"); } ``` 85 is also at least 70, so the first test already holds and the chain stops there. Worse, the `>= 80` and `>= 90` blocks can now never run for *anyone*: every score that would reach them has already been caught by `>= 70`. The compiler cannot tell this from a deliberate choice, so it is up to you. A good rule for ranges like these: test the narrowest case first. ## A chain may run nothing Without a final `else`, it is possible for no condition to hold: ```rux let temperature: int32 = 18; if temperature > 30 { PrintLine("heat warning"); } else if temperature < 0 { PrintLine("frost warning"); } PrintLine("{} degrees needs no warning", temperature); ``` Leave out the `else` only when "nothing happens" is a real answer, as it is here. ## A chain, or separate ifs? A chain and a row of separate `if` statements look alike but behave differently: | Shape | Tests | Blocks that run | | ------------------------------ | ------------------------------------ | -------------------------- | | `if … else if … else if …` | until the first condition that holds | at most one | | `if …` then `if …` then `if …` | every condition, every time | every one whose test holds | ```rux if temperature > 10 { PrintLine("above 10"); } if temperature > 15 { PrintLine("above 15"); } ``` Both of these print, because they are two separate statements. Written as a chain, only `above 10` would. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/ControlFlow/ElseIf){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // `else if` adds another condition to an `if`, and a chain of them chooses among many cases. The // chain tests its conditions from the top, runs the block of the first one that holds, and skips // everything after it. So at most one block in a chain runs, and a final plain `else` catches // whatever no condition matched. // // Because the first match wins, the order of a chain is part of its meaning. The two chains below // test the same score with the same conditions, in different orders, and disagree. import Io::PrintLine; func Main() -> int { let score: int32 = 85; // Each test may assume the ones above it failed: by the `>= 80` line, the score is known to be // below 90, so the chain needs no `score >= 80 && score < 90`. if score >= 90 { PrintLine("{} earns an A", score); } else if score >= 80 { PrintLine("{} earns a B", score); } else if score >= 70 { PrintLine("{} earns a C", score); } else { PrintLine("{} needs another try", score); } // The same conditions, loosest first. 85 is also at least 70, so the first test already // holds, the chain stops there, and the `>= 80` and `>= 90` blocks can never run for anyone. if score >= 70 { PrintLine("reordered chain: a C"); } else if score >= 80 { PrintLine("reordered chain: a B"); } else if score >= 90 { PrintLine("reordered chain: an A"); } // Without a final `else`, a chain may run nothing at all. let temperature: int32 = 18; if temperature > 30 { PrintLine("heat warning"); } else if temperature < 0 { PrintLine("frost warning"); } PrintLine("{} degrees needs no warning", temperature); // Compare a chain with separate `if` statements: separate statements test every condition, // and each one that holds runs. Both of these print, where a chain would print only the first. if temperature > 10 { PrintLine("above 10"); } if temperature > 15 { PrintLine("above 15"); } return 0; } ``` ## Run it ```sh cd Examples/ControlFlow/ElseIf rux run ``` ```text 85 earns a B reordered chain: a C 18 degrees needs no warning above 10 above 15 ``` ## Common mistakes ::mistake **Testing the loosest case first.**:br With `score >= 70` at the top, every passing score stops there, and the A and B blocks become unreachable. The compiler does not warn about it — the program simply gives the wrong answer. Put the narrowest condition first. :: ::mistake **Using separate `if`s where only one case should win.**:br Two separate `if` statements both run when both conditions hold. When the cases are meant to exclude each other, join them with `else if`. :: ## Try it yourself 1. Change `score` to `95`, `72` and `40` and predict each line before you run. 2. Add an `A+` grade for scores of 97 and above. Where in the chain does it have to go? 3. Rewrite the temperature check so it prints `"mild"` when there is no warning, using a final `else`. 4. Turn the two separate `if`s at the end into one chain, and check that only one line prints. ## Learn more - [`if` / `else`](https://rux-lang.dev/docs/lang/statements/if) in the Rux Reference - [Match](https://rux-lang.dev/docs/learn/match) — a tidier chain when every test compares one value with `==` - [If](https://rux-lang.dev/docs/learn/if) — the two-way choice this lesson extends # Ternary ::note **You'll need**: [If](https://rux-lang.dev/docs/learn/if) :: `if` chooses which *statements* run. Sometimes the choice is smaller than that: you only need one of two *values*, right in the middle of an expression — "even" or "odd", the larger of two numbers, an `s` for a plural or nothing. The conditional operator makes that choice without leaving the expression. It is often called the *ternary* operator, because it is the only operator with three operands. ## condition ? whenTrue : whenFalse The condition comes first, then `?`, the value for `true`, `:`, and the value for `false`: ```rux let label = n % 2 == 0 ? "even" : "odd"; ``` With `n` at 7, `n % 2 == 0` is `false`, so `label` becomes `"odd"`. Only the chosen side is evaluated; the other is skipped, just as an untaken `if` block is. ## Why not just use if? Here is the same choice written with `if`: ```rux var labelTheLongWay = ""; if n % 2 == 0 { labelTheLongWay = "even"; } else { labelTheLongWay = "odd"; } ``` It works, but the binding has to be declared first with a placeholder value and filled in later, in whichever branch runs — so it must be a `var`. The conditional gives the binding its value where it is declared, so it can be a `let`. That is the real gain, more than the shorter line: a `let` cannot be changed by accident later on. ## A value goes anywhere Because the whole conditional is a value, it can be passed straight to a call: ```rux PrintLine("the larger of {} and {} is {}", a, b, a > b ? a : b); ``` ```rux PrintLine("{} item{}", count, count == 1 ? "" : "s"); ``` or used inside arithmetic: ```rux let total = price - (member ? 5 : 0); ``` The parentheses matter in that last line. The conditional ranks below arithmetic, just above assignment, so without them `price - member` would be worked out first — and an `int32` minus a `bool` makes no sense. When a conditional sits inside a larger expression, wrap it. ## One value, one type The conditional produces one value, so both sides must have the same type. `ready ? "yes" : 0` is refused, because one side is text and the other a number: ```mermaid flowchart LR c{"`condition`"} -- "`true`" --> t["`whenTrue`"] c -- "`false`" --> f["`whenFalse`"] t --> v["one value,
one type"] f --> v ``` ## Chains of conditionals A conditional may take the place of the false side of another. It reads as a list of cases tested from the left: ```rux let sign = n < 0 ? "negative" : n == 0 ? "zero" : "positive"; ``` `n < 0` is tested first; if it fails, `n == 0`; if that fails too, the answer is `"positive"`. Two or three cases read well like this. Past that, an [`else if` chain](https://rux-lang.dev/docs/learn/else-if) — or a [`match` expression](https://rux-lang.dev/docs/learn/match-expression) — is clearer. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/ControlFlow/Ternary){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // `if` chooses which statements run. Sometimes the choice is smaller than that: one of two // *values*, in the middle of an expression. `condition ? whenTrue : whenFalse` makes that choice. // It is an expression, so it goes anywhere a value goes. // // The whole conditional is one value with one type, so both sides must have the same type: // // let answer = ready ? "yes" : 0; // error: conditional branch type mismatch: expected 'char8[..]', found 'int' // help: make both branches produce the same type // // Give both sides text, or both numbers. import Io::PrintLine; func Main() -> int { let n: int32 = 7; // Written with `if`, choosing a label needs a `var`: the binding is declared first and given // its value later, in whichever branch runs. var labelTheLongWay = ""; if n % 2 == 0 { labelTheLongWay = "even"; } else { labelTheLongWay = "odd"; } // Written as a conditional, the binding gets its value where it is declared, so it can be a // `let`. That is the real gain, more than the shorter line. let label = n % 2 == 0 ? "even" : "odd"; PrintLine("{} is {} ({} the long way)", n, label, labelTheLongWay); // Being a value, it can be passed straight to a call or used inside arithmetic. let a: int32 = 3; let b: int32 = 5; PrintLine("the larger of {} and {} is {}", a, b, a > b ? a : b); let count: int32 = 3; PrintLine("{} item{}", count, count == 1 ? "" : "s"); let price: int32 = 40; let member = true; let total = price - (member ? 5 : 0); PrintLine("members pay {}", total); // A conditional may take the place of the false side of another, which reads as a list of // cases tested from the left. Past two or three cases, an `else if` chain is clearer. let sign = n < 0 ? "negative" : n == 0 ? "zero" : "positive"; PrintLine("{} is {}", n, sign); return 0; } ``` ## Run it ```sh cd Examples/ControlFlow/Ternary rux run ``` ```text 7 is odd (odd the long way) the larger of 3 and 5 is 5 3 items members pay 35 7 is positive ``` ## Common mistakes ::mistake **Giving the two sides different types.**:br`let answer = ready ? "yes" : 0;` fails with: ```text error: conditional branch type mismatch: expected 'char8[..]', found 'int' ``` The help says to make both branches produce the same type. :: ::mistake **Forgetting the parentheses inside arithmetic.**:br`price - member ? 5 : 0` is read as `(price - member) ? 5 : 0`, and fails with: ```text error: operator '-' cannot combine left operand 'int32' with right operand 'bool8' ``` Write `price - (member ? 5 : 0)`. :: ::mistake **Using a number as the condition.**:br`n % 2 ? "odd" : "even"` fails with: ```text error: condition for '?:' must have type 'bool', but found 'int32' ``` As with `if`, write the comparison: `n % 2 != 0`. :: ## Try it yourself 1. Print `"pass"` or `"fail"` for a `score` depending on whether it is at least 50. 2. Use a conditional to print the smaller of `a` and `b`. 3. Set `count` to `1` and check that the plural `s` disappears. 4. Extend `sign` so that numbers above 100 print `"large"`. Is it still easy to read? ## Learn more - [Precedence](https://rux-lang.dev/docs/learn/precedence) — the order in which operators apply - [If](https://rux-lang.dev/docs/learn/if) — choosing between blocks of statements - [Match expression](https://rux-lang.dev/docs/learn/match-expression) — choosing a value from many cases # While ::note **You'll need**: [If](https://rux-lang.dev/docs/learn/if), [Assignment](https://rux-lang.dev/docs/learn/assignment) :: Computers are good at doing the same thing many times without getting bored. A *loop* runs a block of code again and again, and `while` is the most basic one: it repeats its block for as long as a condition holds. Everything else in this part about repeating — `do`-`while`, `loop`, `for` — is a variation on it. ## Test, run, repeat A `while` looks like an `if`: the keyword, a condition, and a block. The difference is what happens at the closing brace. An `if` carries on; a `while` goes back and tests its condition again. ```rux var count: int32 = 3; while count > 0 { PrintLine("{}...", count); count -= 1; } PrintLine("liftoff"); ``` ```mermaid flowchart LR start(["`count = 3`"]) --> test{"`count > 0?`"} test -- "`true`" --> body["print `count`
`count -= 1`"] body --> test test -- "`false`" --> after["`liftoff`"] ``` The condition is tested before every pass, the first one included. It holds for 3, 2 and 1; after the third pass `count` is 0, the test fails, and the program carries on after the loop. ## Something must change A `while` ends only when something inside it makes the condition false. That is usually a `var` the condition reads, changed on every pass — here, `count -= 1`. Leave that line out and `count` stays at 3 forever: the program prints `3...` again and again and never reaches `liftoff`. If that happens to you, press **Ctrl+C** to stop it. Most loops need two things: a variable that says where the loop has got to, and often another that carries the result. Adding up 1 + 2 + … + 10 uses both: ```rux var n: int32 = 1; var sum: int32 = 0; while n <= 10 { sum += n; n += 1; } PrintLine("1 + 2 + ... + 10 = {}", sum); ``` ## When the number of passes is unknown `while` suits a loop whose number of passes you cannot know in advance. How many doublings take 1 past 1000? The loop finds out by doing them: ```rux var value: int32 = 1; var doublings: int32 = 0; while value <= 1000 { value *= 2; doublings += 1; } PrintLine("{} doublings reach {}", doublings, value); ``` The condition describes when to *keep going*, and the loop counts how many passes it took: 10 doublings reach 1024. ## Zero passes is possible Because the test comes first, a loop whose condition starts out false never runs its body at all: ```rux var fuel: int32 = 0; while fuel > 0 { PrintLine("driving"); fuel -= 1; } ``` That is usually exactly right — with an empty tank there is nothing to drive. When the body must run at least once, the [next lesson](https://rux-lang.dev/docs/learn/do-while) has the loop for it. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/ControlFlow/While){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // `while` repeats a block for as long as its condition holds. The condition is tested before // every pass, the first one included, so a loop whose condition starts out false runs zero times. // // The loop ends only when something inside it makes the condition false. That is usually a `var` // the condition reads, changed on every pass. Forget the change (`count -= 1` below) and the // condition never becomes false: the program repeats the same pass forever. import Io::PrintLine; func Main() -> int { // A countdown: the condition reads `count`, and the body brings it one step closer to 0. var count: int32 = 3; while count > 0 { PrintLine("{}...", count); count -= 1; } PrintLine("liftoff"); // Adding up 1 + 2 + ... + 10. One variable says where the loop is, another carries the result. var n: int32 = 1; var sum: int32 = 0; while n <= 10 { sum += n; n += 1; } PrintLine("1 + 2 + ... + 10 = {}", sum); // `while` suits loops whose number of passes is not known in advance. How many doublings take // 1 past 1000? The loop finds out by doing them. var value: int32 = 1; var doublings: int32 = 0; while value <= 1000 { value *= 2; doublings += 1; } PrintLine("{} doublings reach {}", doublings, value); // Here the condition is false before the first pass, so the body never runs. var fuel: int32 = 0; while fuel > 0 { PrintLine("driving"); fuel -= 1; } PrintLine("the tank was empty, so the loop ran zero times"); return 0; } ``` ## Run it ```sh cd Examples/ControlFlow/While rux run ``` ```text 3... 2... 1... liftoff 1 + 2 + ... + 10 = 55 10 doublings reach 1024 the tank was empty, so the loop ran zero times ``` ## Common mistakes ::mistake **Forgetting to change the condition's variable.**:br Without `count -= 1`, the loop's condition never becomes false and the program runs forever. Nothing warns you: it compiles cleanly. Check that every pass moves the loop towards its end. :: ::mistake **Off by one.**:br`while n < 10` stops before adding 10; `while n <= 10` includes it. When a loop gives an answer that is slightly wrong, check the comparison in its condition first. :: ::mistake **Using a number as the condition.**:br`while count { }` fails with: ```text error: condition for 'while' must have type 'bool', but found 'int32' ``` Write `while count != 0`. :: ## Try it yourself 1. Make the countdown start from 10 and print `liftoff` at the end. 2. Add up only the even numbers from 2 to 20 by stepping `n` by 2. 3. Find how many times 1,000,000 can be halved with `/= 2` before it reaches 0. 4. Change `while n <= 10` to `while n < 10` and explain the new sum. ## Learn more - [`while`](https://rux-lang.dev/docs/lang/statements/loops#while) in the Rux Reference - [Do-while](https://rux-lang.dev/docs/learn/do-while) — test at the bottom, so the body runs at least once - [For](https://rux-lang.dev/docs/learn/for) — the loop that handles its own counter # Do-while ::note **You'll need**: [While](https://rux-lang.dev/docs/learn/while) :: A `while` loop tests first and runs second, so it may run zero times. Some jobs need the opposite order: do the work once, then decide whether to do it again. Asking a user for input until it is valid is one — you cannot check an answer before you have asked. `do`-`while` puts the test at the bottom, so the body always runs at least once. ## The test at the bottom ```rux do { doPasses += 1; } while doPasses > 5; ``` The body comes first, after `do`. The condition comes last, after `while`, and the whole statement ends with a semicolon. Apart from where the test sits, it behaves like a `while`: after each pass the condition is tested, and the loop repeats while it holds. ```mermaid flowchart LR w(["`while`"]) --> wt{"test"} wt -- "`true`" --> wb["body"] wb --> wt wt -- "`false`" --> wa["after the loop"] d(["`do-while`"]) --> db["body"] db --> dt{"test"} dt -- "`true`" --> db dt -- "`false`" --> da["after the loop"] ``` ## The same false condition, both ways The program runs both loops with a condition that is false from the start: ```rux var whilePasses: int32 = 0; while whilePasses > 5 { whilePasses += 1; } var doPasses: int32 = 0; do { doPasses += 1; } while doPasses > 5; PrintLine("while ran {} times, do-while ran {} time", whilePasses, doPasses); ``` `while` never runs its body, and `do`-`while` runs it once. That guarantee is the only difference between them, and the reason to choose one over the other. ## Where the guarantee matters Counting the digits of a number is a natural fit: divide by 10 until nothing is left, counting as you go. ```rux var number: int32 = 4096; var digits: int32 = 0; do { digits += 1; number /= 10; } while number != 0; PrintLine("4096 has {} digits", digits); ``` 4096 becomes 409, 40, 4 and 0 — four passes, four digits. Now consider 0. It has one digit, but it is already `0` before the first pass. The `do`-`while` runs once anyway and gets the right answer, `1`. The same loop written with `while` tests `number != 0` first, never runs, and reports that 0 has no digits at all: ```rux while number != 0 { digits += 1; number /= 10; } ``` | Number | `do`-`while` says | `while` says | | ------ | ----------------- | ------------ | | 4096 | 4 digits | 4 digits | | 0 | 1 digit | 0 digits | Both are correct for every other number. Edge cases like 0 are where the choice of loop shows. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/ControlFlow/DoWhile){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // `do { ... } while condition;` runs its body first and tests the condition afterwards. So the // body always runs at least once, even when the condition is false from the start. That // guarantee is the only difference from `while`, and the reason to choose one over the other. // // The test sits at the end, so the statement ends with a semicolon after the condition. Leave it // out and the compiler stops at whatever comes next: // // error: expected ';' after the 'do while' condition before 'PrintLine' import Io::PrintLine; func Main() -> int { // The same false condition, both ways round: `while` never runs its body, `do` runs it once. var whilePasses: int32 = 0; while whilePasses > 5 { whilePasses += 1; } var doPasses: int32 = 0; do { doPasses += 1; } while doPasses > 5; PrintLine("while ran {} times, do-while ran {} time", whilePasses, doPasses); // Where the guarantee matters: counting the digits of a number by dividing by 10 until // nothing is left. Every number has at least one digit, and 0 is the case that shows it. var number: int32 = 4096; var digits: int32 = 0; do { digits += 1; number /= 10; } while number != 0; PrintLine("4096 has {} digits", digits); number = 0; digits = 0; do { digits += 1; number /= 10; } while number != 0; PrintLine("0 has {} digit", digits); // Written with `while`, the same loop never runs for 0 and reports no digits at all. number = 0; digits = 0; while number != 0 { digits += 1; number /= 10; } PrintLine("the while version says 0 has {} digits", digits); return 0; } ``` ## Run it ```sh cd Examples/ControlFlow/DoWhile rux run ``` ```text while ran 0 times, do-while ran 1 time 4096 has 4 digits 0 has 1 digit the while version says 0 has 0 digits ``` ## Common mistakes ::mistake **Forgetting the semicolon after the condition.**:br`do { … } while number != 0` must end with `;`. Without it the compiler stops at whatever comes next: ```text error: expected ';' after the 'do while' condition before 'PrintLine' ``` :: ::mistake **Choosing `do`-`while` when zero passes is a valid answer.**:br If the body must not run for some starting values — an empty list, a balance of 0 — the guarantee of one pass is a bug, not a feature. Use `while` there. :: ## Try it yourself 1. Count the digits of `7`, `10` and `1000000` with the `do`-`while` loop. 2. Change the digit counter to add up the digits instead (`number % 10` is the last digit). What does `4096` give? 3. Write a `do`-`while` that doubles a `var value: int32 = 1;` until it passes 100, and print how many passes it took. ## Learn more - [`while`](https://rux-lang.dev/docs/lang/statements/loops#while) in the Rux Reference - [While](https://rux-lang.dev/docs/learn/while) — the loop that tests first - [Loop](https://rux-lang.dev/docs/learn/loop) — for a loop whose exit belongs in the middle # Loop ::note **You'll need**: [While](https://rux-lang.dev/docs/learn/while), [Do-while](https://rux-lang.dev/docs/learn/do-while) :: `while` tests at the top of each pass, and `do`-`while` at the bottom. Some loops want the test in the **middle**: there is work to do before the question can be asked, and different work after it. `loop` is the keyword for that — a loop with no condition at all, whose way out is a `break` written wherever it belongs. ## A loop with no condition ```rux loop { total += odd; if total > 50 { break; } odd += 2; } ``` On its own, `loop { … }` would repeat forever. The `break` inside is what ends it: it leaves the loop at once, and the program carries on with the statement after the closing brace. The [next lesson](https://rux-lang.dev/docs/learn/break) looks at `break` in every kind of loop; here it is simply the way out. ## The exit in the middle The Collatz sequence is a good example of a loop that wants its test in the middle. Start from a number; halve it if it is even, triple it and add one if it is odd; stop on reaching 1. The program prints the whole sequence with arrows between the numbers: ```rux var n: int32 = 6; var steps: int32 = 0; loop { Print("{}", n); if n == 1 { break; } Print(" -> "); if n % 2 == 0 { n /= 2; } else { n = 3 * n + 1; } steps += 1; } ``` ```mermaid flowchart LR top(["`loop`"]) --> p["print `n`"] p --> t{"`n == 1?`"} t -- "yes: `break`" --> out["after the loop"] t -- "no" --> arrow["print `' -> '`
compute the next `n`"] arrow --> p ``` Each number is printed *before* the test, so the final 1 is printed too. The arrow and the next number come *after* the test, so nothing is printed or computed past the end. Move the test to the top of the body or to the bottom, and either way the line ends in a stray arrow with the final 1 missing. `Print`, unlike `PrintLine`, does not end the line, which is how the sequence stays on one row — the `PrintLine()` after the loop finishes it. ## The exit can depend on the work In the second loop, the test reads a value the body has only just computed: ```rux var odd: int32 = 1; var total: int32 = 0; loop { total += odd; if total > 50 { break; } odd += 2; } PrintLine("adding odd numbers up to {} passes 50, at {}", odd, total); ``` The total is updated first, then tested, and only if the loop goes on does `odd` move to the next odd number. That way `odd` still holds the number that pushed the total past 50 when the loop ends. ## loop or while true? `while true { … }` with a `break` inside does the same job and compiles fine. `loop` is the better way to say it: the reader sees at once that the loop's ending is decided inside it, instead of reading a condition that is not really one. | Loop | Where the test is | Runs at least once? | | ---------------- | --------------------- | ------------------- | | `while` | at the top | no | | `do`-`while` | at the bottom | yes | | `loop` + `break` | wherever you write it | up to the `break` | ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/ControlFlow/Loop){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // `loop { ... }` repeats its body with no condition at all. On its own it would run forever, so // somewhere in the body there is a `break`, which leaves the loop at once and carries on with the // statement after it. // // `while` tests at the top of each pass and `do`-`while` at the bottom. `loop` is for the loop // whose exit belongs in the middle: some work has to happen before the test, and some after it. // It also says plainly that the loop's ending is decided inside it, which `while true` hides. // // The next lesson, Break, looks at `break` in every kind of loop. Here it is just the way out. import Io::{ Print, PrintLine }; func Main() -> int { // The Collatz sequence: halve an even number, triple an odd one and add one, and stop on // reaching 1. Each number is printed before the test, so the final 1 is printed too. The arrow // and the next number come after the test, so nothing is printed or computed past the end. var n: int32 = 6; var steps: int32 = 0; loop { Print("{}", n); if n == 1 { break; } Print(" -> "); if n % 2 == 0 { n /= 2; } else { n = 3 * n + 1; } steps += 1; } PrintLine(); PrintLine("6 reaches 1 in {} steps", steps); // The exit can depend on what the body just computed. Keep adding odd numbers 1 + 3 + 5 + ... // and stop once the total passes 50. var odd: int32 = 1; var total: int32 = 0; loop { total += odd; if total > 50 { break; } odd += 2; } PrintLine("adding odd numbers up to {} passes 50, at {}", odd, total); return 0; } ``` ## Run it ```sh cd Examples/ControlFlow/Loop rux run ``` ```text 6 -> 3 -> 10 -> 5 -> 16 -> 8 -> 4 -> 2 -> 1 6 reaches 1 in 8 steps adding odd numbers up to 15 passes 50, at 64 ``` ## Common mistakes ::mistake **A `loop` with no reachable `break`.**:br The compiler does not insist on a `break`, so a `loop` whose `break` is never reached runs forever. Make sure every path through the body moves towards the exit — press **Ctrl+C** to stop a program that is stuck. :: ::mistake **Putting the test in the wrong place.**:br Move `if n == 1 { break; }` to the top or the bottom of the Collatz loop and the output ends `4 -> 2 -> `— a stray arrow, and no final `1`. Where the `break` sits decides what happens on the last pass. :: ## Try it yourself 1. Start the Collatz sequence from `27` and count the steps. (It takes a while.) 2. Change the second loop to stop once the total passes 100. 3. Rewrite the second loop with `while`. Which variable needs a different starting value, or which test needs to change? ## Learn more - [`loop`](https://rux-lang.dev/docs/lang/statements/loops#loop) in the Rux Reference - [Break](https://rux-lang.dev/docs/learn/break) — leaving any loop early - [While](https://rux-lang.dev/docs/learn/while) and [Do-while](https://rux-lang.dev/docs/learn/do-while) — loops with a test at one end # Break ::note **You'll need**: [Loop](https://rux-lang.dev/docs/learn/loop) :: A search can stop as soon as it finds what it is looking for. There is no point checking the rest of the haystack once the needle is in your hand. `break` leaves a loop immediately: the rest of the current pass is skipped, the condition is not tested again, and the program carries on with the first statement after the loop. It works in every loop — `while`, `do`-`while`, `loop`, and the `for` loop coming up later in this part. ## Stopping a search early The program looks for the smallest divisor of 91. It could try every candidate from 2 up to 90, but once one divides evenly there is no reason to keep going: ```rux let number: int32 = 91; var divisor: int32 = 2; while divisor < number { if number % divisor == 0 { break; } divisor += 1; } ``` 2, 3, 4, 5 and 6 do not divide 91; 7 does, so the loop stops with `divisor` at 7 — after six candidates instead of eighty-nine. ## How did the loop end? A loop with a `break` can end two ways: its condition became false, or the `break` ran. Code after the loop often needs to know which, and it finds out by looking at the variables the loop left behind: ```rux if divisor < number { PrintLine("{} = {} x {}", number, divisor, number / divisor); } else { PrintLine("{} is prime", number); } ``` ```mermaid flowchart LR test{"`divisor < number?`"} -- "`true`" --> check{"`number % divisor == 0?`"} check -- "yes: `break`" --> found["`divisor < number`:
a divisor was found"] check -- "no" --> step["`divisor += 1`"] step --> test test -- "`false`" --> prime["`divisor == number`:
no divisor, prime"] ``` If the loop ran out of candidates, `divisor` ended equal to `number`; if `break` ran, it is still below. One comparison tells the two endings apart. ## break leaves one loop With loops inside loops, `break` leaves only the loop it is written in — the innermost one around it. Here it ends one row of a triangle, and the outer loop carries on with the next row as if nothing happened: ```rux var row: int32 = 1; while row <= 4 { var column: int32 = 1; while column <= 4 { if column > row { break; } Print("*"); column += 1; } PrintLine(); row += 1; } ``` Row 1 prints one star before `column > row` stops the inner loop, row 2 prints two, and so on. To leave an *outer* loop from inside an inner one, you need a label — the subject of [Label](https://rux-lang.dev/docs/learn/label). ## break in a do-while In a `do`-`while`, `break` also skips the test at the bottom: ```rux var attempts: int32 = 0; do { attempts += 1; if attempts == 3 { break; } } while attempts < 10; PrintLine("gave up after {} attempts", attempts); ``` The condition would allow ten attempts, but the `break` ends the loop at three. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/ControlFlow/Break){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // `break` leaves a loop immediately. The rest of the current pass is skipped, the condition is // not tested again, and the program carries on with the first statement after the loop. It works // in every loop: `while`, `do`-`while` and `loop` alike. // // A loop with a `break` can end two ways: its condition became false, or the `break` ran. Code // after the loop often needs to know which, and it finds out by looking at the variables the // loop left behind. // // `break` belongs inside a loop. Anywhere else it is an error: // // error: 'break' can only be used inside 'while', 'for', or 'loop' import Io::{ Print, PrintLine }; func Main() -> int { // Searching for the smallest divisor of 91. The loop could try every candidate below 91, but // once one divides evenly there is no reason to keep going. let number: int32 = 91; var divisor: int32 = 2; while divisor < number { if number % divisor == 0 { break; } divisor += 1; } // Reaching `number` means the condition ended the loop and no divisor was found. if divisor < number { PrintLine("{} = {} x {}", number, divisor, number / divisor); } else { PrintLine("{} is prime", number); } // `break` leaves only the loop it is written in. Here it ends one row of the triangle; the // outer loop carries on with the next row as if nothing happened. var row: int32 = 1; while row <= 4 { var column: int32 = 1; while column <= 4 { if column > row { break; } Print("*"); column += 1; } PrintLine(); row += 1; } // In a `do`-`while`, `break` also skips the test at the bottom. var attempts: int32 = 0; do { attempts += 1; if attempts == 3 { break; } } while attempts < 10; PrintLine("gave up after {} attempts", attempts); return 0; } ``` ## Run it ```sh cd Examples/ControlFlow/Break rux run ``` ```text 91 = 7 x 13 * ** *** **** gave up after 3 attempts ``` ## Common mistakes ::mistake **`break` outside a loop.**:br`break` belongs inside a loop. Anywhere else it fails with: ```text error: 'break' can only be used inside 'while', 'for', or 'loop' ``` In particular, it cannot leave an `if` — an `if` block is not a loop. :: ::mistake **Expecting `break` to leave every loop.**:br In nested loops, a plain `break` ends only the innermost one. The outer loop carries on. Use a [label](https://rux-lang.dev/docs/learn/label) to leave an outer loop. :: ::mistake **Not checking how the loop ended.**:br After a search loop, the variables may describe "found" or "not found". Test them before using the result — otherwise a prime such as 97 would be reported as `97 = 97 x 1`. :: ## Try it yourself 1. Change `number` to `97` and check that the program reports it as prime. 2. Find the first multiple of 7 above 100 with a `loop` and `break`. 3. Make the triangle print five rows, then make it print the triangle upside down. ## Learn more - [`break` / `continue`](https://rux-lang.dev/docs/lang/statements/break-continue) in the Rux Reference - [Continue](https://rux-lang.dev/docs/learn/continue) — skipping one pass instead of leaving the loop - [Label](https://rux-lang.dev/docs/learn/label) — breaking out of an outer loop # Continue ::note **You'll need**: [Break](https://rux-lang.dev/docs/learn/break) :: `break` gives up on the whole loop. Often you only want to give up on one value — skip the blank line, ignore the negative reading, pass over the multiples of 3 — and carry on with the rest. `continue` abandons the rest of the current pass and starts the next one. It does not leave the loop. ## Skipping a value ```rux var n: int32 = 0; while n < 20 { n += 1; if n % 3 == 0 { continue; } Print(" {}", n); } ``` For 3, 6, 9 and the other multiples of 3, `continue` jumps over the `Print`. Every other number reaches it. The shape is worth remembering: the test for "not this one" goes at the top of the body, and the work below it runs only for the values that remain. ## Where continue goes next Where the next pass begins depends on the loop: | Loop | After `continue` | | ------------ | ------------------------------ | | `while` | tests its condition again | | `do`-`while` | goes to the test at its bottom | | `loop` | starts its body again | | `for` | moves on to the next value | ```mermaid flowchart LR test{"`n < 20?`"} -- "`true`" --> step["`n += 1`"] step --> skip{"`n % 3 == 0?`"} skip -- "yes: `continue`" --> test skip -- "no" --> work["print `n`"] work --> test test -- "`false`" --> after["after the loop"] ``` ## The step goes first `continue` skips *everything* after it in the body — including any line that moves the loop on. That is why `n += 1` comes at the top of both loops here. Suppose it were written at the bottom instead: ```rux while n < 20 { if n % 3 == 0 { continue; } Print(" {}", n); n += 1; } ``` `n` starts at 0, which is already a multiple of 3. `continue` jumps back to the test before `n += 1` runs, so `n` is still 0, the test still holds, `continue` runs again — and the loop tests the same value forever, without printing a thing. Step first, then decide whether to skip. ## Skipped passes still happen A skipped pass is not a pass that never ran; it just ends early. The second loop counts both: ```rux var passes: int32 = 0; var kept: int32 = 0; var sum: int32 = 0; n = 0; while n < 10 { n += 1; passes += 1; if n % 2 == 0 { continue; } kept += 1; sum += n; } ``` Ten passes run; five reach the bottom, adding up the odd numbers 1 + 3 + 5 + 7 + 9 = 25. ## continue and break together The two combine naturally: skip some values, stop at another. ```rux var k: int32 = 0; loop { k += 1; if k % 2 == 0 { continue; } if k > 7 { break; } Print(" {}", k); } ``` Even numbers are skipped; the first odd number above 7 — which is 9 — ends the loop. So `k` is 9 afterwards, even though the last number printed was 7. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/ControlFlow/Continue){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // `continue` abandons the rest of the current pass and starts the next one. Unlike `break`, it // does not leave the loop: a `while` goes back to testing its condition, a `do`-`while` goes to // the test at its bottom, and a `loop` starts its body again. // // It suits a loop that has to skip some values: the test for "not this one" goes at the top of // the body, and the work below it runs only for the values that remain. // // The trap: `continue` skips *everything* after it, including the step that moves the loop on. // Write the step below the `continue` and a skipped value is never stepped past, so the loop // tests the same value forever. That is why `n += 1` comes first in both loops below. import Io::{ Print, PrintLine }; func Main() -> int { // Numbers from 1 to 20 that are not multiples of 3. Print("not multiples of 3:"); var n: int32 = 0; while n < 20 { n += 1; if n % 3 == 0 { continue; } Print(" {}", n); } PrintLine(); // Counting and summing only the values that pass a test. The skipped passes still happen; // they just end early. var passes: int32 = 0; var kept: int32 = 0; var sum: int32 = 0; n = 0; while n < 10 { n += 1; passes += 1; if n % 2 == 0 { continue; } kept += 1; sum += n; } PrintLine("{} passes, {} odd numbers kept, summing to {}", passes, kept, sum); // `continue` and `break` together: skip the even numbers, stop at the first odd one above 7. Print("odd numbers up to 7:"); var k: int32 = 0; loop { k += 1; if k % 2 == 0 { continue; } if k > 7 { break; } Print(" {}", k); } PrintLine(); PrintLine("stopped at {}", k); return 0; } ``` ## Run it ```sh cd Examples/ControlFlow/Continue rux run ``` ```text not multiples of 3: 1 2 4 5 7 8 10 11 13 14 16 17 19 20 10 passes, 5 odd numbers kept, summing to 25 odd numbers up to 7: 1 3 5 7 stopped at 9 ``` ## Common mistakes ::mistake **Stepping after the `continue`.**:br If the line that moves the loop on comes below a `continue`, a skipped value is never stepped past, and the loop runs forever on the same value. The compiler cannot see this — it compiles cleanly. Put the step at the top of the body. ([For](https://rux-lang.dev/docs/learn/for) handles the step itself, so the trap disappears there.) :: ::mistake **`continue` outside a loop.**:br Like `break`, it belongs in a loop: ```text error: 'continue' can only be used inside 'while', 'for', or 'loop' ``` :: ## Try it yourself 1. Print the numbers from 1 to 30 that are multiples of neither 2 nor 3. 2. Add up only the numbers from 1 to 100 that end in 7 (`n % 10 == 7`). 3. Change the last loop to stop at the first odd number above 15. ## Learn more - [`break` / `continue`](https://rux-lang.dev/docs/lang/statements/break-continue) in the Rux Reference - [Break](https://rux-lang.dev/docs/learn/break) — leaving the loop instead of one pass - [For](https://rux-lang.dev/docs/learn/for) — a loop where `continue` can never skip the step # Range ::note **You'll need**: [While](https://rux-lang.dev/docs/learn/while), [Comparison](https://rux-lang.dev/docs/learn/comparison) :: "The digits 0 to 9." "Faces one to six." "Hours from 9 until 17." A great deal of counting is about a run of consecutive numbers described by where it starts and where it stops. A *range* is a value that holds exactly that: two ends. The main use of a range is walking through it, which the [next lesson](https://rux-lang.dev/docs/learn/for) does in one line; this lesson looks at what a range is, so that the walk holds no surprises. ## Two spellings, two kinds of end ```rux let digits = 0..10; let die = 1..=6; ``` `a..b` starts at `a` and stops **just before** `b` — the end is excluded, so `0..10` is the ten digits 0 to 9. `a..=b` **includes** `b`, so `1..=6` is the six faces of a die. | Range | Type | Values | How many | | ------- | ----------- | ---------- | --------------------- | | `0..10` | `int..int` | 0, 1, …, 9 | `end - start` = 10 | | `1..=6` | `int..=int` | 1, 2, …, 6 | `end - start + 1` = 6 | | `5..5` | `int..int` | none | 0 | | `5..=5` | `int..=int` | 5 | 1 | The two spellings make two different types. That is not a detail to memorise — it means the compiler always knows which kind of end a range has. ## A range holds only its bounds A range does not list its values. It remembers its two ends, which it offers as `.start` and `.end`: ```rux PrintLine("digits: start {}, end {} (excluded)", digits.start, digits.end); PrintLine("die: start {}, end {} (included)", die.start, die.end); ``` Everything else follows from those two numbers. How many values a range holds is a subtraction, plus one for an inclusive end: ```rux PrintLine("{} digits", digits.end - digits.start); PrintLine("{} faces", die.end - die.start + 1); ``` Whether a number falls inside is two comparisons — and the one against the end differs by a single character: ```rux let roll = 7; let isDigit = roll >= digits.start && roll < digits.end; let isFace = roll >= die.start && roll <= die.end; ``` ## Bounds and their type The bounds may be any integer expressions, not only literals: ```rux let first: int32 = 3; let width: int32 = 4; let window = first..first + width; ``` `..` ranks below arithmetic, so `first..first + width` is `3..7`. The bounds take the type of the values they are built from — `int32` here. With literal bounds the default is `int`, and an annotation picks another integer type: ```rux let hours: uint8..uint8 = 0..24; ``` ## Walking a range by hand To visit every value: start at `.start`, step by one, and stop according to the kind of end. ```rux var face = die.start; while face <= die.end { Print(" {}", face); face += 1; } ``` ```mermaid flowchart LR s(["`face = start`"]) --> t{"exclusive: `face < end`
inclusive: `face <= end`"} t -- "`true`" --> b["use `face`
`face += 1`"] b --> t t -- "`false`" --> done["done"] ``` Every walk over a range has these same three parts — a start, a test, a step — and the only thing that changes is `<` or `<=`. That repetition is exactly what `for` takes off your hands. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/ControlFlow/Range){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // A range is a value that describes a run of consecutive integers by its two ends. `a..b` starts // at `a` and stops just before `b`, so `b` is excluded; `a..=b` includes `b`. The two spellings // make two different types: `0..10` is an `int..int` and `1..=6` an `int..=int`. // // A range does not list its values; it only remembers its bounds, which it offers as `.start` // and `.end`. Everything else (how many values, whether a number is inside) follows from them. // // The start may not come after the end. A range written backwards with literal bounds is refused: // // let backwards = 5..2; // error: range start cannot be greater than its end // // The main use of a range is walking through it, which the next lesson, For, does in one line. // Here a `while` loop does it by hand, to show what a range means. import Io::{ Print, PrintLine }; func Main() -> int { let digits = 0..10; let die = 1..=6; PrintLine("digits: start {}, end {} (excluded)", digits.start, digits.end); PrintLine("die: start {}, end {} (included)", die.start, die.end); // How many values each range holds. The inclusive end is one value more. PrintLine("{} digits", digits.end - digits.start); PrintLine("{} faces", die.end - die.start + 1); // Whether a number falls inside: the comparison against the end differs by one character. let roll = 7; let isDigit = roll >= digits.start && roll < digits.end; let isFace = roll >= die.start && roll <= die.end; PrintLine("{} is a digit: {}, a face: {}", roll, isDigit, isFace); // Equal bounds: the exclusive range holds nothing at all, the inclusive one holds one value. let empty = 5..5; let single = 5..=5; PrintLine("5..5 holds {} values, 5..=5 holds {}", empty.end - empty.start, single.end - single.start + 1); // The bounds may be any integer expressions, not only literals. let first: int32 = 3; let width: int32 = 4; let window = first..first + width; PrintLine("window: start {}, end {}", window.start, window.end); // An annotation picks another integer type for the bounds, and literal bounds take it. let hours: uint8..uint8 = 0..24; PrintLine("hours: start {}, end {}", hours.start, hours.end); // Walking a range by hand: start at `.start`, step by one, stop according to the kind of end. Print("faces:"); var face = die.start; while face <= die.end { Print(" {}", face); face += 1; } PrintLine(); return 0; } ``` ## Run it ```sh cd Examples/ControlFlow/Range rux run ``` ```text digits: start 0, end 10 (excluded) die: start 1, end 6 (included) 10 digits 6 faces 7 is a digit: true, a face: false 5..5 holds 0 values, 5..=5 holds 1 window: start 3, end 7 hours: start 0, end 24 faces: 1 2 3 4 5 6 ``` ## Common mistakes ::mistake **A range written backwards.**:br The start may not come after the end. With literal bounds the compiler catches it: `let backwards = 5..2;` fails with: ```text error: range start cannot be greater than its end ``` With bounds computed while the program runs, nothing is reported, and a walk over the range runs zero times. :: ::mistake **Off by one at the end.**:br`1..6` stops at 5. When you mean "up to and including", write `..=`. Counting uses `end - start` for `..` but `end - start + 1` for `..=`. :: ## Try it yourself 1. Make a range for the months of the year and print how many values it holds. 2. Test whether `0`, `5` and `10` fall inside `digits`, and whether they fall inside `0..=10`. 3. Walk `digits` by hand with `while`, printing every value. Which comparison does the condition need? 4. Write `let backwards = 5..2;` and read the error. ## Learn more - [Ranges](https://rux-lang.dev/docs/lang/ranges/overview) and [using ranges](https://rux-lang.dev/docs/lang/ranges/overview#in-a-for-loop) in the Rux Reference - [For](https://rux-lang.dev/docs/learn/for) — walking a range in one line - [Range pattern](https://rux-lang.dev/docs/learn/range-pattern) — matching a value against a range # For ::note **You'll need**: [Range](https://rux-lang.dev/docs/learn/range), [Continue](https://rux-lang.dev/docs/learn/continue) :: The [Range](https://rux-lang.dev/docs/learn/range) lesson walked through a range by hand: a counter, a test against the end, a step on every pass. Three separate lines, and getting any one of them wrong — the wrong comparison, a forgotten step — breaks the loop. `for` does the whole walk in one line. It runs its body once for every value in a range, in order, and hands each value to the body by name. ## for name in range ```rux for i in 1..5 { Print(" {}", i); } ``` On each pass, `i` is the next value of the range: 1, 2, 3, 4. The end of `..` is excluded, so 5 is not visited; with `..=` it is: ```rux for i in 1..=5 { Print(" {}", i); } ``` Here is what `for` does for you, compared with the hand-written walk: | Part | Hand-written `while` | `for i in 1..=5` | | ---------- | -------------------------- | ----------------------- | | Start | `var i = 1;` | from the range's start | | Test | `while i <= 5` | from the kind of end | | Step | `i += 1;` — easy to forget | done by the loop | | Loop value | a `var` anyone can change | a fresh `let` each pass | ```mermaid flowchart LR r(["`for i in 1..=5`"]) --> more{"values left?"} more -- "yes" --> bind["`i` = next value"] bind --> body["run the body"] body --> more more -- "no" --> after["after the loop"] ``` ## Ranges stored in a binding A range kept in a variable works the same as one written in place. The loop variable takes the type of the bounds, so this `face` is an `int32`, like the `total` it is added to: ```rux let die: int32..=int32 = 1..=6; var total: int32 = 0; for face in die { total += face; } ``` ## Bounds are evaluated once The bounds are worked out once, before the first pass. A factorial — 10! is 1 × 2 × … × 10 — multiplies every number up to and *including* `n`, so the inclusive form matches its definition exactly: ```rux let n = 10; var factorial = 1; for i in 2..=n { factorial *= i; } ``` Starting at 2 skips a pointless multiplication by 1. An empty range, such as `3..3`, gives the body nothing to run for: the loop runs zero times. ## The loop variable cannot be changed `i` is a fresh, immutable binding on every pass. The body can read it but cannot assign to it, so it cannot push the loop along or hold it back. When the body really does need to control the stepping — skipping ahead by more than one, or going back — that is a job for `while`. ## break and continue work here too `break` and `continue` work in `for` as in every other loop. And because the loop does its own stepping, `continue` moves straight on to the next value — the trap from [Continue](https://rux-lang.dev/docs/learn/continue), a step skipped by mistake, cannot happen: ```rux for i in 0..10 { if i % 2 == 0 { continue; } Print(" {}", i); } ``` Whenever a loop visits a known run of numbers, reach for `for` first. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/ControlFlow/For){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // `for name in range { ... }` runs its body once for every value in the range, in order, binding // the value to `name` on each pass. It is the walk the Range lesson wrote by hand with `while`, // with the counter, the test and the step all handled by the loop, so none of them can be // forgotten or got wrong. // // The loop variable is a fresh, immutable binding on every pass, so the body cannot move the loop // along by assigning to it: // // for i in 1..4 { i = 10; } // error: cannot modify immutable variable 'i' // // When the body needs to control the stepping, use `while`. import Io::{ Print, PrintLine }; func Main() -> int { // The end of `..` is excluded, the end of `..=` is included. Print("1..5: "); for i in 1..5 { Print(" {}", i); } PrintLine(); Print("1..=5:"); for i in 1..=5 { Print(" {}", i); } PrintLine(); // A range stored in a binding works the same as one written in place. The loop variable takes // the type of the bounds, so this `face` is an `int32`, like the `total` it is added to. let die: int32..=int32 = 1..=6; var total: int32 = 0; for face in die { total += face; } PrintLine("the faces of a die add up to {}", total); // Bounds are evaluated once, before the first pass. A factorial multiplies every number from // 1 up to and including n, so the inclusive form matches its definition. let n = 10; var factorial = 1; for i in 2..=n { factorial *= i; } PrintLine("{}! = {}", n, factorial); // An empty range gives the body nothing to run for. var passes: int32 = 0; for i in 3..3 { passes += 1; } PrintLine("3..3 ran the body {} times", passes); // `break` and `continue` work in `for` as in every other loop. `continue` moves straight on to // the next value, with no step to forget. Print("odd numbers below 10:"); for i in 0..10 { if i % 2 == 0 { continue; } Print(" {}", i); } PrintLine(); return 0; } ``` ## Run it ```sh cd Examples/ControlFlow/For rux run ``` ```text 1..5: 1 2 3 4 1..=5: 1 2 3 4 5 the faces of a die add up to 21 10! = 3628800 3..3 ran the body 0 times odd numbers below 10: 1 3 5 7 9 ``` ## Common mistakes ::mistake **Assigning to the loop variable.**:br`for i in 1..4 { i = 10; }` fails with: ```text error: cannot modify immutable variable 'i' ``` The compiler's help suggests declaring `i` with `var`, but a `for` variable cannot be — `for var i in …` does not parse. Use `while` when the body must control the stepping. :: ::mistake **Counting down with a backwards range.**:br A range only counts up. `for i in 5..0` is refused with: ```text error: range start cannot be greater than its end ``` With bounds computed at run time, such as `high..low`, the body silently runs zero times. Count down with a `while` loop. :: ::mistake **Off by one at the end.**:br`for i in 1..10` stops at 9. If the last value should be included, write `1..=10`. :: ## Try it yourself 1. Print the squares of the numbers from 1 to 10. 2. Add up the numbers from 1 to 100 with `for`, then compare with the `while` version in [While](https://rux-lang.dev/docs/learn/while). 3. Print a multiplication table for 7, from `7 x 1` to `7 x 10`. 4. Compute 12! with the factorial loop. Does the answer still fit in an `int`? ## Learn more - [`for` / `in`](https://rux-lang.dev/docs/lang/statements/loops#for) in the Rux Reference - [Label](https://rux-lang.dev/docs/learn/label) — leaving an outer `for` from an inner one - [Iterator](https://rux-lang.dev/docs/learn/iterator) — making your own types walkable by `for` # Label ::note **You'll need**: [For](https://rux-lang.dev/docs/learn/for), [Break](https://rux-lang.dev/docs/learn/break), [Continue](https://rux-lang.dev/docs/learn/continue) :: A plain `break` or `continue` acts on the innermost loop around it. With one loop inside another, that is sometimes the wrong one. A search through a grid of rows and columns wants to stop the *whole* search once it finds a match — not just the current row, only for the outer loop to start the next one. A **label** gives a loop a name, so `break` and `continue` can say which loop they mean. ## Naming a loop Write the label before the loop, followed by a colon. Then `break` or `continue` with that name acts on that loop: ```rux var checks: int32 = 0; search: for a in 1..10 { for b in a..10 { checks += 1; if a * a + b * b == 100 { PrintLine("{}^2 + {}^2 = 100", a, b); break search; } } } PrintLine("found after {} checks", checks); ``` The program looks for two numbers below 10 whose squares add up to 100. When it finds 6 and 8, `break search;` leaves the loop named `search` — and every loop inside it — and goes straight to the `PrintLine` after it. Without the label, `break` would end only the inner loop over `b`, and the outer loop would go on searching after the answer was found. (The inner range starts at `a`, so each pair is tried only once: 6 and 8, never 8 and 6 as well.) ## continue with a label `continue search;` abandons the inner loops and starts the next pass of the labelled one. The second example reports, for each row of a times table, the first product above 10: ```rux rows: for row in 1..=4 { for column in 1..=9 { if row * column > 10 { PrintLine("row {}: {} x {} = {}", row, row, column, row * column); continue rows; } } PrintLine("row {}: no product above 10", row); } ``` `continue rows` skips the rest of the row — including the line after the inner loop. So `no product above 10` prints only for a row where the inner loop ran to its end without finding anything, which here is row 1. ## Where each jump goes ```mermaid flowchart LR outer(["`outer: for …`"]) --> inner(["`for …` (inner)"]) inner --> body["inner body"] body -- "`break`" --> afterInner["rest of the outer body"] body -- "`continue`" --> inner body -- "`break outer`" --> afterOuter["after the outer loop"] body -- "`continue outer`" --> outer ``` | Inside the inner loop | Goes to | | --------------------- | ---------------------------------------- | | `break;` | the rest of the outer loop's body | | `continue;` | the next pass of the inner loop | | `break outer;` | the first statement after the outer loop | | `continue outer;` | the next pass of the outer loop | Labels work on `while`, `do`-`while` and `loop` too, not only `for`. ## Labels are checked names A label is checked like any other name, so a misspelling is caught at compile time instead of jumping somewhere unexpected. And a nested loop may not reuse the label of a loop around it, which would leave `break outer;` naming two loops at once. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/ControlFlow/Label){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // A plain `break` or `continue` acts on the innermost loop around it. With nested loops, that is // sometimes the wrong one: a search through a grid wants to stop the *whole* search once it finds // a match, not just the current row. // // A label names a loop. Write it before the loop with a colon, `search: for ...`, and then // `break search;` leaves that loop and every loop inside it, while `continue search;` abandons // the inner loops and starts the next pass of the labeled one. Labels work on `while`, `do` and // `loop` too. // // A label is checked like any other name, so a misspelling is caught: // // break serach; // error: 'break' refers to unknown loop label 'serach' // // And a nested loop may not reuse the label of a loop around it, which would leave `break outer;` // naming two loops at once: // // outer: for i in 0..3 { outer: for j in 0..3 { break outer; } } // error: loop label 'outer' shadows an enclosing loop label // help: give the inner loop a different label import Io::PrintLine; func Main() -> int { // Find two numbers below 10 whose squares add up to 100. Without the label, `break` would // end only the inner loop, and the outer one would go on searching after the answer was found. var checks: int32 = 0; search: for a in 1..10 { for b in a..10 { checks += 1; if a * a + b * b == 100 { PrintLine("{}^2 + {}^2 = 100", a, b); break search; } } } PrintLine("found after {} checks", checks); // For each row of a times table, report the first product above 10 and move on to the next // row. `continue rows` skips the rest of the row, including the line after the inner loop, // which therefore prints only for a row where nothing was found. rows: for row in 1..=4 { for column in 1..=9 { if row * column > 10 { PrintLine("row {}: {} x {} = {}", row, row, column, row * column); continue rows; } } PrintLine("row {}: no product above 10", row); } return 0; } ``` ## Run it ```sh cd Examples/ControlFlow/Label rux run ``` ```text 6^2 + 8^2 = 100 found after 38 checks row 1: no product above 10 row 2: 2 x 6 = 12 row 3: 3 x 4 = 12 row 4: 4 x 3 = 12 ``` ## Common mistakes ::mistake **Misspelling the label.**:br`break serach;` fails with: ```text error: 'break' refers to unknown loop label 'serach' ``` The label must match the one written before the loop. :: ::mistake **Reusing a label on a nested loop.**:br`outer: for i in 0..3 { outer: for j in 0..3 { break outer; } }` fails with: ```text error: loop label 'outer' shadows an enclosing loop label ``` The help says to give the inner loop a different label. :: ::mistake **Forgetting the label.**:br A plain `break` in the inner loop leaves only the inner loop. The search then carries on, and `checks` counts far more than it needed to. :: ## Try it yourself 1. Remove `search` from `break search;` and compare the number of checks. 2. Change the search to find two numbers whose squares add up to `65`. How many pairs exist below 10, and which one does the program report? 3. Label a `while` loop and use `break` with its name from inside a nested `loop`. ## Learn more - [`loop`](https://rux-lang.dev/docs/lang/statements/loops#loop) and [`break` / `continue`](https://rux-lang.dev/docs/lang/statements/break-continue) in the Rux Reference - [Break](https://rux-lang.dev/docs/learn/break) and [Continue](https://rux-lang.dev/docs/learn/continue) — the unlabelled forms - [Match](https://rux-lang.dev/docs/learn/match) — the next lesson, choosing a branch by value # Match ::note **You'll need**: [Else if](https://rux-lang.dev/docs/learn/else-if) :: An `else if` chain that compares one value with a list of constants — `if status == 200 … else if status == 404 … else if status == 500 …` — repeats the same name in every condition, and the reader has to check each line to be sure it really is the same value. `match` says it once. It compares one value against a list of **arms** and runs the first arm whose pattern fits. ## Arms and patterns ```rux let count: int32 = 2; match count { 0 => PrintLine("none"), 1 => PrintLine("one"), 2 => PrintLine("a pair"), else => PrintLine("several") } ``` After `match` comes the value being examined, then the arms in braces. Each arm is `pattern => what to do`, and arms are separated by commas. The patterns here are literals — the arm `2` fits when `count` is 2. ## How an arm is chosen The arms are tried from the top. The first one that fits runs, and the rest are skipped — exactly like an `else if` chain. Whichever arm runs, or none, the program then carries on after the match: ```mermaid flowchart LR v(["`match count`"]) --> a0{"fits `0`?"} a0 -- "yes" --> r0["`none`"] a0 -- "no" --> a1{"fits `1`?"} a1 -- "yes" --> r1["`one`"] a1 -- "no" --> a2{"fits `2`?"} a2 -- "yes" --> r2["`a pair`"] a2 -- "no" --> e{"is there an
`else` arm?"} e -- "yes" --> re["`several`"] e -- "no" --> skip["nothing runs"] ``` The last arm may be `else`, which fits any value the arms above it did not name. The default arm is always spelled `else` — the `_` that other languages use is refused. ## An arm with a block An arm that needs more than one statement takes a block in braces. The comma still follows it: ```rux match status { 200 => PrintLine("ok"), 404 => { PrintLine("not found"); PrintLine("check the address"); }, else => PrintLine("status {}", status) } ``` ## Covering every value A `bool` has only two values, so naming both covers everything, and no `else` is needed: ```rux match ready { true => PrintLine("ready"), false => PrintLine("not ready yet") } ``` An integer has far too many values to name, and here is the caveat: an integer that fits no arm is **not** an error. Nothing runs, and the program carries on after the match: ```rux let missed: int32 = 99; match missed { 1 => PrintLine("one"), 2 => PrintLine("two") } ``` Write an `else` arm whenever every value ought to be handled. A match that produces a value is held to a stricter rule, as the [next lesson](https://rux-lang.dev/docs/learn/match-expression) shows. ## What match checks for you `match` is stricter than an `else if` chain in a useful way. A chain will happily run with a condition that can never be reached, but `match` refuses arms that cannot run: | Mistake | `else if` chain | `match` | | ------------------------------ | ------------------ | -------------------------------------------------------------------------------- | | The same case written twice | the second is dead | `error: duplicate pattern in match` | | A catch-all before other cases | the rest are dead | `error: match arm is unreachable because an earlier pattern matches every value` | An arm holds exactly one pattern. There is no `6 | 7 =>`: two values that share an outcome are written as two arms. Later parts add richer patterns — [characters](https://rux-lang.dev/docs/learn/character-pattern), [ranges](https://rux-lang.dev/docs/learn/range-pattern) such as `1..=9 =>`, and [guards](https://rux-lang.dev/docs/learn/guard) that add a condition to an arm. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/ControlFlow/Match){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // `match` compares one value against a list of arms and runs the first arm whose pattern fits. // It says the same as an `if` / `else if` chain of `==` tests, but names the value once instead // of repeating it in every condition. // // Each arm is `pattern => what to do`, and arms are separated by commas. The last arm may be // `else`, which fits any value the arms above it did not name. The default arm is always spelled // `else`; the `_` other languages use is refused: // // error: use 'else' for the default match arm // // An arm holds exactly one pattern. There is no `1 | 2 =>`: two values that share an outcome are // written as two arms. import Io::PrintLine; func Main() -> int { // Literal patterns, and `else` for everything else. let count: int32 = 2; match count { 0 => PrintLine("none"), 1 => PrintLine("one"), 2 => PrintLine("a pair"), else => PrintLine("several") } // An arm that needs more than one statement takes a block. let status: int32 = 404; match status { 200 => PrintLine("ok"), 404 => { PrintLine("not found"); PrintLine("check the address"); }, else => PrintLine("status {}", status) } // A `bool` has only two values, so naming both covers everything and no `else` is needed. let ready = false; match ready { true => PrintLine("ready"), false => PrintLine("not ready yet") } // The caveat: an integer that fits no arm is not an error. Nothing runs, and the program // carries on after the match. Write an `else` arm whenever every value ought to be handled. // (A match that produces a value is held to more than this, as the next lesson shows.) let missed: int32 = 99; match missed { 1 => PrintLine("one"), 2 => PrintLine("two") } PrintLine("99 fit no arm, so that match did nothing"); return 0; } ``` ## Run it ```sh cd Examples/ControlFlow/Match rux run ``` ```text a pair not found check the address not ready yet 99 fit no arm, so that match did nothing ``` ## Common mistakes ::mistake **Using `_` for the default arm.**:br`_ => PrintLine("other")` fails with: ```text error: use 'else' for the default match arm ``` :: ::mistake **Combining values in one arm.**:br`6 | 7 => …` is not a pattern in Rux; the parser stops with: ```text error: expected '=>' after the match arm pattern before '|' ``` Write one arm for each value. :: ::mistake **Forgetting the comma between arms.**:br Every arm except the last ends with a comma — including an arm whose body is a block. Without it: ```text error: expected ',' between match arms before 'else' ``` :: ::mistake **Putting `else` first.**:br`else` fits everything, so arms after it could never run: ```text error: match arm is unreachable because an earlier pattern matches every value ``` Keep `else` last. :: ::mistake **Leaving out `else` by accident.**:br An integer match with no `else` silently does nothing for a value no arm names. If every value should be handled, add the `else` arm. :: ## Try it yourself 1. Write a match on an `int32` `day` that prints the name of the day for 1 to 7 and `"no such day"` for anything else. 2. Rewrite the `status` match as an `else if` chain and compare how often `status` is named. 3. Set `missed` to `2` and run again, then add an `else` arm that prints the value. 4. Write the same case twice in one match and read the error. ## Learn more - [`match`](https://rux-lang.dev/docs/lang/patterns/match) in the Rux Reference - [Match expression](https://rux-lang.dev/docs/learn/match-expression) — `match` as a value - [Exhaustive](https://rux-lang.dev/docs/learn/exhaustive) — when a match must cover every case # Match expression ::note **You'll need**: [Match](https://rux-lang.dev/docs/learn/match), [Ternary](https://rux-lang.dev/docs/learn/ternary) :: The conditional `? :` chooses between two values; [Ternary](https://rux-lang.dev/docs/learn/ternary) showed why that is better than declaring a `var` and assigning it in an `if`. `match` can do the same with any number of cases. Each arm produces a value instead of running a statement, and the whole match *becomes* the value of the arm that fit. ## The long way: match as a statement As a statement, choosing a value needs a `var`, declared first with a placeholder and assigned in every arm: ```rux let day: int32 = 6; var kindTheLongWay = ""; match day { 6 => { kindTheLongWay = "weekend"; }, 7 => { kindTheLongWay = "weekend"; }, else => { kindTheLongWay = "weekday"; } } ``` It works, but the name is repeated in every arm, nothing stops an arm from forgetting to assign it, and the result is a `var` that anything later could change. ## The short way: match as a value As an expression, each arm is just the value it produces: ```rux let kind = match day { 6 => "weekend", 7 => "weekend", else => "weekday" }; ``` The binding is a `let` that gets its value where it is declared. Note the semicolon after the closing brace: the match is part of the `let` statement, and the statement needs its `;`. ## A value goes anywhere Like any value, a match expression can be passed straight to a call. Most months have 31 days, so `else` covers the common case and the arms list the exceptions: ```rux PrintLine("month {} has {} days", month, match month { 2 => 28, 4 => 30, 6 => 30, 9 => 30, 11 => 30, else => 31 }); ``` Or it can stand inside arithmetic — here, a price per cup size, multiplied by the number of cups: ```rux let total = cups * match size { 1 => 3, 2 => 4, else => 5 }; ``` ## One type, every value covered A match expression has to produce exactly one value, of one type, whatever the input. That gives the compiler two things to check that a match *statement* does not need: ```mermaid flowchart LR m(["`let x = match value { … }`"]) --> t{"Do all arms produce
the same type?"} t -- "no" --> e1["`error: match arm`
`type mismatch`"] t -- "yes" --> c{"Do the arms cover
every possible value?"} c -- "no" --> e2["`error: match on 'int32'`
`is not exhaustive`"] c -- "yes" --> ok["`x` gets the value
of the arm that fits"] ``` A match over numbers cannot name every value, so it needs an `else` arm, and the compiler checks that it is there. The statement-form caveat from [Match](https://rux-lang.dev/docs/learn/match) — an integer that fits no arm silently does nothing — cannot happen here, because "nothing" is not a value. A `bool` match that names both `true` and `false` already covers every input, so it needs no `else`: ```rux let sign = match open { true => "come in", false => "closed" }; ``` | Form | Arms produce | Must cover every value? | Result | | ------------------ | ------------------ | --------------------------- | --------- | | `match` statement | statements | no — unmatched does nothing | nothing | | `match` expression | values of one type | yes — `else` for numbers | one value | ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/ControlFlow/MatchExpression){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // A `match` is also an expression: each arm can produce a value instead of running a statement, // and the whole match becomes the value of the arm that fit. So it can initialize a `let`, be // passed to a call, or appear in arithmetic, just like the `? :` conditional, but with any number // of cases. // // Being one value, it has one type, so every arm must produce the same type: // // let label = match day { 6 => "weekend", else => 0 }; // error: match arm type mismatch: expected 'char8[..]', found 'int' // // And a value has to come out whatever the input, so the arms must cover every value. A match // over numbers cannot name them all, so it needs an `else` arm, and the compiler checks: // // let kind = match day { 6 => "weekend", 7 => "weekend" }; // error: match on 'int32' is not exhaustive; its arms do not cover every value // help: add an 'else' arm // // A `bool` match that names both `true` and `false` already covers every input. import Io::PrintLine; func Main() -> int { // As a statement, choosing a value needs a `var`, declared first and assigned in every arm. let day: int32 = 6; var kindTheLongWay = ""; match day { 6 => { kindTheLongWay = "weekend"; }, 7 => { kindTheLongWay = "weekend"; }, else => { kindTheLongWay = "weekday"; } } // As an expression, the binding is a `let` that gets its value where it is declared. The // match ends with a semicolon here, because it is part of the `let` statement. let kind = match day { 6 => "weekend", 7 => "weekend", else => "weekday" }; PrintLine("day {} is a {} ({} the long way)", day, kind, kindTheLongWay); // Passed straight to a call. Most months have 31 days, so `else` covers the common case. let month: int32 = 4; PrintLine("month {} has {} days", month, match month { 2 => 28, 4 => 30, 6 => 30, 9 => 30, 11 => 30, else => 31 }); // Used inside arithmetic: a price per size, times a quantity. let size: int32 = 2; let cups: int32 = 3; let total = cups * match size { 1 => 3, 2 => 4, else => 5 }; PrintLine("{} cups of size {} cost {}", cups, size, total); // A `bool` match that names both values covers every input, so it needs no `else`. let open = true; let sign = match open { true => "come in", false => "closed" }; PrintLine("the sign says {}", sign); return 0; } ``` ## Run it ```sh cd Examples/ControlFlow/MatchExpression rux run ``` ```text day 6 is a weekend (weekend the long way) month 4 has 30 days 3 cups of size 2 cost 12 the sign says come in ``` ## Common mistakes ::mistake **Arms of different types.**:br`let label = match day { 6 => "weekend", else => 0 };` fails with: ```text error: match arm type mismatch: expected 'char8[..]', found 'int' ``` Every arm must produce the same type. :: ::mistake **Missing the `else` arm.**:br`let kind = match day { 6 => "weekend", 7 => "weekend" };` fails with: ```text error: match on 'int32' is not exhaustive; its arms do not cover every value ``` The help says to add an `else` arm. :: ::mistake **Forgetting the semicolon.**:br A match that initialises a `let` ends with `};`. Leave out the `;` and the compiler stops at the next statement: ```text error: expected ';' after the binding declaration before 'PrintLine' ``` :: ## Try it yourself 1. Write `let name = match day { … };` that gives the name of each day from 1 to 7, with `"unknown"` for everything else. 2. Make the month match return 29 for February in a leap year, using a `bool` `leap` and the conditional `? :` inside the arm. 3. Turn the cups example into a statement match that assigns a `var`, and compare the two versions. 4. Remove the `else` arm from the month match and read the error. ## Learn more - [`match`](https://rux-lang.dev/docs/lang/patterns/match) in the Rux Reference - [Exhaustive](https://rux-lang.dev/docs/learn/exhaustive) — how the compiler decides whether a match covers every case - [Variant match](https://rux-lang.dev/docs/learn/variant-match) — matching the cases of your own types # Part 4: Functions A function gives a piece of work a name, so it can be written once and run from anywhere. This part starts with the plain shape — parameters in, a result out — and then shows every way Rux lets one function do more: return early, call itself, share a name, leave arguments out, work for many types, and take another function as an argument. By the end, `Main` stops being the whole program and becomes the place that calls the parts. ## What you will learn - Declaring functions with typed parameters and a result, and calling them. - Leaving a function early with `return`, and writing functions with no result. - Recursion: a function that calls itself, and the base case that stops it. - Overloading: several functions with one name, chosen by their arguments. - Default arguments that let a call leave the usual value out. - Generic functions with a type parameter ``, inferred or given explicitly. - Passing a function as a value, typed by its shape: `func(int32) -> int32`. ## One idea, many shapes ```mermaid flowchart LR f["A function
parameters in, result out"] --> r["Return
leave early, or give nothing back"] r --> rec["Recursion
call yourself on a smaller problem"] f --> o["Overload
one name, several parameter lists"] o --> g["Generic
one body, many types"] f --> d["Default argument
a parameter the call may skip"] f --> cb["Callback
a function passed as a value"] ``` ## Lessons | | Lesson | What you will learn | | --- | -------------------------------------------------------------------- | -------------------------------------------------------------------------- | | 4.1 | [Function](https://rux-lang.dev/docs/learn/function) | declare functions with parameters and a return value, and call them | | 4.2 | [Return](https://rux-lang.dev/docs/learn/return) | return early, and write functions that return nothing | | 4.3 | [Recursion](https://rux-lang.dev/docs/learn/recursion) | a function that calls itself, and the base case that stops it | | 4.4 | [Overload](https://rux-lang.dev/docs/learn/overload) | give several functions one name, and let the arguments choose between them | | 4.5 | [Default argument](https://rux-lang.dev/docs/learn/default-argument) | give a parameter a default value so callers may leave it out | | 4.6 | [Generic](https://rux-lang.dev/docs/learn/generic) | write one function that works for many types | | 4.7 | [Callback](https://rux-lang.dev/docs/learn/callback) | pass a function to another function as an ordinary value | ## Before you start Finish [Part 1: Basics](https://rux-lang.dev/docs/learn/basics) and [Part 3: Control flow](https://rux-lang.dev/docs/learn/control-flow) first — the lessons here use `var`, `if` and `for` throughout, and [Part 2: Operators](https://rux-lang.dev/docs/learn/operators) for the arithmetic inside them. Each lesson's package is in the Examples repository's `Functions/` folder: ```sh cd Examples/Functions/Function rux run ``` ## After this part [Part 5: Sequences](https://rux-lang.dev/docs/learn/sequences) passes whole arrays, slices and tuples to the functions you can now write — including functions that take any number of arguments. You are also ready for the checkpoint project [Temperature](https://rux-lang.dev/docs/learn/temperature). For the full rules behind this part, see [Functions](https://rux-lang.dev/docs/lang/functions/declaration), [Function declaration](https://rux-lang.dev/docs/lang/functions/declaration), [Generic functions](https://rux-lang.dev/docs/lang/generics/overview) and [Function type aliases](https://rux-lang.dev/docs/lang/functions/function-types) in the Rux Reference. # Function ::note **You'll need**: [Mutable](https://rux-lang.dev/docs/learn/mutable), [Float](https://rux-lang.dev/docs/learn/float), [For](https://rux-lang.dev/docs/learn/for) :: A function gives a piece of work a name. You write the work once, and then any part of the program can run it by calling that name — with different values each time. `Main` has been a function since the very first lesson; this lesson writes others and calls them from `Main`. Functions are how a program stays readable as it grows. `CelsiusToFahrenheit(100.0)` says what it does, while `100.0 * 9.0 / 5.0 + 32.0` makes you work it out. ## The shape of a function Every function has the same parts: `func`, a name, the parameters in parentheses, `->` and the type of the result, then a body in braces that hands the result back with `return`: ```rux func Add(left: int, right: int) -> int { return left + right; } ``` | Part | In `Add` | Meaning | | ----------- | -------------------------- | ------------------------------------------------- | | Name | `Add` | How callers refer to it — PascalCase, like `Main` | | Parameters | `left: int, right: int` | The values the caller must supply, each typed | | Result type | `-> int` | The type of the value the function gives back | | Body | `{ return left + right; }` | The work, ending in `return` | ## Calling a function A call is the name followed by one argument per parameter, in the same order. Each argument becomes the value of its parameter for that one run of the body, and the value after `return` replaces the call: ```mermaid flowchart LR invoke["`Add(2, 3)`"] --> bind["`left = 2`
`right = 3`"] bind --> body["`return left + right;`"] body --> result["the call is
worth `5`"] ``` The result type is whatever the work produces. Here two `float64` values go in and one `float64` comes out: ```rux func Average(first: float64, second: float64) -> float64 { return (first + second) / 2.0; } ``` Arguments must match the parameter types exactly — nothing is converted for you. `Square(2.5)` is refused because `Square` takes an `int` and `2.5` is a `float64`. ## Parameters cannot change Inside the body a parameter behaves like a `let` binding: you can read it, but not assign to it. A function that needs a running value declares a local `var` of its own: ```rux func SumUpTo(last: int) -> int { var total = 0; for i in 1..=last { total += i; } return total; } ``` Each call gets its own fresh `total`, so calling `SumUpTo` twice never mixes the two sums. ## A call is a value Anywhere a value of the result type fits, a call fits too. It can be bound to a name, or passed straight into another call: ```rux let side = Add(4, 5); ``` ```rux PrintLine("Add(Square(3), Square(4)) {}", Add(Square(3), Square(4))); ``` The inner calls run first: `Square(3)` is 9, `Square(4)` is 16, and only then does `Add` run, with 9 and 16 as its arguments. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Functions/Function){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // A function gives a piece of work a name, so it can be written once and run // from as many places as need it. `Main` has been one since the first lesson; // this lesson writes others and calls them from `Main`. // // The shape is always the same: `func`, a name, the parameters in parentheses, // `->` and the type of the result, then a body that hands the result back with // `return`. import Io::PrintLine; // Every parameter is written `name: type`, separated by commas. A call must // supply one argument for each, in the same order. func Add(left: int, right: int) -> int { return left + right; } func Square(value: int) -> int { return value * value; } // The result type is whatever the work produces. Here two `float64` values go // in and one `float64` comes out. func Average(first: float64, second: float64) -> float64 { return (first + second) / 2.0; } func CelsiusToFahrenheit(celsius: float64) -> float64 { return celsius * 9.0 / 5.0 + 32.0; } // Parameters are immutable inside the body, exactly like `let` bindings, so a // running value needs a local `var` of its own. func SumUpTo(last: int) -> int { var total = 0; for i in 1..=last { total += i; } return total; } func Main() -> int { PrintLine("Add(2, 3) {}", Add(2, 3)); PrintLine("Square(7) {}", Square(7)); PrintLine("Average(4.0, 7.0) {}", Average(4.0, 7.0)); PrintLine("CelsiusToFahrenheit(100.0) {}", CelsiusToFahrenheit(100.0)); PrintLine("SumUpTo(10) {}", SumUpTo(10)); // A call is an ordinary value. It can be bound to a name... let side = Add(4, 5); PrintLine("side {}", side); // ...or passed straight into another call. The inner call runs first. PrintLine("Square(Add(1, 2)) {}", Square(Add(1, 2))); PrintLine("Add(Square(3), Square(4)) {}", Add(Square(3), Square(4))); // Arguments must match the parameter types. `Square(2.5)` is rejected, // because `2.5` is a `float64` and `Square` takes an `int` — the value is // not converted for you. And assigning to a parameter inside its function // is an error: // // func Bump(n: int) -> int { n = n + 1; return n; } // error: cannot modify parameter 'n' return 0; } ``` ## Run it ```sh cd Examples/Functions/Function rux run ``` ```text Add(2, 3) 5 Square(7) 49 Average(4.0, 7.0) 5.5 CelsiusToFahrenheit(100.0) 212.0 SumUpTo(10) 55 side 9 Square(Add(1, 2)) 9 Add(Square(3), Square(4)) 25 ``` ## Common mistakes ::mistake **An argument of the wrong type.**:br`Square(2.5)` fails with: ```text error: argument 1 to 'Square' has type 'float64', but parameter 'value' requires 'int' ``` Pass a value of the parameter's type, or convert it with `as` as in [Convert](https://rux-lang.dev/docs/learn/convert). :: ::mistake **Too few or too many arguments.**:br`Add(2)` fails with: ```text error: call to 'Add' expects 2 arguments, but 1 was provided ``` Every parameter needs an argument — until [Default argument](https://rux-lang.dev/docs/learn/default-argument) shows how to make one optional. :: ::mistake **Assigning to a parameter.**:br`func Bump(n: int) -> int { n = n + 1; return n; }` fails with: ```text error: cannot modify parameter 'n' ``` Copy the parameter into a local `var` and change that instead, as `SumUpTo` does with `total`. :: ::mistake **Getting the name's case wrong.**:br Names are case-sensitive: `square(2)` fails with: ```text error: name 'square' is not defined in this scope ``` The compiler suggests `did you mean 'Square'?`. :: ## Try it yourself 1. Write `Cube(value: int) -> int` that returns `value * Square(value)`, and print `Cube(3)`. 2. Write `FahrenheitToCelsius` and check that it turns `212.0` back into `100.0`. 3. Write `Product(last: int) -> int` that multiplies the numbers from 1 to `last`, following the shape of `SumUpTo`. 4. Call `Square(2.5)` and `Add(2)` and read both messages. ## Learn more - [Functions](https://rux-lang.dev/docs/lang/functions/declaration) and [Function declaration](https://rux-lang.dev/docs/lang/functions/declaration) in the Rux Reference - [The Main entry point](https://rux-lang.dev/docs/lang/functions/main) — the function every program starts in - [Return](https://rux-lang.dev/docs/learn/return) — leaving a function early, and functions with no result # Return ::note **You'll need**: [Function](https://rux-lang.dev/docs/learn/function), [If](https://rux-lang.dev/docs/learn/if), [For](https://rux-lang.dev/docs/learn/for) :: `return` does two jobs at once: it hands back the result, and it leaves the function on the spot. Nothing after it runs. That makes it a way to answer **early** — the moment the function knows the answer — instead of carrying a result down to the last line. This lesson also meets functions that have no result at all, the ones you call for what they *do*. ## Answering early Each `if` here answers one case and leaves. By the time the last line runs, the other cases have already been ruled out, so it needs no condition of its own: ```rux func Sign(value: int) -> int { if value > 0 { return 1; } if value < 0 { return -1; } return 0; } ``` The same style turns a set of rules into a straight list. A leap year is decided by three rules, most specific first, and every rule that settles the answer returns at once — no `else` anywhere: ```rux func IsLeapYear(year: int) -> bool { if year % 400 == 0 { return true; } if year % 100 == 0 { return false; } return year % 4 == 0; } ``` ```mermaid flowchart LR y["`year`"] --> a{"divisible
by 400?"} a -- "yes" --> t["`return true`"] a -- "no" --> b{"divisible
by 100?"} b -- "yes" --> f["`return false`"] b -- "no" --> c["`return year % 4 == 0`"] ``` ## Returning from inside a loop `return` inside a loop leaves the loop **and** the function together. The line after the loop runs only when the loop finished without finding anything: ```rux func SmallestDivisor(number: int) -> int { for candidate in 2..number { if number % candidate == 0 { return candidate; } } return number; } ``` | Statement | Leaves | Then runs | | ---------- | -------------------------- | ----------------------------------- | | `continue` | the rest of this iteration | the next iteration | | `break` | the loop | the first line after the loop | | `return` | the loop and the function | the caller, with the returned value | ## Functions with no result Some functions are called for their effect, such as printing. They leave off the `->` and the result type entirely. A bare `return;` still leaves early, and reaching the closing brace is the ordinary way out: ```rux func Countdown(from: int) { if from < 1 { PrintLine("nothing to count"); return; } for i in 0..from { Print("{} ", from - i); } PrintLine("liftoff"); } ``` A function without a result is called as a statement on its own — `Countdown(5);` — because there is no value to bind or print. ## Every path must return A function with a result type has to return a value of that type on every way through its body. The compiler checks this: if `Sign` lost its final `return 0;`, a value of exactly zero would reach the closing brace with nothing to give back, and the function is refused. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Functions/Return){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // `return` does two things at once: it hands back the result, and it leaves // the function on the spot. Nothing after it runs. That makes it a way to // answer early — as soon as the function knows the answer — instead of // carrying a result down to the last line. // // And some functions have no result at all. They are called for what they do, // such as printing, and leave the `->` and the result type off entirely. import Io::{ Print, PrintLine }; // Each `if` answers one case and leaves. By the time the last line is reached, // the earlier cases have been ruled out, so it needs no condition of its own. func Sign(value: int) -> int { if value > 0 { return 1; } if value < 0 { return -1; } return 0; } // A leap year in three rules, most specific first. Every rule that decides the // answer returns at once, so no `else` is needed anywhere. func IsLeapYear(year: int) -> bool { if year % 400 == 0 { return true; } if year % 100 == 0 { return false; } return year % 4 == 0; } // `return` inside a loop leaves the loop and the function together — further // than `break` goes. The line after the loop runs only if nothing was found. func SmallestDivisor(number: int) -> int { for candidate in 2..number { if number % candidate == 0 { return candidate; } } return number; } // No `->`, so no result. A bare `return;` still leaves early; falling off the // closing brace is the ordinary way out. func Countdown(from: int) { if from < 1 { PrintLine("nothing to count"); return; } for i in 0..from { Print("{} ", from - i); } PrintLine("liftoff"); } func Main() -> int { PrintLine("Sign(-4) {} Sign(0) {} Sign(9) {}", Sign(-4), Sign(0), Sign(9)); PrintLine("IsLeapYear(2024) {}", IsLeapYear(2024)); PrintLine("IsLeapYear(1900) {}", IsLeapYear(1900)); PrintLine("IsLeapYear(2000) {}", IsLeapYear(2000)); PrintLine("SmallestDivisor(91) {}", SmallestDivisor(91)); PrintLine("SmallestDivisor(97) {}", SmallestDivisor(97)); // A function without a result is called as a statement on its own. Countdown(5); Countdown(0); // The compiler checks that a function with a result returns one on every // path. Leave out the final `return 0;` in `Sign` and it says: // // error: function 'Sign' must return a value of type 'int' on every // control-flow path // // The opposite mistake, `return 5;` in a function with no `->`, is also // refused: 'return' cannot have a value in a function with no return type. return 0; } ``` ## Run it ```sh cd Examples/Functions/Return rux run ``` ```text Sign(-4) -1 Sign(0) 0 Sign(9) 1 IsLeapYear(2024) true IsLeapYear(1900) false IsLeapYear(2000) true SmallestDivisor(91) 7 SmallestDivisor(97) 97 5 4 3 2 1 liftoff nothing to count ``` ## Common mistakes ::mistake **A path that never returns.**:br Leave out the final `return 0;` in `Sign` and the compiler says: ```text error: function 'Sign' must return a value of type 'int' on every control-flow path ``` Make sure the last line returns something, even when the `if`s above it cover every case you can think of. :: ::mistake **A value in a function with no result.**:br`return 5;` inside `Countdown` fails with: ```text error: 'return' cannot have a value in a function with no return type ``` Either drop the value, or give the function a `->` and a result type. :: ::mistake **Printing a function that has no result.**:br`PrintLine("{}", Countdown(3))` is refused with: ```text error: no matching overload for 'PrintLine' with argument types (char8[..], opaque) ``` `Countdown` returns `()`, the empty type of "no result", which the message spells `opaque` — and there is nothing in it to print. :: ## Try it yourself 1. Write `Max(first: int, second: int) -> int` with one `if` and two `return`s. 2. Write `IsPrime(number: int) -> bool` using `SmallestDivisor`. Remember that numbers below 2 are not prime — answer them first and return early. 3. Delete the final `return 0;` from `Sign` and read the error. 4. Give `Countdown` a second early exit that prints `too many` and returns when `from` is greater than 10. ## Learn more - [Function declaration](https://rux-lang.dev/docs/lang/functions/declaration) in the Rux Reference - [Break](https://rux-lang.dev/docs/learn/break) and [Continue](https://rux-lang.dev/docs/learn/continue) — leaving a loop without leaving the function - [Recursion](https://rux-lang.dev/docs/learn/recursion) — a function whose early return is what stops it # Recursion ::note **You'll need**: [Function](https://rux-lang.dev/docs/learn/function), [Return](https://rux-lang.dev/docs/learn/return) :: A function may call itself. That is *recursion*, and it suits any problem that contains a smaller copy of itself: 5! is 5 × 4!, and 4! is 4 × 3!. Instead of describing the steps of a loop, a recursive function describes how a big answer is built from a smaller one — and trusts the smaller call to do the rest. ## Base case and recursive case Every recursive function has two parts: - The **base case** is small enough to answer directly. It stops the descent. - The **recursive case** calls the same function on a smaller problem and builds its answer from the result. The [For](https://rux-lang.dev/docs/learn/for) lesson built a factorial with a loop. Here is the same definition written recursively — `n <= 1` is the base case, and every other `n` is answered in terms of `n - 1`: ```rux func Factorial(n: int) -> int { if n <= 1 { return 1; } return n * Factorial(n - 1); } ``` `Factorial(4)` cannot finish until `Factorial(3)` has, which waits on `Factorial(2)`, and so on down to the base case. Then the answers travel back up, each call multiplying in its own `n`: ```mermaid flowchart LR f4["`Factorial(4)`
`4 × Factorial(3)`"] --> f3["`Factorial(3)`
`3 × Factorial(2)`"] f3 --> f2["`Factorial(2)`
`2 × Factorial(1)`"] f2 --> f1["`Factorial(1)`
base case"] f1 -. "returns `1`" .-> f2 f2 -. "returns `2`" .-> f3 f3 -. "returns `6`" .-> f4 f4 -. "returns `24`" .-> done["the caller"] ``` ## Shrinking the problem The recursive case does not have to subtract one. Euclid's greatest common divisor swaps in a smaller pair on every call: ```rux func Gcd(first: int, second: int) -> int { if second == 0 { return first; } return Gcd(second, first % second); } ``` | Call | `first % second` | Next call | | ------------- | ---------------- | ------------- | | `Gcd(48, 18)` | 12 | `Gcd(18, 12)` | | `Gcd(18, 12)` | 6 | `Gcd(12, 6)` | | `Gcd(12, 6)` | 0 | `Gcd(6, 0)` | | `Gcd(6, 0)` | — | base case: 6 | The remainder is always smaller than `second`, so the pair keeps shrinking and `second == 0` is always reached. ## Each call has its own variables Every call gets its own `n`, kept safe while the deeper calls run. That is visible when a function does work both before and after its recursive call: ```rux func Descend(n: int) { if n == 0 { Print("| "); return; } Print("{} ", n); Descend(n - 1); Print("{} ", n); } ``` The first `Print` happens on the way down: 4, 3, 2, 1. The second waits until every deeper call has returned, so it happens on the way back up — in reverse order, 1, 2, 3, 4. `Descend(4)` prints `4 3 2 1 | 1 2 3 4`. ## The base case must be reached Every recursive call must move closer to the base case. `Factorial(-3)` is safe only because the test is `n <= 1`; with `n == 1`, the calls would count down past zero and never stop. Each waiting call takes up a little memory on the *stack*, and when the stack is full the program crashes. The compiler cannot catch this for you — it is the one thing to check every time you write a recursive function. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Functions/Recursion){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // A function may call itself. That is recursion, and it suits any problem that // contains a smaller copy of itself: 5! is 5 times 4!, and 4! is 4 times 3!. // // Every recursive function has two parts. The *base case* is small enough to // answer directly and stops the descent. The *recursive case* calls the same // function on a smaller problem and builds its answer from the result. import Io::{ Print, PrintLine }; // The For lesson built a factorial with a loop. This is the same definition // written recursively: `n <= 1` is the base case, and every other `n` is // answered in terms of `n - 1`. func Factorial(n: int) -> int { if n <= 1 { return 1; } return n * Factorial(n - 1); } // Euclid's greatest common divisor. Each call swaps in a smaller pair, and the // pair always shrinks, so the base case `second == 0` is always reached. func Gcd(first: int, second: int) -> int { if second == 0 { return first; } return Gcd(second, first % second); } // Each call has its own `n`, kept while the deeper calls run. The first // `Print` happens on the way down; the second waits until every deeper call // has returned, so it happens on the way back up, in reverse order. func Descend(n: int) { if n == 0 { Print("| "); return; } Print("{} ", n); Descend(n - 1); Print("{} ", n); } func Main() -> int { for i in 1..=6 { PrintLine("Factorial({}) = {}", i, Factorial(i)); } PrintLine("Gcd(48, 18) = {}", Gcd(48, 18)); PrintLine("Gcd(17, 5) = {}", Gcd(17, 5)); Descend(4); PrintLine(); // Watch out for a missing or unreachable base case. `Factorial(-3)` is // safe only because the test is `n <= 1` rather than `n == 1`; with `==` // the calls would count down past zero forever, until the program runs // out of stack space and crashes. Every recursive call must move closer // to the base case. return 0; } ``` ## Run it ```sh cd Examples/Functions/Recursion rux run ``` ```text Factorial(1) = 1 Factorial(2) = 2 Factorial(3) = 6 Factorial(4) = 24 Factorial(5) = 120 Factorial(6) = 720 Gcd(48, 18) = 6 Gcd(17, 5) = 1 4 3 2 1 | 1 2 3 4 ``` ## Common mistakes ::mistake **A base case that can be skipped.**:br A test like `n == 1` is missed by any argument that starts below 1, and the recursion runs until the program crashes. Prefer a test that covers everything at or below the bottom, such as `n <= 1`. :: ::mistake **A recursive call that does not shrink the problem.**:br`return n * Factorial(n);` calls itself with the same argument forever. Each call must pass something strictly closer to the base case. :: ::mistake **Calling yourself but forgetting `return`.**:br Writing `Gcd(second, first % second);` as a bare statement throws the answer away, and the compiler reports: ```text error: function 'Gcd' must return a value of type 'int' on every control-flow path ``` The recursive case has to return what the deeper call gives back. :: ## Try it yourself 1. Write a recursive `Power(base: int, exponent: int) -> int`. What is the base case when `exponent` is 0? 2. Write `SumDigits(number: int) -> int`, so that `SumDigits(1234)` is 10. Use `number % 10` for the last digit and `number / 10` for the rest. 3. Write `Fibonacci(n: int) -> int`, where the first two values are 0 and 1, and print the first ten. 4. Change `n <= 1` to `n == 1` in `Factorial`, call `Factorial(-3)`, and watch what happens. ## Learn more - [Functions](https://rux-lang.dev/docs/lang/functions/declaration) in the Rux Reference - [For](https://rux-lang.dev/docs/learn/for) — the loop version of factorial - [Return](https://rux-lang.dev/docs/learn/return) — the early return that every base case relies on # Overload ::note **You'll need**: [Function](https://rux-lang.dev/docs/learn/function), [Return](https://rux-lang.dev/docs/learn/return), [Character](https://rux-lang.dev/docs/learn/character) :: Several functions may share one name, as long as their parameters differ. At each call the compiler looks at the arguments and picks the version that fits, so the caller writes one name and gets the right behaviour for whatever it passes. A set of functions sharing a name is an *overload set*. You have been using one since the first lesson. `PrintLine` is not a single function but over twenty: one for `int`, one for `float64`, one for `bool`, one for a single character, one taking nothing at all, one taking a format string and values, and more. Writing `PrintLine(x)` has been choosing among them all along. ## Told apart by type Four functions, one name, each taking a different type: ```rux func Describe(value: int) { PrintLine("an integer: {}", value); } func Describe(value: float64) { PrintLine("a number with a fraction: {}", value); } ``` …and two more for `bool` and `char`. Nothing at the call says which one to run — each argument's type decides, which is why the same spelling produces four different messages: ```rux Describe(42); Describe(2.5); Describe(true); Describe('R'); ``` ## Told apart by count Overloads may also differ in how many parameters they take: ```rux func Area(side: int) -> int { return side * side; } func Area(width: int, height: int) -> int { return width * height; } func Area(width: float64, height: float64) -> float64 { return width * height; } ``` `Area(4)` can only mean the square, `Area(4, 5)` the integer rectangle and `Area(1.5, 2.0)` the floating-point one. No call can match more than one of them, so the set is unambiguous. ## How a call is resolved ```mermaid flowchart LR invoke["`Area(4, 5)`"] --> all["Every function
named `Area`"] all --> fit{"Which take this many
arguments, of these types?"} fit -- "exactly one" --> run["That one is called"] fit -- "none" --> err["`error: no matching overload`
`for 'Area' with argument types …`"] ``` The argument types have to fit the parameters as they are. `Area(4, 2.0)` matches nothing: `4` is an `int` and `2.0` a `float64`, and there is no `Area(int, float64)`. Write `Area(4.0, 2.0)` to reach the floating-point version. ## Never by the result Overloading is decided by the parameters, never by the result type. A call does not say what type it wants back, so two functions that differ only in what they return could not be told apart — and the second is refused: ```rux func Half(value: int) -> int { ... } func Half(value: int) -> float64 { ... } ``` When the difference is what comes back, give the functions separate names, such as `Half` and `HalfExact`. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Functions/Overload){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // Several functions may share one name as long as their parameters differ. The // compiler picks one by the arguments at each call, so the caller writes one // name and gets the version that fits. // // This is not new: `PrintLine` has been an overload set since the first lesson. // There is one for `int`, one for `float64`, one for `bool`, one for a single // character, one taking nothing at all, one taking a format string and values, // and more — over twenty in total. Writing `PrintLine(x)` has been choosing // among them all along. import Io::PrintLine; // Four functions, one name, told apart by the type of their argument. func Describe(value: int) { PrintLine("an integer: {}", value); } func Describe(value: float64) { PrintLine("a number with a fraction: {}", value); } func Describe(value: bool) { PrintLine("a truth value: {}", value); } func Describe(value: char) { PrintLine("a character: {}", value); } // Overloads may also differ in how many parameters they take. These are // unambiguous because no call can match more than one. func Area(side: int) -> int { return side * side; } func Area(width: int, height: int) -> int { return width * height; } func Area(width: float64, height: float64) -> float64 { return width * height; } func Main() -> int { // Nothing here says which `Describe` to run. Each argument's type decides, // which is why the same call spelling produces four different messages. Describe(42); Describe(2.5); Describe(true); Describe('R'); // The count of arguments chooses just as well as their types. PrintLine("square {}", Area(4)); PrintLine("rectangle {}", Area(4, 5)); PrintLine("float rectangle {}", Area(1.5, 2.0)); // Overloading is resolved by the parameters, never by the result. Two // functions differing only in what they return could not be told apart // at a call, so the second one is refused: // // func Half(value: int) -> int { ... } // func Half(value: int) -> float64 { ... } // error: function 'Half' has the same parameter signature as an // earlier overload // // Give them separate names when the difference is what comes back. return 0; } ``` ## Run it ```sh cd Examples/Functions/Overload rux run ``` ```text an integer: 42 a number with a fraction: 2.5 a truth value: true a character: R square 16 rectangle 20 float rectangle 3.0 ``` ## Common mistakes ::mistake **Overloads that differ only in their result.**:br The second `Half` above fails with: ```text error: function 'Half' has the same parameter signature as an earlier overload ``` Change the parameters, or use two names. :: ::mistake **Mixing an integer and a float in one call.**:br`Area(4, 2.0)` fails with: ```text error: no matching overload for 'Area' with argument types (int, float64) ``` A literal is not converted to suit an overload — write `4.0`, or add the overload you actually need. :: ## Try it yourself 1. Add `Describe(value: char8[..])` that prints `some text: …`, and call `Describe("hello")`. 2. Add a fourth `Area` that takes one `float64` radius and returns the area of a circle (`3.14159 * radius * radius`). Does `Area(2.0)` reach it, and does `Area(2)` still reach the square? 3. Call `Area(4, 2.0)` and read the error, then fix the call. 4. Write the two `Half` functions from this lesson and see the second one refused. ## Learn more - [Function declaration](https://rux-lang.dev/docs/lang/functions/declaration) in the Rux Reference - [Console](https://rux-lang.dev/docs/learn/console) — the `PrintLine` overloads you have been calling - [Generic](https://rux-lang.dev/docs/learn/generic) — one function for many types, instead of one overload per type # Default argument ::note **You'll need**: [Function](https://rux-lang.dev/docs/learn/function), [Return](https://rux-lang.dev/docs/learn/return), [Character](https://rux-lang.dev/docs/learn/character) :: Some arguments are nearly always the same. Squaring is the usual power; 0 to 100 is the usual range. A *default value* lets the common call leave that argument out, while the unusual call can still say exactly what it wants. You write it after the parameter's type: `name: type = value`. ## One optional parameter `exponent` has a default, so a call may stop after `base`: ```rux func Power(base: int, exponent: int = 2) -> int { var result = 1; for i in 0..exponent { result *= base; } return result; } ``` `Power(5)` means exactly `Power(5, 2)` — the compiler fills in the missing argument at the call. `Power(2, 10)` passes its own exponent, and the default is not used. ## Arguments fill from the left Several parameters may have defaults: ```rux func Clamp(value: int, low: int = 0, high: int = 100) -> int { ``` Arguments still fill the parameters strictly from the left. A call can stop early, but it cannot skip a parameter in the middle: | Call | `value` | `low` | `high` | Result | | -------------------- | ------- | ----- | ------ | ------ | | `Clamp(150)` | 150 | 0 | 100 | 100 | | `Clamp(-5)` | −5 | 0 | 100 | 0 | | `Clamp(42, 50)` | 42 | 50 | 100 | 50 | | `Clamp(150, 0, 255)` | 150 | 0 | 255 | 150 | The last row is the price of that rule: to change `high`, the call must also give `low`, even when it wants the default there. There is no way to name an argument and skip the ones before it. ## Every parameter optional A default may be any value of the parameter's type — a character as easily as a number. When every parameter has one, a call may pass nothing at all: ```rux func Rule(width: int = 12, mark: char = '-') { for i in 0..width { Print(mark); } PrintLine(); } ``` `Rule()` prints twelve dashes, `Rule(5)` five, and `Rule(5, '=')` five equals signs. ## Defaults come last A parameter without a default may not follow one with a default. In `Mix(first: int = 1, second: int)` there would be no way to supply `second` while leaving `first` out — the first argument always lands in `first` — so the declaration itself is refused. Put the parameters callers usually change first, and the ones they rarely touch at the end. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Functions/DefaultArgument){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // A parameter can carry a default value, written `name: type = value`. A call // may then leave that argument out, and the default is used in its place. // // Defaults suit the argument that is nearly always the same: squaring is the // usual power, 0 to 100 the usual range. The common call stays short, and the // unusual one can still say exactly what it wants. import Io::{ Print, PrintLine }; // `exponent` is optional. `Power(5)` means `Power(5, 2)`. func Power(base: int, exponent: int = 2) -> int { var result = 1; for i in 0..exponent { result *= base; } return result; } // Several parameters may have defaults. Arguments still fill the parameters // from the left, so a call can stop early but cannot skip one in the middle. func Clamp(value: int, low: int = 0, high: int = 100) -> int { if value < low { return low; } if value > high { return high; } return value; } // A default may be any value of the parameter's type, a character as easily as // a number. Every parameter here has one, so a call may pass nothing at all. func Rule(width: int = 12, mark: char = '-') { for i in 0..width { Print(mark); } PrintLine(); } func Main() -> int { PrintLine("Power(5) {}", Power(5)); PrintLine("Power(2, 10) {}", Power(2, 10)); PrintLine("Clamp(150) {}", Clamp(150)); PrintLine("Clamp(-5) {}", Clamp(-5)); PrintLine("Clamp(42, 50) {}", Clamp(42, 50)); // To change `high` the call must also give `low`, even when it wants the // default there. There is no way to name an argument and skip the rest. PrintLine("Clamp(150, 0, 255) {}", Clamp(150, 0, 255)); Rule(); Rule(5); Rule(5, '='); // A parameter without a default may not come after one with a default, // because there would be no way to reach it while leaving the earlier one // out: // // func Mix(first: int = 1, second: int) -> int { ... } // error: parameter 'second' without a default value cannot follow // a parameter with a default value return 0; } ``` ## Run it ```sh cd Examples/Functions/DefaultArgument rux run ``` ```text Power(5) 25 Power(2, 10) 1024 Clamp(150) 100 Clamp(-5) 0 Clamp(42, 50) 50 Clamp(150, 0, 255) 150 ------------ ----- ===== ``` ## Common mistakes ::mistake **A required parameter after an optional one.**:br`func Mix(first: int = 1, second: int)` fails with: ```text error: parameter 'second' without a default value cannot follow a parameter with a default value ``` Move the parameters with defaults to the end. :: ::mistake **Naming an argument to skip ahead.**:br Rux has no named arguments, so `Clamp(150, high: 255)` is a syntax error: ```text expected ',' between arguments before ':' ``` Pass every argument up to the one you want to change. :: ::mistake **A default of the wrong type.**:br`exponent: int = 2.5` fails with: ```text error: default value type 'float64' does not match parameter type 'int' ``` The default is checked against the parameter's type like any other value. :: ## Try it yourself 1. Write `Greet(name: char8[..] = "world")` that prints `Hello, …!`, and call it with and without a name. 2. Predict what `Clamp(150, 255)` returns, then run it. Which parameter did `255` land in? 3. Swap the parameters of `Rule` so that `mark` comes first and only `width` has a default. Which calls in `Main` still compile? 4. Write the `Mix` function from this lesson and read the error. ## Learn more - [Default arguments](https://rux-lang.dev/docs/lang/functions/declaration) in the Rux Reference - [Overload](https://rux-lang.dev/docs/learn/overload) — the other way to let one name take different numbers of arguments - [Variadic](https://rux-lang.dev/docs/learn/variadic) — a function that takes any number of arguments # Generic ::note **You'll need**: [Overload](https://rux-lang.dev/docs/learn/overload), [Convert](https://rux-lang.dev/docs/learn/convert) :: The [Overload](https://rux-lang.dev/docs/learn/overload) lesson wrote one function per type: an `Area` for `int` and another for `float64`, with the same body. That works, but every new type means another copy. A *generic* function writes the body once, with a placeholder where the type goes. ## A type parameter A name in angle brackets after the function name is a **type parameter**. It stands for a type the caller supplies: ```rux func Larger(first: T, second: T) -> T { if first > second { return first; } return second; } ``` Read it as "for some type `T`, take two `T`s and give back a `T`". Both arguments must be the same type, and the result is that type too — two `int` values give back an `int`, two `float64` values a `float64`. Nothing is converted at run time. The compiler produces a separate version of the function for each type that is actually used, as if you had written the overloads by hand: ```mermaid flowchart LR g["`Larger`, generic over `T`"] --> i["`Larger` for `int`
`Larger(3, 9)`"] g --> f["`Larger` for `float64`
`Larger(2.5, 1.5)`"] g --> c["`Larger` for `char`
`Larger('a', 'z')`"] ``` A body that does nothing with its values except pass them along accepts any type at all — even text: ```rux func Pick(useFirst: bool, first: T, second: T) -> T { ``` ## Inferred or explicit Usually `T` is inferred from the arguments, so a call looks like any other: ```rux PrintLine("Larger(3, 9) {}", Larger(3, 9)); ``` You can also give `T` yourself, in angle brackets at the call. That matters when the arguments alone would choose a different type. Bare literals become `int`, but with `` they become `uint8` — and so does the result, which is why adding 100 wraps around past 255 to 44: ```rux PrintLine("Larger(200, 7) + 100 {}", Larger(200, 7) + 100); PrintLine("Larger(200, 7) + 100 {}", Larger(200, 7) + 100); ``` ## What T is allowed to do `Larger` uses `>` on a `T` it knows nothing about. That is checked once `T` is known, for each version the program asks for. Numbers, characters and booleans all have `>`, so those versions compile. A string does not, so `Larger("abc", "abd")` is rejected — with a note naming the call that asked for that version. The same reasoning stops a generic function from printing its value. `PrintLine("{}", first)` inside `Larger` is refused, because `{}` needs a type known to be printable and an unconstrained `T` promises nothing. That is why each function here returns its value for `Main` to print. A *bound* such as `` is how `T` makes that promise; it is taught in [Generic bound](https://rux-lang.dev/docs/learn/generic-bound). ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Functions/Generic){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // The Overload lesson wrote one function per type: an `Area` for `int` and // another for `float64`, with the same body. A generic function writes that // body once. // // A name in angle brackets after the function name is a type parameter. It // stands for a type the caller supplies, and the compiler produces a separate // version of the function for each type actually used. import Io::PrintLine; // Both arguments must be the same type `T`, and the result is that type too, // so two `int` values give back an `int` and two `float64` values a `float64`. func Larger(first: T, second: T) -> T { if first > second { return first; } return second; } // Nothing in this body depends on what `T` can do, so it accepts any type. func Pick(useFirst: bool, first: T, second: T) -> T { if useFirst { return first; } return second; } func Main() -> int { // Usually `T` is inferred from the arguments. Four types and no conversion // anywhere: each type used compiles its own version of the function. PrintLine("Larger(3, 9) {}", Larger(3, 9)); PrintLine("Larger(2.5, 1.5) {}", Larger(2.5, 1.5)); PrintLine("Larger('a', 'z') {}", Larger('a', 'z')); PrintLine("Pick(true, \"yes\", \"no\") {}", Pick(true, "yes", "no")); // `T` can also be given explicitly in angle brackets at the call. That // matters when the arguments alone would choose a different type. Bare // literals become `int`, but with `` they become `uint8`, and so // does the result — which is why adding 100 wraps around here. PrintLine("Larger(200, 7) + 100 {}", Larger(200, 7) + 100); PrintLine("Larger(200, 7) + 100 {}", Larger(200, 7) + 100); // `Larger` uses `>` on a `T` it knows nothing about. That is checked once // `T` is known: calling `Larger` with a type that has no `>` is rejected // when that version of `Larger` is compiled. // // Watch out: a function with an unconstrained `T` cannot print its value. // `PrintLine("{}", first)` inside `Larger` is refused, because `{}` needs // a type known to be printable and `T` promises nothing. That is why each // function here returns its value for `Main` to print. A bound such as // ``, taught in the Generics part, is how `T` makes that promise. return 0; } ``` ## Run it ```sh cd Examples/Functions/Generic rux run ``` ```text Larger(3, 9) 9 Larger(2.5, 1.5) 2.5 Larger('a', 'z') z Pick(true, "yes", "no") yes Larger(200, 7) + 100 300 Larger(200, 7) + 100 44 ``` ## Common mistakes ::mistake **Arguments that disagree about T.**:br`Larger(3, 2.5)` is refused with: ```text error: argument 1 to 'Larger' has type 'int', but parameter 'first' requires 'T' ``` Both parameters are the same `T`, and an `int` and a `float64` cannot both be it. Write `Larger(3.0, 2.5)`. :: ::mistake **A type that cannot do what the body needs.**:br`Larger("abc", "abd")` fails with an error, followed by a note: ```text error: operator '>' is not defined for slice type 'char8[..]' note: in 'Larger' instantiated with T = char8[..] ``` The error points into the generic body; the note tells you which call caused it. :: ::mistake **Printing a T.**:br`PrintLine("{}", value)` inside a generic function fails with: ```text error: no matching overload for 'PrintLine' with argument types (char8[..], T) ``` Return the value and print it where its type is known, or add a bound later in the course. :: ## Try it yourself 1. Write `Smaller` and call it with integers, floats and characters. 2. Write `Clamp(value: T, low: T, high: T) -> T` and call it with `int` and `float64` values. 3. Try `Larger(300, 7)`. Why is `300` refused? 4. Call `Larger("abc", "abd")` and read both the error and its note. ## Learn more - [Generic functions](https://rux-lang.dev/docs/lang/generics/overview) in the Rux Reference - [Overload](https://rux-lang.dev/docs/learn/overload) — the hand-written alternative - [Generic bound](https://rux-lang.dev/docs/learn/generic-bound) — promising what `T` can do, such as being printable - [Wrapping arithmetic](https://rux-lang.dev/docs/learn/wrapping-arithmetic) — why `uint8` 200 + 100 is 44 # Callback ::note **You'll need**: [Function](https://rux-lang.dev/docs/learn/function), [Return](https://rux-lang.dev/docs/learn/return), [For](https://rux-lang.dev/docs/learn/for) :: So far every function has been called by name. Functions are also **values**: one can be stored in a binding, passed to another function, and called from there. A function handed over to be called later is a *callback*. That lets one function be given the part that varies. `ShowTable` below knows how to print a row of results but not what to compute — each caller tells it, by passing a function. ## The type of a function A function's type is its shape: what it takes and what it gives back. It is written like a declaration with the name and parameter names taken out: | Function | Its type | | ------------------------------------ | ---------------------- | | `func Double(value: int32) -> int32` | `func(int32) -> int32` | | `func Square(value: int32) -> int32` | `func(int32) -> int32` | | `func IsEven(value: int32) -> bool` | `func(int32) -> bool` | `Double` and `Square` have different names and different bodies but the same shape, so either fits wherever a `func(int32) -> int32` is wanted. ## Passing a function A parameter can have a function type. `ShowTable` accepts any function with the shape `func(int32) -> int32` and calls it once per number: ```rux func ShowTable(last: int32, operation: func(int32) -> int32) { for i in 1..=last { Print("{} ", operation(i)); } PrintLine(); } ``` At the call, the function is named but **not** called — no parentheses after it: ```rux ShowTable(5, Double); ShowTable(5, Square); ``` ```mermaid flowchart LR main["`Main`
`ShowTable(5, Double)`"] --> st["`ShowTable`
`operation = Double`"] st -- "`operation(1)` … `operation(5)`" --> d["`Double`"] d -- "`2, 4, 6, 8, 10`" --> st ``` A callback can be called more than once, or have its result fed back into itself: ```rux func ApplyTwice(operation: func(int32) -> int32, value: int32) -> int32 { return operation(operation(value)); } ``` And a callback need not compute a number. `CountWhere` takes a *test* — a function returning `bool` — so it can answer any question that can be written as one: ```rux func CountWhere(last: int32, test: func(int32) -> bool) -> int32 { ``` ## A function in a binding A function value can be held in a binding, with its type written out in full. A `var` binding can be pointed at another function later; either way it is called exactly like the function it holds: ```rux var chosen: func(int32) -> int32 = Double; PrintLine("chosen(21) {}", chosen(21)); chosen = Square; PrintLine("chosen(21) {}", chosen(21)); ``` The same call, `chosen(21)`, gives 42 the first time and 441 the second. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Functions/Callback){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // Functions have been called by name all along. They are also values: one can // be stored in a binding, passed to another function, and called from there. // A function handed over to be called later is a *callback*. // // That lets one function be given the part that varies. `ShowTable` below // knows how to print a row of results but not what to compute; each caller // tells it, by passing a function. import Io::{ Print, PrintLine }; func Double(value: int32) -> int32 { return value * 2; } func Square(value: int32) -> int32 { return value * value; } func IsEven(value: int32) -> bool { return value % 2 == 0; } // The parameter's type is the shape of the function: what it takes and what it // gives back. `func(int32) -> int32` accepts any function with exactly that // shape, whatever its name. func ShowTable(last: int32, operation: func(int32) -> int32) { for i in 1..=last { Print("{} ", operation(i)); } PrintLine(); } func ApplyTwice(operation: func(int32) -> int32, value: int32) -> int32 { return operation(operation(value)); } // A function taking a test rather than a value can answer any question that // can be written as one. func CountWhere(last: int32, test: func(int32) -> bool) -> int32 { var found: int32 = 0; for i in 1..=last { if test(i) { found += 1; } } return found; } func Main() -> int { // `Double` is passed, not called — no parentheses after it. `ShowTable` // does the calling, once per number. ShowTable(5, Double); ShowTable(5, Square); PrintLine("ApplyTwice(Double, 3) {}", ApplyTwice(Double, 3)); PrintLine("ApplyTwice(Square, 3) {}", ApplyTwice(Square, 3)); PrintLine("CountWhere(10, IsEven) {}", CountWhere(10, IsEven)); // A function value can be held in a binding, with its type written out in // full. A `var` binding can be pointed at another function later; either // way it is called exactly like the function it holds. var chosen: func(int32) -> int32 = Double; PrintLine("chosen(21) {}", chosen(21)); chosen = Square; PrintLine("chosen(21) {}", chosen(21)); // Watch out: the shape must match exactly. `ShowTable(5, IsEven)` is // refused, because `IsEven` returns `bool`: // // error: argument 2 to 'ShowTable' has type 'func(int32) -> bool8', // but parameter 'operation' requires 'func(int32) -> int32' // // Writing `ShowTable(5, Double(3))` is the other common slip: that calls // `Double` and passes its `int32` result, not the function. return 0; } ``` ## Run it ```sh cd Examples/Functions/Callback rux run ``` ```text 2 4 6 8 10 1 4 9 16 25 ApplyTwice(Double, 3) 12 ApplyTwice(Square, 3) 81 CountWhere(10, IsEven) 5 chosen(21) 42 chosen(21) 441 ``` ## Common mistakes ::mistake **A function of the wrong shape.**:br`ShowTable(5, IsEven)` fails with: ```text error: argument 2 to 'ShowTable' has type 'func(int32) -> bool8', but parameter 'operation' requires 'func(int32) -> int32' ``` The shape must match exactly — `bool8` is the full name of `bool`. The parameter types count too: a `func(int) -> int` does not fit a `func(int32) -> int32` parameter. :: ::mistake **Calling the function instead of passing it.**:br`ShowTable(5, Double(3))` calls `Double` straight away and passes its result, so it fails with: ```text has type 'int32', but parameter 'operation' requires 'func(int32) -> int32' ``` Pass the name alone: `ShowTable(5, Double)`. :: ## Try it yourself 1. Write `Triple` and pass it to `ShowTable` and to `ApplyTwice`. 2. Write `IsMultipleOfThree` and count the multiples of three up to 30 with `CountWhere`. 3. Write `ApplyTimes(operation: func(int32) -> int32, value: int32, times: int32) -> int32` that applies `operation` `times` times in a loop. 4. Call `ShowTable(5, IsEven)` and read the error. ## Learn more - [Function type aliases](https://rux-lang.dev/docs/lang/functions/function-types) in the Rux Reference - [Generic](https://rux-lang.dev/docs/learn/generic) — the other way to give one function a part that varies - [Function field](https://rux-lang.dev/docs/learn/function-field) — storing a function inside a struct # Part 5: Sequences So far every variable has held one value. This part is about holding many: a fixed row of values of one type in an **array**, a view into part of one in a **slice**, and a small group of values of different types in a **tuple**. Along the way you will write functions that accept arrays of any length, change the caller's elements through a view, take any number of arguments, and hand back more than one result. ## What you will learn - Arrays: a fixed count of one element type, stored inline, indexed from zero, copied whole. - Filling an array with one repeated value, `[0; 16]`, and nesting arrays into a grid. - Slices: read-only views, `int32[..]`, that serve arrays of every length without copying. - Writable views, `var int32[..]`, and why a view's writability is separate from its binding. - Variadic functions that collect any number of arguments into a slice, and spreading with `...`. - Tuples for grouping values of different types, and destructuring them into names. ## Which sequence? ```mermaid flowchart LR q{"What are you
holding?"} -- "a fixed number of
values of one type" --> a["Array
`int32[4]`"] a -- "rows of rows" --> n["Nested array
`int32[4][3]`"] a -- "part of it, or any length,
without copying" --> s["Slice
`int32[..]`"] s -- "and change it" --> w["Writable slice
`var int32[..]`"] s -- "as arguments" --> v["Variadic
`args: int32...`"] q -- "a few values of
different types" --> t["Tuple
`(int32, bool)`"] t -- "named in one step" --> d["Destructure
`let (x, y) = …`"] ``` ## Lessons | | Lesson | What you will learn | | --- | ---------------------------------------------------------------- | ---------------------------------------------------------------------------- | | 5.1 | [Array](https://rux-lang.dev/docs/learn/array) | an inline array holding a fixed number of values of one type | | 5.2 | [Array repeat](https://rux-lang.dev/docs/learn/array-repeat) | fill an array with one repeated value: `[0; 16]` | | 5.3 | [Array nested](https://rux-lang.dev/docs/learn/array-nested) | arrays of arrays: a grid with rows and columns | | 5.4 | [Slice](https://rux-lang.dev/docs/learn/slice) | view part of an array without copying it, and pass it to a function | | 5.5 | [Writable slice](https://rux-lang.dev/docs/learn/writable-slice) | change an array through a `var T[..]` view | | 5.6 | [Variadic](https://rux-lang.dev/docs/learn/variadic) | accept any number of arguments, the way `PrintLine` does | | 5.7 | [Tuple](https://rux-lang.dev/docs/learn/tuple) | group a few values without declaring a type, and return more than one result | | 5.8 | [Destructure](https://rux-lang.dev/docs/learn/destructure) | unpack a tuple into separate names with `let (x, y) = ...` | ## Before you start Finish [Part 3: Control flow](https://rux-lang.dev/docs/learn/control-flow) and [Part 4: Functions](https://rux-lang.dev/docs/learn/functions) first — every lesson here walks a sequence with `for` and passes it to functions of its own. [Convert](https://rux-lang.dev/docs/learn/convert) from Part 1 matters too, because lengths and indices are `uint`. Each lesson's package is in the Examples repository's `Sequences/` folder: ```sh cd Examples/Sequences/Array rux run ``` ## After this part [Part 6: Types](https://rux-lang.dev/docs/learn/types) declares types of your own — structs, enums and variants — for the groups of values that deserve names rather than `.0` and `.1`. You are also ready for the checkpoint project [Prime](https://rux-lang.dev/docs/learn/prime). For the full rules behind this part, see [Arrays](https://rux-lang.dev/docs/lang/arrays/overview), [Slices](https://rux-lang.dev/docs/lang/slices/overview), [Ranges](https://rux-lang.dev/docs/lang/ranges/overview), [Variadic functions](https://rux-lang.dev/docs/lang/functions/parameters#variadic-parameters) and [Tuples](https://rux-lang.dev/docs/lang/tuples/overview) in the Rux Reference. # Array ::note **You'll need**: [Mutable](https://rux-lang.dev/docs/learn/mutable), [For](https://rux-lang.dev/docs/learn/for) :: An *array* holds a fixed number of values of one type, side by side. Four primes, twelve monthly totals, the eight squares of a chess row — whenever you have several values of the same kind and know how many, an array keeps them under one name. ## The type says how many `int32[4]` means "four `int32` values": the element type, then the count in square brackets. An array literal lists the elements, also in square brackets: ```rux let primes: int32[4] = [2, 3, 5, 7]; ``` The count is part of the type. An `int32[4]` and an `int32[5]` are different types, and an array never grows or shrinks. The elements live **inline**, right inside the variable — exactly like the bytes of a single integer do. Nothing is allocated, and nothing has to be freed. ## Indexing from zero Elements are numbered from zero, so the last one sits at `length - 1`: | Index | 0 | 1 | 2 | 3 | | ------------- | - | - | - | - | | `primes[...]` | 2 | 3 | 5 | 7 | ```rux PrintLine("first {}, last {}", primes[0], primes[primes.length - 1]); PrintLine("length {}", primes.length); ``` ## Walking an array `for` walks an array element by element, just as it walked a range: ```rux var sum: int32 = 0; for prime in primes { sum += prime; } ``` When the position matters, walk the indices instead. `..` stops before its upper bound, which is exactly the set of valid indices: ```rux for i in 0..primes.length { PrintLine("primes[{}] = {}", i, primes[i]); } ``` ## Changing and copying `let` freezes the elements too. To change one, the array must be `var`: ```rux var scores: int32[3] = [10, 20, 30]; scores[1] = 25; ``` Assigning an array to another variable copies **all** of its elements. The two variables share nothing, so changing the copy leaves the original alone: ```rux var copy = scores; copy[0] = 99; ``` ```mermaid flowchart LR s["`scores`
`10 · 25 · 30`"] -- "`var copy = scores;`" --> c["`copy`
`10 · 25 · 30`"] c -- "`copy[0] = 99;`" --> c2["`copy`
`99 · 25 · 30`"] s -. "unchanged" .-> s2["`scores`
`10 · 25 · 30`"] ``` Two arrays of the same type are equal when every element is, so `scores == copy` is `false` once one element differs. ## Every index is checked An index must be below `length`. A constant index past the end does not compile. An index computed while the program runs is checked as it runs, and one past the end stops the program with `Panic: index out of range` — it never reads the memory beyond the array. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Sequences/Array){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // An array holds a fixed number of values of one type, side by side. `int32[4]` is "four int32 // values": the element type, then the count in square brackets. The count is part of the type, // so an `int32[4]` and an `int32[5]` are different types, and an array never grows or shrinks. // // The elements live inline, right inside the variable, exactly like the bytes of a single // integer do. Nothing is allocated, and copying an array copies every element. import Io::PrintLine; func Main() -> int { // An array literal lists the elements in square brackets. let primes: int32[4] = [2, 3, 5, 7]; // Elements are numbered from zero, so the last one sits at `length - 1`. PrintLine("first {}, last {}", primes[0], primes[primes.length - 1]); PrintLine("length {}", primes.length); // `for` walks an array element by element, just as it walked a range. var sum: int32 = 0; for prime in primes { sum += prime; } PrintLine("sum {}", sum); // When the position matters, walk the indices instead. `..` stops before its upper bound, // which is exactly the set of valid indices. for i in 0..primes.length { PrintLine("primes[{}] = {}", i, primes[i]); } // `let` freezes the elements too. To change one, the array must be `var`. var scores: int32[3] = [10, 20, 30]; scores[1] = 25; // Assigning an array copies all of its elements. Changing the copy leaves the original // alone, because the two variables share nothing. var copy = scores; copy[0] = 99; PrintLine("scores {} {} {}", scores[0], scores[1], scores[2]); PrintLine("copy {} {} {}", copy[0], copy[1], copy[2]); // Two arrays of the same type are equal when every element is. PrintLine("scores == copy {}", scores == copy); // Every index must be below `length`, and it is checked. A constant index past the end, // `primes[7]`, does not compile: // error: index 7 is out of range for an array of 4 elements // An index computed while the program runs is checked as it runs, and one past the end stops // the program with `Panic: index out of range` rather than read memory beyond the array. return 0; } ``` ## Run it ```sh cd Examples/Sequences/Array rux run ``` ```text first 2, last 7 length 4 sum 17 primes[0] = 2 primes[1] = 3 primes[2] = 5 primes[3] = 7 scores 10 25 30 copy 99 25 30 scores == copy false ``` ## Common mistakes ::mistake **Changing an element of a `let` array.**:br`primes[0] = 1;` fails with: ```text error: cannot modify immutable variable 'primes' ``` The compiler suggests declaring it with `var`. :: ::mistake **Counting to `length` inclusive.**:br`for i in 0..=primes.length` visits one index too many. The last pass stops the program with: ```text Panic: index out of range ``` Use `0..primes.length`. With a constant index the compiler catches it first: `primes[7]` fails with: ```text error: index 7 is out of range for an array of 4 elements help: valid indexes are 0 through 3 ``` :: ::mistake **A literal with the wrong number of elements.**:br`let three: int32[4] = [1, 2, 3];` fails with: ```text error: cannot assign 'int[3]' to 'int32[4]' ``` The count is part of the type, so it has to match. :: ::mistake **Printing a whole array.**:br`PrintLine("{}", primes)` is refused — an array is not printable as one value. Print its elements, as the program does. :: ## Try it yourself 1. Find the largest element of `primes` with a `for` loop and a `var`. 2. Print the elements of `primes` in reverse order by walking the indices backwards. 3. Set `copy[0]` back to `10` and print `scores == copy` again. 4. Change `0..primes.length` to `0..=primes.length` and run the program. ## Learn more - [Arrays](https://rux-lang.dev/docs/lang/arrays/overview) and [Indexing and iteration](https://rux-lang.dev/docs/lang/arrays/overview#indexing) in the Rux Reference - [For](https://rux-lang.dev/docs/learn/for) — the loop used to walk arrays - [Array repeat](https://rux-lang.dev/docs/learn/array-repeat) — an array of many equal values without listing them - [Copy](https://rux-lang.dev/docs/learn/copy) — what copying a value means, later in the course # Array repeat ::note **You'll need**: [Array](https://rux-lang.dev/docs/learn/array), [Function](https://rux-lang.dev/docs/learn/function) :: Listing every element works for four values, not for sixteen — and not at all for a thousand. `[value; count]` builds an array of `count` copies of one value: `[0; 16]` is sixteen zeros. This lesson shows the form, its one surprise, and the job it is usually given: starting an array from a clean slate. ## Many copies of one value ```rux let zeros: int32[16] = [0; 16]; ``` Read `[0; 16]` as "zero, sixteen times". The element type comes from the variable — here `int32`, because the variable says `int32[16]` — and the count must match the count in the type. The count must be known **at compile time**, because it becomes part of the array's type. A literal works, and so does a `const`, but a `let` variable does not: its value is only known once the program runs. ## The value is evaluated once The surprise is in how the value is produced. It is evaluated exactly once, and that one result is copied into every element: ```rux let rolls = [Roll(); 4]; ``` `Roll` prints a line every time it is called, and the output shows `Roll called` only **once**. The four elements are always equal, whatever `Roll` returns. ```mermaid flowchart LR r["`Roll()`
called once"] --> v["`4`"] v --> e0["`rolls[0] = 4`"] v --> e1["`rolls[1] = 4`"] v --> e2["`rolls[2] = 4`"] v --> e3["`rolls[3] = 4`"] ``` If you want each element computed on its own, list them — `[Roll(), Roll(), Roll(), Roll()]` makes four calls — or fill the array in a loop. ## A clean slate to fill in The usual reason to repeat a value is to start a `var` array from zero and fill it in afterwards. Here, a tally of the last digit of each number: ```rux var tally: int32[10] = [0; 10]; let numbers: int32[8] = [12, 7, 22, 35, 2, 17, 40, 32]; for number in numbers { tally[number % 10] += 1; } ``` `number % 10` is the last digit, 0 to 9, so it is always a valid index into `tally`. Each element counts how many numbers end in that digit: 12, 22, 2 and 32 all land in `tally[2]`. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Sequences/ArrayRepeat){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // Listing every element works for four values, not for sixteen. `[value; count]` builds an array // of `count` copies of one value: `[0; 16]` is sixteen zeros, of type `int32[16]` when the // variable says so. // // The surprise is in how the value is produced. It is evaluated exactly once, and that one // result is copied into every element. `[Roll(); 4]` calls `Roll` once, not four times, so the // four elements are always equal. import Io::PrintLine; // Prints a line every time it is called, so the output shows how many calls happened. func Roll() -> int32 { PrintLine("Roll called"); return 4; } func Main() -> int { // The count must be known at compile time; the element type comes from the variable. let zeros: int32[16] = [0; 16]; PrintLine("zeros: length {}, first {}, last {}", zeros.length, zeros[0], zeros[15]); // One call, four copies of its result. let rolls = [Roll(); 4]; PrintLine("rolls: {} {} {} {}", rolls[0], rolls[1], rolls[2], rolls[3]); // The usual reason to repeat a value is to start a `var` array from a clean slate and // fill it in afterwards. Here, a tally of the last digit of each number. var tally: int32[10] = [0; 10]; let numbers: int32[8] = [12, 7, 22, 35, 2, 17, 40, 32]; for number in numbers { tally[number % 10] += 1; } for digit in 0..tally.length { if tally[digit] > 0 { PrintLine("ending in {}: {}", digit, tally[digit]); } } return 0; } ``` ## Run it ```sh cd Examples/Sequences/ArrayRepeat rux run ``` ```text zeros: length 16, first 0, last 0 Roll called rolls: 4 4 4 4 ending in 0: 1 ending in 2: 4 ending in 5: 1 ending in 7: 2 ``` ## Common mistakes ::mistake **A count only known at run time.**:br With `let n = 4;`, the literal `[0; n]` fails with: ```text error: array repeat count must be a non-negative compile-time integer ``` Use a literal or a `const`. :: ::mistake **A count that disagrees with the type.**:br`let b: int32[5] = [0; 4];` fails with: ```text error: cannot assign 'int[4]' to 'int32[5]' ``` The repeat count and the type's count have to be the same number. :: ::mistake **Expecting a fresh value per element.**:br`[Roll(); 4]` calls `Roll` once. If each element should be different, list the calls or assign the elements in a loop. :: ## Try it yourself 1. Declare `const Size = 5;` and use it in both places: `var squares: int32[Size] = [0; Size];`. Fill the array with the squares of its indices — they are `uint`, so convert with `as int32`. 2. Replace `[Roll(); 4]` with `[Roll(), Roll(), Roll(), Roll()]` and count the `Roll called` lines. 3. Change the tally to count the remainders of each number divided by 3 instead. 4. Try `[0; n]` with a `let n = 4;` and read the error. ## Learn more - [Arrays](https://rux-lang.dev/docs/lang/arrays/overview) in the Rux Reference - [Const](https://rux-lang.dev/docs/learn/const) — a value known at compile time - [Array nested](https://rux-lang.dev/docs/learn/array-nested) — repeating a whole row to build a grid # Array nested ::note **You'll need**: [Array](https://rux-lang.dev/docs/learn/array), [Array repeat](https://rux-lang.dev/docs/learn/array-repeat) :: An array's element type can be another array, and that is all a two-dimensional array is. A grid of three rows of four numbers is an array of three rows, where each row is an `int32[4]`. Boards, tables, images and spreadsheets all start out this way. ## Built inside out, read outside in The surprise is the order in the type. Each `[n]` wraps everything written before it, so the type is built inside out: ```mermaid flowchart LR e["`int32`
one number"] --> r["`int32[4]`
one row of 4 numbers"] r --> g["`int32[4][3]`
3 of those rows"] ``` Indexing reads the other way, outside in: `grid[row]` picks a row, and `grid[row][column]` picks a number within it. ```rux let grid: int32[4][3] = [ [1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12] ]; ``` | | column 0 | column 1 | column 2 | column 3 | | --------- | -------- | -------- | -------- | -------- | | **row 0** | 1 | 2 | 3 | 4 | | **row 1** | 5 | 6 | 7 | 8 | | **row 2** | 9 | 10 | 11 | 12 | So `grid[2][1]` is row 2, column 1: `10`. The outer `length` counts rows and a row's `length` counts columns: ```rux PrintLine("{} rows of {} columns", grid.length, grid[0].length); ``` ## Walking by rows `for` over the grid yields whole rows, and an inner `for` walks each row: ```rux for row in grid { var sum: int32 = 0; for value in row { sum += value; } PrintLine("row {} {} {} {} adds up to {}", row[0], row[1], row[2], row[3], sum); } ``` `row` is an ordinary `int32[4]`, so it has a `length`, it can be indexed, and it can be walked like any other array. ## Walking by columns There is no "column" value to loop over — columns cut across the rows. Going down a column means holding the column fixed and stepping through the rows by index: ```rux for column in 0..grid[0].length { var total: int32 = 0; for row in 0..grid.length { total += grid[row][column]; } PrintLine("column {} adds up to {}", column, total); } ``` ## Repeating a row A repeated array nests too. `[0; 3]` is a row of three zeros, and `[[0; 3]; 3]` is three copies of that row — a blank board to fill in: ```rux var board: int32[3][3] = [[0; 3]; 3]; for i in 0..board.length { board[i][i] = 1; } ``` Setting `board[i][i]` for each `i` puts a 1 on the diagonal. Because each row is a separate copy, changing one row never touches another. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Sequences/ArrayNested){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // An array's element type can be another array, and that is all a two-dimensional array is. A // grid of three rows of four numbers is an array of three rows, where each row is an `int32[4]`. // // The surprise is the order in the type. Each `[n]` wraps everything written before it, so the // type is built inside out: `int32[4]` is one row, and `int32[4][3]` is three of those rows. // Indexing reads the other way, outside in: `grid[row]` picks a row, and `grid[row][column]` // picks a number within it. import Io::PrintLine; func Main() -> int { // Three rows, each a literal of four numbers. let grid: int32[4][3] = [ [1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12] ]; // The outer length counts rows; a row's length counts columns. PrintLine("{} rows of {} columns", grid.length, grid[0].length); PrintLine("grid[2][1] is {}", grid[2][1]); // `for` over the grid yields whole rows, and an inner `for` walks each row. for row in grid { var sum: int32 = 0; for value in row { sum += value; } PrintLine("row {} {} {} {} adds up to {}", row[0], row[1], row[2], row[3], sum); } // Going down a column means holding the column fixed and stepping through the rows. for column in 0..grid[0].length { var total: int32 = 0; for row in 0..grid.length { total += grid[row][column]; } PrintLine("column {} adds up to {}", column, total); } // A repeated array nests too: three copies of a row of three zeros, filled in afterwards. var board: int32[3][3] = [[0; 3]; 3]; for i in 0..board.length { board[i][i] = 1; } for row in board { PrintLine("{} {} {}", row[0], row[1], row[2]); } return 0; } ``` ## Run it ```sh cd Examples/Sequences/ArrayNested rux run ``` ```text 3 rows of 4 columns grid[2][1] is 10 row 1 2 3 4 adds up to 10 row 5 6 7 8 adds up to 26 row 9 10 11 12 adds up to 42 column 0 adds up to 15 column 1 adds up to 18 column 2 adds up to 21 column 3 adds up to 24 1 0 0 0 1 0 0 0 1 ``` ## Common mistakes ::mistake **Writing the dimensions in reading order.**:br Three rows of four is `int32[4][3]`, not `int32[3][4]`. The wrong order fails with: ```text error: cannot assign 'int[4][3]' to 'int32[3][4]' ``` The message shows the shape the literal really has. :: ::mistake **One index with a comma.**:br`grid[1, 2]` is a syntax error: ```text expected ']' to close the index expression before ',' ``` Each level takes its own brackets: `grid[1][2]`. :: ::mistake **Rows of different lengths.**:br Every row has the same type, so a short row is refused: ```text error: array element 2 has type 'int[3]', but the array's element type is 'int32[4]' ``` :: ## Try it yourself 1. Add up every number in `grid` with two nested `for` loops. 2. Print `grid` with its rows and columns swapped, so that the first line reads `1 5 9`. 3. Build a multiplication table, `var table: int32[10][10] = [[0; 10]; 10];`, and fill it with `(row + 1) * (column + 1)`. The indices are `uint`, so the product needs `as int32`. 4. Change the type of `grid` to `int32[3][4]` and read the error. ## Learn more - [Arrays](https://rux-lang.dev/docs/lang/arrays/overview) and [Indexing and iteration](https://rux-lang.dev/docs/lang/arrays/overview#indexing) in the Rux Reference - [Array repeat](https://rux-lang.dev/docs/learn/array-repeat) — the `[value; count]` form used for `board` - [Slice](https://rux-lang.dev/docs/learn/slice) — passing arrays of any length to one function # Slice ::note **You'll need**: [Array](https://rux-lang.dev/docs/learn/array), [Function](https://rux-lang.dev/docs/learn/function) :: An array's length is part of its type, so a function taking an `int32[5]` accepts arrays of exactly five — no more, no fewer. A *slice*, written `int32[..]`, removes that limit. It is a **view** into an array: where the elements start and how many there are, with no elements of its own. One function taking a slice serves arrays of every size, and making a view copies nothing. ## A view, not a copy A slice is two numbers — a position and a length — pointing into an array that already exists: ```mermaid flowchart LR subgraph numbers["`numbers: int32[5]`"] direction LR n0["`10`"] --- n1["`20`"] --- n2["`30`"] --- n3["`40`"] --- n4["`50`"] end middle["`middle = numbers[1..4]`
starts at `20`, length 3"] -.-> n1 ``` The `..` in `int32[..]` reads as "some number of": the element type is fixed, the count is not. ## One function for every length An array passed where a slice is wanted becomes a view of all of itself: ```rux func Total(values: int32[..]) -> int32 { var sum: int32 = 0; for value in values { sum += value; } return sum; } ``` ```rux PrintLine("numbers {}", Total(numbers)); PrintLine("more {}", Total(more)); ``` `numbers` has five elements and `more` has three, yet both calls reach the same function. Inside it, `values` has a `length`, can be indexed and can be walked with `for`, just like an array. ## Part of an array Indexing with a [range](https://rux-lang.dev/docs/learn/range) gives a view of part of the array. As everywhere else, `..` stops before its upper bound and `..=` includes it, and either end may be left out: | Expression | Elements | Meaning | | ---------------- | -------------- | ----------------------------- | | `numbers[1..4]` | 20, 30, 40 | indices 1 up to, not incl., 4 | | `numbers[1..=4]` | 20, 30, 40, 50 | indices 1 to 4 inclusive | | `numbers[2..]` | 30, 40, 50 | from index 2 to the end | | `numbers[..2]` | 10, 20 | from the start up to 2 | | `numbers[..]` | all five | the whole array | A slice can be sliced again. Its indices count from the start of the **view**, not the array: ```rux let inner = middle[1..]; ``` `middle` starts at 20, so `middle[1..]` starts at 30, and `inner[0]` is 30. ## Strings are slices A string literal has been a slice all along: `char8[..]`, a view of UTF-8 bytes. That is why `.length` counts bytes: ```rux let greeting: char8[..] = "hello"; ``` ## Read-only by default A plain slice can look at the elements but never change them — `Total` cannot write into `values`. Writing through a view is the subject of the next lesson, [Writable slice](https://rux-lang.dev/docs/learn/writable-slice). ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Sequences/Slice){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // An array's length is part of its type, so a function taking an `int32[5]` accepts arrays of // exactly five. A slice, written `int32[..]`, removes that limit. It is a view into an array: a // position and a length, with no elements of its own. One function taking a slice serves arrays // of every size, and making a view copies nothing. import Io::PrintLine; // Every call below reaches this one function, whatever the length of what it is given. func Total(values: int32[..]) -> int32 { var sum: int32 = 0; for value in values { sum += value; } return sum; } func Main() -> int { let numbers: int32[5] = [10, 20, 30, 40, 50]; let more: int32[3] = [1, 2, 3]; // An array passed where a slice is wanted becomes a view of all of itself. PrintLine("numbers {}", Total(numbers)); PrintLine("more {}", Total(more)); // Indexing with a range gives a view of part of the array. As everywhere else, `..` stops // before its upper bound, so this is elements 1, 2 and 3; `..=` would include the end. let middle = numbers[1..4]; PrintLine("numbers[1..4] {} over {} elements", Total(middle), middle.length); PrintLine("numbers[1..=4] {}", Total(numbers[1..=4])); // Either end may be left out, meaning "from the start" or "to the end". PrintLine("numbers[2..] {}", Total(numbers[2..])); PrintLine("numbers[..2] {}", Total(numbers[..2])); // A slice can be sliced again. Its indices count from the start of the view, not the array. let inner = middle[1..]; PrintLine("middle[1..] {}, starting at {}", Total(inner), inner[0]); // A string literal has been a slice all along: `char8[..]`, a view of UTF-8 bytes. let greeting: char8[..] = "hello"; PrintLine("\"{}\" is {} bytes", greeting, greeting.length); return 0; } ``` ## Run it ```sh cd Examples/Sequences/Slice rux run ``` ```text numbers 150 more 6 numbers[1..4] 90 over 3 elements numbers[1..=4] 140 numbers[2..] 120 numbers[..2] 30 middle[1..] 70, starting at 30 "hello" is 5 bytes ``` ## Common mistakes ::mistake **Writing through a read-only slice.**:br`values[0] = 1;` inside `Total` fails with: ```text error: cannot modify elements through read-only slice 'int32[..]' ``` The compiler points to `var T[..]` — see [Writable slice](https://rux-lang.dev/docs/learn/writable-slice). :: ::mistake **A range that runs backwards or past the end.**:br`numbers[3..1]` fails with: ```text error: range start cannot be greater than its end ``` A range past the end, such as `numbers[1..9]`, is checked when the program runs and stops it with: ```text Panic: index out of range ``` :: ::mistake **Comparing two slices with `==`.**:br`a == b` on two `int32[..]` values fails with: ```text error: operator '==' is not defined for slice type 'int32[..]' ``` A slice is a view, so comparing views would compare where they point rather than what they contain. Compare the elements one at a time. :: ## Try it yourself 1. Write `Largest(values: int32[..]) -> int32` and call it with `numbers`, `more` and `numbers[1..3]`. 2. Print `Total(numbers[..])` and check that it matches `Total(numbers)`. 3. Write `CountAbove(values: int32[..], limit: int32) -> int32` that counts the elements greater than `limit`, and call it on `numbers[1..]`. 4. Try `numbers[3..1]` and read the error. ## Learn more - [Slices](https://rux-lang.dev/docs/lang/slices/overview) and [Arrays as slices](https://rux-lang.dev/docs/lang/arrays/overview#arrays-as-slices) in the Rux Reference - [Using ranges](https://rux-lang.dev/docs/lang/ranges/overview#in-a-for-loop) — ranges as loop bounds and slice indices - [String literal](https://rux-lang.dev/docs/learn/string-literal) — more on `char8[..]` # Writable slice ::note **You'll need**: [Slice](https://rux-lang.dev/docs/learn/slice) :: A plain slice, `int32[..]`, is read-only: it can look at the elements but never change them. A *writable slice*, `var int32[..]`, may also write through to the array it views. That is how a function changes the elements of an array it was given — fill it, sort it, scale it — without copying it first. ## Two kinds of view Which kind you get depends on the array you take it from: | Taken from | Example | Type | Can write elements? | | ----------------- | -------------------- | --------------- | ------------------- | | a `var` array | `storage[1..4]` | `var int32[..]` | yes | | a `let` array | `numbers[1..4]` | `int32[..]` | no | | any array, passed | `Show("…", storage)` | `int32[..]` | no | A writable view writes straight into the array behind it: ```rux var storage: int32[5] = [1, 2, 3, 4, 5]; ``` ```rux let view = storage[1..4]; view[0] = 20; ``` `view` starts at index 1 of `storage`, so `view[0] = 20` changes `storage[1]` from 2 to 20. ## A function that changes its argument A function that writes into its argument's elements asks for a writable view: ```rux func Fill(values: var int32[..], value: int32) { for i in 0..values.length { values[i] = value; } } ``` A function that only reads asks for a read-only view — and a writable one is accepted there too, so `Show` takes both. There is one asymmetry. An array becomes a read-only view on its own, but a writable one has to be **asked for** with a range, so that changing the caller's array is always visible at the call: ```rux Fill(storage[3..], 0); ``` `storage[..]` would fill all of it. ## The view and its binding The surprise is that a view's writability has nothing to do with how the view itself is bound. Two separate questions are being answered: ```mermaid flowchart LR b["the binding
`let` or `var`"] -- "can it be pointed
somewhere else?" --> v["the view
`int32[..]` or `var int32[..]`"] v -- "can it change
the elements?" --> a["the array"] ``` `let view = storage[1..4];` is a writable view in an immutable binding: `view[0] = 20` is fine, because it changes the array, but `view = …` is rejected, because it would change the binding. A `var` binding of a read-only view is the reverse — it may move along the array, but never write an element: ```rux var cursor: int32[..] = storage[..2]; PrintLine("cursor starts at {}", cursor[0]); cursor = storage[2..]; ``` | Binding | View | Point it elsewhere? | Write elements? | | ------- | --------------- | ------------------- | --------------- | | `let` | `int32[..]` | no | no | | `let` | `var int32[..]` | no | yes | | `var` | `int32[..]` | yes | no | | `var` | `var int32[..]` | yes | yes | ## Views see later writes A writable view may be stored as a read-only one. Both look at the same array, so the read-only view sees what is written through the other afterwards: ```rux let reader: int32[..] = view; view[1] = 30; PrintLine("reader sees {}", reader[1]); ``` ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Sequences/WritableSlice){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // A plain slice, `int32[..]`, is read-only: it can look at the elements but never change them. // A writable slice, `var int32[..]`, may also write through to the array it views. Taking a // range of a `var` array gives a writable view; taking one of a `let` array gives a read-only // one. // // The surprise is that the view's writability has nothing to do with how the view itself is // bound. `let view = storage[..];` is a writable view held in an immutable binding: `view[0] = 1` // is fine, because it changes the array, while `view = ...` is rejected, because it would change // the binding. A `var` binding of a read-only view is the reverse: it can be pointed somewhere // else, but it can never write an element. import Io::PrintLine; // A function that changes its argument's elements asks for a writable view. func Fill(values: var int32[..], value: int32) { for i in 0..values.length { values[i] = value; } } // A function that only reads asks for a read-only view, and a writable one is accepted too. func Show(label: char8[..], values: int32[..]) { PrintLine("{} {} {} {} {} {}", label, values[0], values[1], values[2], values[3], values[4]); } func Main() -> int { var storage: int32[5] = [1, 2, 3, 4, 5]; Show("start ", storage); // A `let` binding, a writable view. Writing through it writes the array. let view = storage[1..4]; view[0] = 20; Show("view ", storage); // The function writes through its view, so the change shows up in `storage`. An array // becomes a read-only view on its own, but a writable one has to be asked for with a range. // `Fill(storage[..], 0)` would fill all of it, while `Fill(storage, 0)` stops with // error: no matching overload for 'Fill' with argument types (int32[5], int) Fill(storage[3..], 0); Show("filled ", storage); // A `var` binding, a read-only view. It may move along the array, but `cursor[0] = 9` // would be rejected. var cursor: int32[..] = storage[..2]; PrintLine("cursor starts at {}", cursor[0]); cursor = storage[2..]; PrintLine("cursor moved to {}", cursor[0]); // A writable view may be stored as a read-only one, which then sees later writes too. let reader: int32[..] = view; view[1] = 30; PrintLine("reader sees {}", reader[1]); return 0; } ``` ## Run it ```sh cd Examples/Sequences/WritableSlice rux run ``` ```text start 1 2 3 4 5 view 1 20 3 4 5 filled 1 20 3 0 0 cursor starts at 1 cursor moved to 3 reader sees 30 ``` ## Common mistakes ::mistake **Passing the array itself to a writable parameter.**:br`Fill(storage, 0)` fails with: ```text error: no matching overload for 'Fill' with argument types (int32[5], int) ``` An array only becomes a read-only view on its own; write `Fill(storage[..], 0)` to hand over a writable one. :: ::mistake **Taking a writable view of a `let` array.**:br With `let fixed: int32[3] = [1, 2, 3];`, the call `Fill(fixed[..], 0)` fails with: ```text has type 'int32[..]', but parameter 'values' requires 'var int32[..]' ``` A view can never grant more than the array allows. :: ::mistake **Confusing the binding with the view.**:br Even though `cursor` is `var`, `cursor[0] = 9;` fails with: ```text error: cannot modify elements through read-only slice 'int32[..]' ``` And even though `view` can write elements, `view = storage[..2];` fails with: ```text error: cannot modify immutable variable 'view' ``` :: ## Try it yourself 1. Write `Scale(values: var int32[..], factor: int32)` that multiplies every element, and call it on `storage[..]`. 2. Write `Reverse(values: var int32[..])` that swaps elements from both ends towards the middle. 3. Call `Fill(storage, 0)` and read the error, then fix the call. 4. Change `storage` to a `let` array and see which lines stop compiling. ## Learn more - [Slices](https://rux-lang.dev/docs/lang/slices/overview) and [Indexing and iteration](https://rux-lang.dev/docs/lang/slices/overview#indexing-and-iteration) in the Rux Reference - [Mutable](https://rux-lang.dev/docs/learn/mutable) — `let` and `var` bindings - [Mutable reference](https://rux-lang.dev/docs/learn/mutable-reference) — the same "may this change?" question for a single value # Variadic ::note **You'll need**: [Slice](https://rux-lang.dev/docs/learn/slice), [Convert](https://rux-lang.dev/docs/learn/convert) :: Some functions cannot say in advance how many arguments they take. A sum of some numbers, the largest of a few values — the work is the same whether there are two arguments or twenty. A *variadic* function accepts any count, zero included. You have been calling one since the first lesson: `PrintLine` takes a format string and then as many values as it has `{}` placeholders. ## Collecting the rest A last parameter written `args: int32...` collects every remaining argument into one slice: ```rux func Sum(args: int32...) -> int32 { var total: int32 = 0; for value in args { total += value; } return total; } ``` Inside the function, `args` is an ordinary `int32[..]` — the [Slice](https://rux-lang.dev/docs/learn/slice) lesson's read-only view. It has a `length`, it can be indexed, and `for` walks it. So one function serves every count: ```mermaid flowchart LR c3["`Sum(1, 2, 3)`"] --> a3["`args` = view of `1, 2, 3`
length 3"] c1["`Sum(42)`"] --> a1["`args` = view of `42`
length 1"] c0["`Sum()`"] --> a0["`args` = empty view
length 0"] ``` `Sum()` is perfectly valid: the loop simply runs zero times and the total stays 0. ## Ordinary parameters first Ordinary parameters may come before the variadic one; only the last parameter can collect the rest: ```rux func Largest(first: int32, args: int32...) -> int32 { ``` Here `first` is required, so `Largest` needs **at least** one argument — there is always a value to start from — and any more land in `args`. ## Spreading a slice back out Going the other way, `args...` at a call spreads a slice back out into separate arguments. That is how one variadic function hands everything it received to another: ```rux func Average(args: int32...) -> int32 { if args.length == 0 { return 0; } return Sum(args...) / (args.length as int32); } ``` `args.length` is a `uint`, so it is converted with `as` before dividing an `int32` by it. An array can be spread too: it becomes a view of all its elements, just as it does when passed to a slice parameter: ```rux let scores: int32[4] = [70, 85, 90, 95]; PrintLine("Average(scores...) {}", Average(scores...)); ``` | Call | `args` inside `Average` | | -------------------- | ----------------------- | | `Average(2, 4, 9)` | 2, 4, 9 | | `Average(scores...)` | 70, 85, 90, 95 | | `Average()` | empty | ## PrintLine is variadic The `PrintLine` you have been calling with a format string is declared with a variadic parameter of its own — `args: Display...`. `Display` is not one type but a promise, "can be printed", which is why one call can mix an `int`, a `float64` and a string. How such promises work is the subject of [Display](https://rux-lang.dev/docs/learn/display) in the Interfaces part. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Sequences/Variadic){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // Some functions cannot say in advance how many arguments they take. A last parameter written // `args: int32...` collects every remaining argument into one slice, so a single function serves // any count, zero included. Inside the function, `args` is an ordinary `int32[..]`: it has a // length, it can be indexed, and `for` walks it. // // Going the other way, `args...` at a call spreads a slice back out into separate arguments, // which is how one variadic function hands everything it received to another. import Io::PrintLine; func Sum(args: int32...) -> int32 { var total: int32 = 0; for value in args { total += value; } return total; } // Ordinary parameters may come first; only the last one can collect the rest. func Largest(first: int32, args: int32...) -> int32 { var largest = first; for value in args { if value > largest { largest = value; } } return largest; } // `args...` passes what this function was given straight on to `Sum`. func Average(args: int32...) -> int32 { if args.length == 0 { return 0; } return Sum(args...) / (args.length as int32); } func Main() -> int { // The same function with three arguments, with one, and with none at all. PrintLine("Sum(1, 2, 3) {}", Sum(1, 2, 3)); PrintLine("Sum(42) {}", Sum(42)); PrintLine("Sum() {}", Sum()); PrintLine("Largest(4, 9, 2) {}", Largest(4, 9, 2)); PrintLine("Largest(7) {}", Largest(7)); PrintLine("Average(2, 4, 9) {}", Average(2, 4, 9)); // An array can be spread too: it becomes a slice of all its elements, just as it does when // passed to a slice parameter. let scores: int32[4] = [70, 85, 90, 95]; PrintLine("Average(scores...) {}", Average(scores...)); return 0; } ``` ## Run it ```sh cd Examples/Sequences/Variadic rux run ``` ```text Sum(1, 2, 3) 6 Sum(42) 42 Sum() 0 Largest(4, 9, 2) 9 Largest(7) 7 Average(2, 4, 9) 5 Average(scores...) 85 ``` ## Common mistakes ::mistake **Passing an array without spreading it.**:br`Sum(scores)` fails with: ```text error: argument 1 to 'Sum' has type 'int32[4]', but variadic parameter 'args' requires 'int32' ``` Each argument must be one `int32`. Write `Sum(scores...)`. :: ::mistake **Mixing a spread with other arguments.**:br`Sum(1, scores...)` fails with: ```text error: spread argument to 'Sum' must be the only argument for variadic parameter 'args' ``` Either list the values one by one or spread a single slice. :: ::mistake **Leaving out a required parameter.**:br`Largest()` fails with: ```text error: call to 'Largest' expects at least 1 argument, but 0 were provided ``` Only the variadic parameter may receive nothing. :: ## Try it yourself 1. Write `Smallest(first: int32, args: int32...) -> int32`. 2. Write `CountAbove(limit: int32, args: int32...) -> int32` and call it as `CountAbove(80, scores...)`. 3. Print `Sum(scores[1..]...)` — a spread works on any slice, not only a whole array. 4. Call `Sum(scores)` without the `...` and read the error. ## Learn more - [Variadic functions](https://rux-lang.dev/docs/lang/functions/parameters#variadic-parameters) in the Rux Reference - [Indexing and iteration](https://rux-lang.dev/docs/lang/slices/overview#indexing-and-iteration) in the Reference — including spreading a slice into arguments - [Console](https://rux-lang.dev/docs/learn/console) — `PrintLine` and its placeholders # Tuple ::note **You'll need**: [Slice](https://rux-lang.dev/docs/learn/slice), [Return](https://rux-lang.dev/docs/learn/return) :: A *tuple* groups a few values without declaring a type for them first. Its type is the list of its members' types in parentheses — `(int32, bool)` — and a value is written the same way, `(17, true)`. Arrays hold many values of **one** type; a tuple holds a fixed handful of values of **any** types, side by side. ## Writing and reading a tuple The members are reached by position: `.0` is the first, `.1` the second, and so on: ```rux let pair: (int32, float64) = (3, 2.5); PrintLine("pair.0 is {} and pair.1 is {}", pair.0, pair.1); ``` | Collection | Element types | How many | Reached by | | ---------- | ------------- | ------------------ | -------------- | | Array | all the same | fixed, any number | `values[i]` | | Tuple | each its own | fixed, usually few | `pair.0`, `.1` | Like an array, a tuple is a plain value: assigning it copies every member, and `let` freezes the members too. ## Several results from one function The everyday use is returning more than one result. A function has a single return type, and a tuple lets that one type carry several values. `Divide` returns the quotient and whether it means anything — there is no number to return for a division by zero, so the second member says whether the first is real: ```rux func Divide(numerator: int32, denominator: int32) -> (int32, bool) { if denominator == 0 { return (0, false); } return (numerator / denominator, true); } ``` ```mermaid flowchart LR a["`Divide(17, 5)`"] --> ra["`(3, true)`
`.0` is the answer"] b["`Divide(1, 0)`"] --> rb["`(0, false)`
`.0` means nothing"] ``` The caller checks the second member before trusting the first: ```rux let good = Divide(17, 5); if good.1 { PrintLine("17 / 5 is {}", good.0); } ``` The members need not share a type. `Smallest` returns the smallest value, an `int32`, and its position, a `uint`: ```rux func Smallest(values: int32[..]) -> (int32, uint) { ``` ## Comparing tuples Tuples of the same type compare member by member: equal when every member is equal. A tuple literal takes its member types from the other side, just as a lone `3` would: ```rux PrintLine("good == (3, true) {}", good == (3, true)); ``` ## A tuple inside a tuple A member may itself be a tuple. The indexes chain, so `outer.0.1` is the second member of the first member: ```rux let outer: ((int32, int32), char8[..]) = ((3, 4), "point"); PrintLine("{} at {}, {}", outer.1, outer.0.0, outer.0.1); ``` Once a tuple's members need names to be understood — or it has more than two or three of them — it is time for a [struct](https://rux-lang.dev/docs/learn/struct), or at least for the next lesson, [Destructure](https://rux-lang.dev/docs/learn/destructure). ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Sequences/Tuple){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // A tuple groups a few values without declaring a type for them first. Its type is the list of // its members' types in parentheses — `(int32, bool)` — and a value is written the same way, // `(17, true)`. The members are reached by position: `.0` is the first, `.1` the second. // // The everyday use is returning more than one result from a function. A function has a single // return type, and a tuple lets that one type carry several values. import Io::PrintLine; // Two results from one call: the quotient, and whether it means anything. There is no number to // return for a division by zero, so the second member says whether the first is real. func Divide(numerator: int32, denominator: int32) -> (int32, bool) { if denominator == 0 { return (0, false); } return (numerator / denominator, true); } // The members need not share a type. func Smallest(values: int32[..]) -> (int32, uint) { var smallest = values[0]; var position: uint = 0; for i in 1..values.length { if values[i] < smallest { smallest = values[i]; position = i; } } return (smallest, position); } func Main() -> int { // Written out in full: the type, then the value. let pair: (int32, float64) = (3, 2.5); PrintLine("pair.0 is {} and pair.1 is {}", pair.0, pair.1); // Check the second member before trusting the first. let good = Divide(17, 5); if good.1 { PrintLine("17 / 5 is {}", good.0); } let bad = Divide(1, 0); if !bad.1 { PrintLine("1 / 0 has no answer"); } let temperatures: int32[5] = [12, 9, 4, 7, 11]; let coldest = Smallest(temperatures); PrintLine("coldest {} at position {}", coldest.0, coldest.1); // Tuples of the same type compare member by member. The literal `(3, true)` takes its member // types from the other side, just as a lone `3` would. PrintLine("good == (3, true) {}", good == (3, true)); PrintLine("bad == (3, true) {}", bad == (3, true)); // A tuple may hold another tuple. The indexes chain, so `outer.0.1` is the second member of // the first member. let outer: ((int32, int32), char8[..]) = ((3, 4), "point"); PrintLine("{} at {}, {}", outer.1, outer.0.0, outer.0.1); return 0; } ``` ## Run it ```sh cd Examples/Sequences/Tuple rux run ``` ```text pair.0 is 3 and pair.1 is 2.5 17 / 5 is 3 1 / 0 has no answer coldest 4 at position 2 good == (3, true) true bad == (3, true) false point at 3, 4 ``` ## Common mistakes ::mistake **A member that does not exist.**:br`pair.2` fails with: ```text error: tuple index 2 is out of range for a tuple with 2 elements ``` Members count from `.0`, like array indices. :: ::mistake **Comparing tuples of different types.**:br`good == (1, 2)` fails with: ```text error: operator '==' cannot compare left operand '(int32, bool8)' with right operand '(int, int)' ``` It adds the note: ```text two tuples compare as one type ``` Both sides must have the same member types in the same order. :: ::mistake **Returning a bare value from a tuple function.**:br`return (numerator / denominator);` in `Divide` fails with: ```text 'return' value must have type '(int32, bool8)', but found 'int32' ``` Parentheses around one value do not make a tuple — every member must be there. :: ::mistake **Printing a whole tuple.**:br`PrintLine("{}", pair)` is refused, because a tuple is not printable as one value. Print its members. :: ## Try it yourself 1. Write `MinMax(values: int32[..]) -> (int32, int32)` and print both members for `temperatures`. 2. Declare `var point = (1, 2);`, change `point.0`, and print both members. 3. Copy a `var` tuple into a second variable, change the original, and check that the copy kept its old values. 4. Compare `good == (1, 2)` and read the error. ## Learn more - [Tuples](https://rux-lang.dev/docs/lang/tuples/overview) and [Tuples vs. structs](https://rux-lang.dev/docs/lang/tuples/overview#tuples-or-structs) in the Rux Reference - [Destructure](https://rux-lang.dev/docs/learn/destructure) — naming a tuple's members in one step - [Tuple pattern](https://rux-lang.dev/docs/learn/tuple-pattern) — matching on tuples in `match` # Destructure ::note **You'll need**: [Tuple](https://rux-lang.dev/docs/learn/tuple) :: `.0` and `.1` work, but they say nothing about what each member *means*, and a function that uses a tuple's members many times fills up with them. *Destructuring* unpacks a tuple into named bindings in one step: `let (x, y) = pair;` declares `x` from `pair.0` and `y` from `pair.1`. ## One name per member The pattern on the left of `=` mirrors the tuple's shape, with one name per member: ```rux let pair = (3, 4); let (x, y) = pair; ``` It reads best straight off a function that returns several results. Compare `result.0` and `result.1` with names that say what they are: ```rux let (quotient, remainder) = Divide(17, 5); PrintLine("17 / 5 is {} remainder {}", quotient, remainder); ``` ## Skipping a member with `_` `_` stands for a member that is not wanted. `Bounds` returns both the lowest and the highest value, but only the high one is needed here: ```rux let (_, high) = Bounds(readings); ``` The skipped member is not bound to anything, so there is no unused name lying around. ## `var` makes every name mutable `var` in front of the pattern makes every name it declares mutable, just as it does for a single binding: ```rux var (low, top) = Bounds(readings); low -= 1; top += 1; ``` ## Patterns nest A nested pattern unpacks a tuple inside a tuple, all the way down. The pattern has exactly the shape of the value: ```rux let segment = ((0, 0), (6, 8)); let ((x1, y1), (x2, y2)) = segment; ``` ```mermaid flowchart LR v["`((0, 0), (6, 8))`"] --> p["`((x1, y1), (x2, y2))`"] p --> s["`x1 = 0, y1 = 0`
`x2 = 6, y2 = 8`"] ``` ## It only declares Destructuring always declares **new** names. It cannot assign to names that already exist, so the swap other languages write as `(a, b) = (b, a);` is rejected: the left side of `=` has to be a single place, such as a variable or an element. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Sequences/Destructure){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // `.0` and `.1` work, but they say nothing about what each member means, and a function that // uses a tuple's members many times fills up with them. Destructuring unpacks a tuple into named // bindings in one step: `let (x, y) = pair;` declares `x` from `pair.0` and `y` from `pair.1`. // // The pattern on the left mirrors the tuple's shape. It needs one name per member, it may nest // to unpack a tuple inside a tuple, and `_` stands for a member that is not wanted. import Io::PrintLine; func Divide(numerator: int32, denominator: int32) -> (int32, int32) { return (numerator / denominator, numerator % denominator); } func Bounds(values: int32[..]) -> (int32, int32) { var low = values[0]; var high = values[0]; for value in values { if value < low { low = value; } if value > high { high = value; } } return (low, high); } func Main() -> int { // The basic form: one name per member. let pair = (3, 4); let (x, y) = pair; PrintLine("x {} y {}", x, y); // It reads best straight off a function call that returns several results. let (quotient, remainder) = Divide(17, 5); PrintLine("17 / 5 is {} remainder {}", quotient, remainder); // `_` skips a member. Only the high bound is needed here. let readings: int32[6] = [12, 9, 15, 4, 7, 11]; let (_, high) = Bounds(readings); PrintLine("highest reading {}", high); // `var` makes every name mutable, just as it does for a single binding. var (low, top) = Bounds(readings); low -= 1; top += 1; PrintLine("padded range {}..={}", low, top); // A nested pattern unpacks a tuple inside a tuple, all the way down. let segment = ((0, 0), (6, 8)); let ((x1, y1), (x2, y2)) = segment; PrintLine("from {},{} to {},{}", x1, y1, x2, y2); // Destructuring only declares new names. Assigning to existing ones, `(a, b) = (b, a);`, // is rejected: the left side of `=` has to be a single place. return 0; } ``` ## Run it ```sh cd Examples/Sequences/Destructure rux run ``` ```text x 3 y 4 17 / 5 is 3 remainder 2 highest reading 15 padded range 3..=16 from 0,0 to 6,8 ``` ## Common mistakes ::mistake **A pattern of the wrong size.**:br`let (a, b) = (1, 2, 3);` fails with: ```text error: tuple pattern has 2 elements but type '(int, int, int)' has 3 ``` Name every member, or skip the ones you do not need with `_`. :: ::mistake **Destructuring something that is not a tuple.**:br`let (x, y) = 5;` fails with: ```text error: cannot destructure non-tuple type 'int' ``` :: ::mistake **Assigning to existing names.**:br`(a, b) = (b, a);` fails with: ```text error: operator '=' requires an assignable target, but its left operand has type '(int, int)' ``` Assign the names one at a time, through a temporary. :: ::mistake **The same name twice.**:br`let (p, p) = (1, 2);` fails with: ```text error: variable 'p' is already declared in this scope ``` Each name in a pattern is a separate declaration. :: ## Try it yourself 1. Keep only the remainder from `Divide(23, 4)` using `_`. 2. Write `let (year, month, day) = (2026, 10, 5);` and print the date as `2026-10-5`. 3. Swap two `var` variables `a` and `b` using a temporary, then try `(a, b) = (b, a);` and read the error. 4. Write a function that returns `((int32, int32), int32)` — a point and a radius — and unpack it with one nested pattern. ## Learn more - [Destructuring](https://rux-lang.dev/docs/lang/bindings/destructuring) in the Rux Reference - [Tuple](https://rux-lang.dev/docs/learn/tuple) — the values being unpacked - [Tuple pattern](https://rux-lang.dev/docs/learn/tuple-pattern) — the same patterns inside `match` # Part 6: Types Until now every value has had a built-in type — a number, a string, an array, a tuple. This part lets you declare types of your own, shaped to the problem: a `Point` with an `x` and a `y`, a `Direction` that is one of four, a `Command` that carries exactly the data its case needs. By the end you can give those types behaviour of their own and pass them around without copying them. ## What you will learn - Grouping named fields into a `struct`, and building values with a struct literal. - Borrowing a value with `&T` to read it, and with `&var T` to change the caller's value in place. - Giving a type methods in an `extend` block, with a `self` receiver that reads or writes. - Building a valid value in one place with a constructor, and adding methods to types you did not write. - Naming a fixed set of cases with `enum`, and choosing the number behind each case. - Letting each case carry its own data with `variant`, and taking it apart with `match`. - Giving a type a second name with `type`, and storing a function in a field. ## How the ideas fit together ```mermaid flowchart LR s["`struct`
all fields at once"] --> r["`&T` and `&var T`
borrow instead of copy"] r --> m["`extend` + `self`
methods"] m --> c["constructors"] m --> x["extending types
you did not write"] m --> ff["function fields
behaviour as data"] e["`enum`
one of a fixed list"] --> ev["enum values
a number per case"] e --> v["`variant`
one case, with its data"] s --> v v --> vm["`match`
take the data out"] a["type alias
a second name"] ``` Structs are the "and" of types — a point has an `x` **and** a `y`. Enums and variants are the "or" — a direction is north **or** east **or** south **or** west. Most programs need both, and the [Patterns](https://rux-lang.dev/docs/learn/patterns) part that follows is all about taking them apart. ## Lessons | | Lesson | What you will learn | | ---- | ---------------------------------------------------------------------- | -------------------------------------------------------------------- | | 6.1 | [Struct](https://rux-lang.dev/docs/learn/struct) | group related values into a struct with named fields | | 6.2 | [Reference](https://rux-lang.dev/docs/learn/reference) | borrow a value with `&T` instead of copying it | | 6.3 | [Mutable reference](https://rux-lang.dev/docs/learn/mutable-reference) | let a function change the caller's value through `&var T` | | 6.4 | [Method](https://rux-lang.dev/docs/learn/method) | give a struct behaviour with `extend` and a `self` receiver | | 6.5 | [Mutating method](https://rux-lang.dev/docs/learn/mutating-method) | a method that changes its receiver through `self: &var T` | | 6.6 | [Constructor](https://rux-lang.dev/docs/learn/constructor) | build a valid value in one place with a constructor | | 6.7 | [Extension](https://rux-lang.dev/docs/learn/extension) | add methods to a type you did not write | | 6.8 | [Enum](https://rux-lang.dev/docs/learn/enum) | name a fixed set of cases | | 6.9 | [Enum value](https://rux-lang.dev/docs/learn/enum-value) | give an enum an explicit underlying type and convert to and from it | | 6.10 | [Variant](https://rux-lang.dev/docs/learn/variant) | attach data to each case | | 6.11 | [Variant match](https://rux-lang.dev/docs/learn/variant-match) | take a variant apart in a `match` arm | | 6.12 | [Type alias](https://rux-lang.dev/docs/learn/type-alias) | give an existing type a second name to make a signature read clearly | | 6.13 | [Function field](https://rux-lang.dev/docs/learn/function-field) | store a function in a struct field and call it later | ## Before you start Finish Parts 1–5 first. This part leans most on [Part 4: Functions](https://rux-lang.dev/docs/learn/functions) — overloads and callbacks come back as constructors and function fields — and on [Part 5: Sequences](https://rux-lang.dev/docs/learn/sequences), whose tuples, arrays and slices appear as fields, receivers and extended types. `match` from [Part 3: Control flow](https://rux-lang.dev/docs/learn/control-flow) is how enums and variants are read. Each lesson's package is in the Examples repository's `Types/` folder: ```sh cd Examples/Types/Struct rux run ``` ## After this part [Part 7: Patterns](https://rux-lang.dev/docs/learn/patterns) shows everything a `match` arm can say — guards, ranges, tuples and struct patterns — on top of the enums and variants you can now declare. [Part 8: Optionals](https://rux-lang.dev/docs/learn/optionals) and [Part 9: Errors](https://rux-lang.dev/docs/learn/errors) then build on variants' idea of "one of several cases" for values that may be missing and operations that may fail. After Part 9, the checkpoint project [Calculator](https://rux-lang.dev/docs/learn/calculator) puts a variant to work describing what went wrong. For the full rules behind this part, see [Structures](https://rux-lang.dev/docs/lang/structs/overview), [Methods](https://rux-lang.dev/docs/lang/structs/methods), [Enumerations](https://rux-lang.dev/docs/lang/enums/overview), [Variants with data](https://rux-lang.dev/docs/lang/variants/overview) and [Type aliases](https://rux-lang.dev/docs/lang/types/aliases) in the Rux Reference. # Struct ::note **You'll need**: [Tuple](https://rux-lang.dev/docs/learn/tuple), [Function](https://rux-lang.dev/docs/learn/function) :: A [tuple](https://rux-lang.dev/docs/learn/tuple) groups values by position. A **struct** groups them by name, and gives the group a type of its own. A `Point` is not just any two numbers: its `x` cannot be mistaken for its `y` the way `.0` can be mistaken for `.1`, and a function that asks for a `Point` cannot be handed a `(int, int)` that happens to mean something else. This lesson is only about the data — declaring the fields, building a value, reading and writing the fields. Functions that belong to a struct come in [Method](https://rux-lang.dev/docs/learn/method), a few lessons on. ## Declaring a struct A declaration is `struct`, a name, and a list of fields in braces. Each field has a name, a colon, a type and a closing semicolon: ```rux struct Point { x: int; y: int; } ``` A field may have any type, including another struct: ```rux struct Box { corner: Point; width: int; height: int; } ``` The declarations sit at the top level of the file, beside the functions, and from then on `Point` and `Box` are types like `int` or `bool`. | A tuple `(int, int)` | A struct `Point` | | --------------------------------------- | --------------------------------------------- | | Fields are read by position: `.0`, `.1` | Fields are read by name: `.x`, `.y` | | Any two `int`s have the same type | A `Point` is its own type, with its name | | Written on the spot, no declaration | Declared once, then used everywhere | | Good for a quick pair from a function | Good for data that means something on its own | ## Building a value A **struct literal** is the type's name and a value for every field, in braces: ```rux let origin = Point { x: 0, y: 0 }; let corner = Point { y: 2, x: 5 }; ``` Because every value is labelled, the fields may come in any order — `corner` lists `y` first. None may be left out, though: a struct value always has all of its fields, so `Point { x: 1 }` is refused. A field holding a struct takes a struct value, and is read by chaining the dots: ```rux let box = Box { corner: corner, width: 4, height: 3 }; PrintLine("box at ({}, {}), {} by {}", box.corner.x, box.corner.y, box.width, box.height); ``` ## Changing a field A field is assigned like a variable, and the same rule applies: the binding must be a `var`. Under `let` the whole struct is read-only, every field included. ```rux var cursor = Point { x: 1, y: 1 }; cursor.x = 10; cursor.y += 5; ``` ## A struct is a value A struct can be passed to a function and returned from one, like any other value: ```rux func Shifted(point: Point, dx: int, dy: int) -> Point { return Point { x: point.x + dx, y: point.y + dy }; } ``` `Shifted` is handed a **copy** of the point it is called with. It builds a new `Point` and returns that, so the caller's `cursor` comes out exactly as it went in: ```mermaid flowchart LR cursor["`cursor`
`(10, 6)`"] -- "copied in" --> point["`point`
`(10, 6)`"] point -- "builds" --> result["`Point (7, 10)`"] result -- "returned" --> moved["`moved`
`(7, 10)`"] cursor -. "unchanged" .-> after["`cursor`
`(10, 6)`"] ``` For two numbers the copy costs nothing. For a large struct it does, and for a function that *should* change the caller's value a copy is no use at all — the next two lessons, [Reference](https://rux-lang.dev/docs/learn/reference) and [Mutable reference](https://rux-lang.dev/docs/learn/mutable-reference), deal with both. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Types/Struct){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // A tuple groups values by position. A struct groups them by name, and gives the group a type of // its own: a `Point` is not just any two numbers, and its `x` cannot be mistaken for its `y` the // way `.0` can be mistaken for `.1`. // // This lesson is only about the data: declaring the fields, building a value with a struct // literal, and reading and writing the fields. Functions that belong to a struct come a few // lessons later. import Io::PrintLine; // A declaration lists the fields, each with its type and a closing semicolon. struct Point { x: int; y: int; } // A field may have any type, including another struct. struct Box { corner: Point; width: int; height: int; } // A struct is a type like any other, so a function can take one and give one back. func Shifted(point: Point, dx: int, dy: int) -> Point { return Point { x: point.x + dx, y: point.y + dy }; } func Main() -> int { // A struct literal is the type's name and a value for every field. The fields may come in // any order, but none may be left out: `Point { x: 1 }` is rejected for missing `y`. let origin = Point { x: 0, y: 0 }; let corner = Point { y: 2, x: 5 }; PrintLine("origin ({}, {})", origin.x, origin.y); PrintLine("corner ({}, {})", corner.x, corner.y); // A field holding a struct is read by chaining the dots. let box = Box { corner: corner, width: 4, height: 3 }; PrintLine("box at ({}, {}), {} by {}", box.corner.x, box.corner.y, box.width, box.height); // A field is assigned like a variable, and the same rule applies: the binding must be a // `var`. Under `let` the whole struct is read-only, every field included. var cursor = Point { x: 1, y: 1 }; cursor.x = 10; cursor.y += 5; PrintLine("cursor ({}, {})", cursor.x, cursor.y); // `Shifted` was handed a copy of `cursor` and built a new point, so `cursor` is unchanged. let moved = Shifted(cursor, -3, 4); PrintLine("moved ({}, {})", moved.x, moved.y); PrintLine("cursor ({}, {})", cursor.x, cursor.y); return 0; } ``` ## Run it ```sh cd Examples/Types/Struct rux run ``` ```text origin (0, 0) corner (5, 2) box at (5, 2), 4 by 3 cursor (10, 6) moved (7, 10) cursor (10, 6) ``` ## Common mistakes ::mistake **Leaving a field out.**:br`Point { x: 1 }` fails with: ```text error: initializer for 'Point' is missing required field 'y' ``` A struct literal names every field; there are no defaults to fall back on. If building a value takes more than listing its fields, give the type a [constructor](https://rux-lang.dev/docs/learn/constructor). :: ::mistake **Misspelling a field.**:br`Point { x: 1, y: 2, z: 3 }` fails with: ```text error: struct 'Point' has no field 'z' ``` A note lists the fields the struct does have. :: ::mistake **Assigning a field of a `let`.**:br With `let p = Point { x: 1, y: 2 };`, the line `p.x = 5;` fails with: ```text error: cannot modify immutable variable 'p' ``` The compiler suggests declaring `p` with `var`. A field is part of its struct, and a `let` struct is read-only all the way through. :: ::mistake **Printing a struct with `{}`.**:br`PrintLine("{}", origin)` fails with: ```text error: no matching overload for 'PrintLine' with argument types (char8[..], Point) ``` `{}` knows how to print numbers, text and booleans, not types you declared. Print the fields one by one — or, once you reach [Display](https://rux-lang.dev/docs/learn/display), teach the type to print itself. :: ## Try it yourself 1. Write `func Mirrored(point: Point) -> Point` that swaps `x` and `y`, and print `Mirrored(corner)`. 2. Write `func Area(box: Box) -> int` and print the area of `box`. 3. Declare a `Line` struct with two `Point` fields, `start` and `end`, build one, and print all four numbers with chained dots. 4. Change `var cursor` to `let cursor` and read the errors on the two assignments. ## Learn more - [Structures](https://rux-lang.dev/docs/lang/structs/overview) in the Rux Reference - [Tuples vs structs](https://rux-lang.dev/docs/lang/tuples/overview#tuples-or-structs) — when each one fits - [Reference](https://rux-lang.dev/docs/learn/reference) — passing a struct without copying it - [Struct pattern](https://rux-lang.dev/docs/learn/struct-pattern) — taking a struct apart in a `match` # Reference ::note **You'll need**: [Struct](https://rux-lang.dev/docs/learn/struct) :: Passing a struct to a function, as the [Struct](https://rux-lang.dev/docs/learn/struct) lesson did, hands the function a copy. For two numbers that costs nothing, but a struct can be large, and copying it only so a function can *read* it is wasted work. A **reference**, written `&T`, borrows the caller's value instead. The function reads the original through the reference, and nothing is copied. A plain `&` is read-only: the function may look at the value but not change it, so the caller can lend it out without worrying. ## Borrowing a value The `&` goes in front of the parameter's type: ```rux func Area(room: &Room) -> float64 { return room.width * room.length; } ``` ```mermaid flowchart LR subgraph copy ["`room: Room` — by value"] k1["`kitchen`"] -- "copied" --> r1["`room`
(a second `Room`)"] end subgraph borrow ["`room: &Room` — by reference"] r2["`room`"] -- "refers to" --> k2["`kitchen`
(the only `Room`)"] end ``` Two things keep references light to use: - **The call site writes nothing extra.** `Describe(kitchen)` borrows `kitchen` because the parameter asks for a `&Room`. The function's signature decides, not the caller. - **A reference is followed automatically.** `room.width` reads the field of the borrowed room — there is no separate operator to "go through" the reference first. ## Read-only, and passed on A function that borrows a value may lend it on. `Describe` hands the room it borrowed straight to `Area`: ```rux func Describe(room: &Room) { PrintLine("{}: {} by {} metres, {} square metres", room.name, room.width, room.length, Area(room)); } ``` What it may not do is change it. `room.width = 0.0;` inside `Describe` is refused: a `&Room` is a promise to the caller that their room comes back untouched. Lending for writing is a different kind of reference, `&var`, and the subject of the [next lesson](https://rux-lang.dev/docs/learn/mutable-reference). ## Anything can be borrowed A reference is not only for structs. An array of three floats is worth borrowing too: ```rux func Widest(widths: &float64[3]) -> float64 { var widest = widths[0]; for i in 1..3 { if widths[i] > widest { widest = widths[i]; } } return widest; } ``` Inside, `widths[i]` indexes the caller's array directly, just as `room.width` read the caller's field. ## A reference as a local A reference can also be a local variable — a second name for a value that already exists: ```rux let chosen: &Room = kitchen; PrintLine("chosen: the {}", chosen.name); ``` `chosen` is not a new room. It is another way to reach `kitchen`. | Parameter | What the function gets | Copies the value | Can change the caller's value | What can be passed | | ------------- | --------------------------- | ---------------- | ----------------------------- | ------------------------ | | `room: Room` | its own copy | yes | no | any `Room` value | | `room: &Room` | the caller's value, to read | no | no | a named `Room` to borrow | ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Types/Reference){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // Passing a struct to a function, as the Struct lesson did, hands the function a copy. For two // numbers that costs nothing, but a struct can be large, and copying it only so a function can // read it is wasted work. // // A reference, written `&T`, borrows the caller's value instead. The function reads the original // through the reference and nothing is copied. A plain `&` is read-only: the function may look at // the value but not change it, so the caller can lend it out without worrying. // // Two things keep references light to use. The call site writes nothing extra: `Area(kitchen)` // borrows `kitchen` because the parameter asks for a `&Room`. And a reference is followed // automatically, so `room.width` reads the field of the borrowed room. import Io::PrintLine; struct Room { name: char8[..]; width: float64; length: float64; } func Area(room: &Room) -> float64 { return room.width * room.length; } // A reference can be passed on: `Describe` lends the room it borrowed to `Area`. Assigning through // it is another matter, and `room.width = 0.0;` here would be rejected. func Describe(room: &Room) { PrintLine("{}: {} by {} metres, {} square metres", room.name, room.width, room.length, Area(room)); } // Any type can be borrowed, an array included. func Widest(widths: &float64[3]) -> float64 { var widest = widths[0]; for i in 1..3 { if widths[i] > widest { widest = widths[i]; } } return widest; } func Main() -> int { let kitchen = Room { name: "kitchen", width: 3.5, length: 4.0 }; let hall = Room { name: "hall", width: 1.5, length: 6.0 }; Describe(kitchen); Describe(hall); // A reference can also be a local: a second name for a value that already exists. let chosen: &Room = kitchen; PrintLine("chosen: the {}", chosen.name); let widths: float64[3] = [3.5, 1.5, 2.75]; PrintLine("widest: {} metres", Widest(widths)); // A borrow needs something to borrow from. A struct built on the spot has no name to lend, // so `Area(Room { ... })` stops with // error: argument 1 to 'Area' has type 'Room', but parameter 'room' requires '&Room' // Bind it with `let` first, as above. return 0; } ``` ## Run it ```sh cd Examples/Types/Reference rux run ``` ```text kitchen: 3.5 by 4.0 metres, 14.0 square metres hall: 1.5 by 6.0 metres, 9.0 square metres chosen: the kitchen widest: 3.5 metres ``` ## Common mistakes ::mistake **Borrowing something that has no name.**:br A borrow needs a value to borrow from. `Area(Room { name: "x", width: 1.0, length: 2.0 })` fails with: ```text error: argument 1 to 'Area' has type 'Room', but parameter 'room' requires '&Room' ``` So does passing a plain literal to a `&int` parameter. Bind the value with `let` first, then pass the name. :: ::mistake **Writing through a `&`.**:br`room.width = 0.0;` in a function that takes `room: &Room` fails with: ```text error: cannot modify data through immutable reference '&Room' ``` If the function really must change the caller's value, it needs a `&var Room` — see [Mutable reference](https://rux-lang.dev/docs/learn/mutable-reference). :: ::mistake **Changing a value while a reference to it is in use.**:br With `var kitchen` and `let chosen: &Room = kitchen;`, assigning `kitchen.width = 9.0;` and then reading `chosen.width` fails with: ```text error: cannot modify 'kitchen.width' while it is immutably borrowed ``` The compiler will not let a value change under a reader that is still looking at it. Finish with `chosen` first; once its last use is behind you, `kitchen` is free to change. [Exclusivity](https://rux-lang.dev/docs/learn/exclusivity) covers the rule in full. :: ## Try it yourself 1. Write `func Perimeter(room: &Room) -> float64` and add the perimeter to what `Describe` prints. 2. Write `func Narrowest(widths: &float64[3]) -> float64` next to `Widest`. 3. Add `room.width = 0.0;` to `Describe` and read the error. 4. Call `Area` with a struct literal, read the error, then fix it with a `let`. ## Learn more - [Function declaration](https://rux-lang.dev/docs/lang/functions/declaration) — parameters and return types, in the Rux Reference - [Mutable reference](https://rux-lang.dev/docs/learn/mutable-reference) — lending a value for writing - [Exclusivity](https://rux-lang.dev/docs/learn/exclusivity) — why a borrowed value cannot change under its reader - [Pointer](https://rux-lang.dev/docs/learn/pointer) — the lower-level relative of a reference # Mutable reference ::note **You'll need**: [Reference](https://rux-lang.dev/docs/learn/reference) :: A `&T` reference lets a function look at the caller's value. A `&var T` reference lets it **change** that value: the writes land in the caller's own storage, so the caller sees them as soon as the call returns. Nothing is copied in, and nothing needs to be handed back. This is how a function updates something it was given — a bank balance, a counter, a game's score — without the caller having to write `account = Deposit(account, 50);`. ## Writing through \&var The parameter's type is `&var` and the type being lent: ```rux func Deposit(account: &var Account, amount: int) { account.balance += amount; account.deposits += 1; } ``` As with `&`, the call site writes nothing extra, and the changes are visible right after: ```rux Deposit(alice, 50); Deposit(alice, 25); ``` After those two calls `alice` itself has a balance of 175 and two deposits. ## Both ends have to agree The parameter says `&var`, and the value passed in must be a `var`. A binding declared with `let` was promised never to change, and lending it out for writing would break that promise: ```rux var alice = Account { owner: "Alice", balance: 100, deposits: 0 }; ``` Had `alice` been a `let`, every `Deposit(alice, …)` would be refused. ## Replacing the whole value Assigning to a field changes that field. Assigning to the reference itself replaces the caller's whole value in one step: ```rux func Close(account: &var Account) { account = Account { owner: account.owner, balance: 0, deposits: 0 }; } ``` ## Any type can be lent A `&var` is not only for structs. A plain integer can be lent for writing too: ```rux func Tick(count: &var int) { count += 1; } ``` Three calls to `Tick(visits)` leave `visits` at 3. ## One writer at a time Two *different* accounts may be lent for writing in the same call: ```rux Transfer(alice, bob, 70); ``` The same account twice, `Transfer(alice, alice, 5)`, is refused. Inside `Transfer`, `from` and `to` would be two names for one value, and every write through one would silently change what the other sees. The rule behind this — while something may write a value, nothing else may touch it — is [Exclusivity](https://rux-lang.dev/docs/learn/exclusivity), in the Ownership part. ## Choosing a parameter type You now have three ways to take an argument: | Parameter | What the function gets | Can change the caller's value | The caller passes | | ----------------- | ----------------------------- | ----------------------------- | ------------------- | | `a: Account` | its own copy, read-only | no | any `Account` value | | `a: &Account` | the caller's value, to read | no | a named `Account` | | `a: &var Account` | the caller's value, to change | yes | a `var` `Account` | ```mermaid flowchart LR q1{"Must the function change
the caller's value?"} -- "yes" --> rv["`&var T`"] q1 -- "no" --> q2{"Is `T` large, or is copying it
wasted work?"} q2 -- "yes" --> r["`&T`"] q2 -- "no — a number, a `bool`" --> v["`T`"] ``` ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Types/MutableReference){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // A `&T` reference lets a function look at the caller's value. A `&var T` reference lets it change // that value: the writes land in the caller's own storage, so the caller sees them once the call // returns. Nothing is copied in, and nothing needs to be handed back. // // Both ends have to agree. The parameter says `&var`, and the value passed in must be a `var`. A // binding declared with `let` was promised never to change, and lending it out for writing would // break that promise, so `Deposit(savings, 10)` with a `let savings` is rejected. import Io::PrintLine; struct Account { owner: char8[..]; balance: int; deposits: int; } // Writing a field through the reference changes that field of the caller's account. func Deposit(account: &var Account, amount: int) { account.balance += amount; account.deposits += 1; } // Two different accounts may be borrowed for writing in the same call. The same account twice, // `Transfer(alice, alice, 5)`, is rejected: two writers to one value at once is the kind of // conflict the Ownership part is about. func Transfer(from: &var Account, to: &var Account, amount: int) { from.balance -= amount; to.balance += amount; } // Assigning to the reference itself replaces the caller's whole value in one step. func Close(account: &var Account) { account = Account { owner: account.owner, balance: 0, deposits: 0 }; } // Any type can be lent this way, a plain integer included. func Tick(count: &var int) { count += 1; } func Show(account: &Account) { PrintLine("{}: balance {}, deposits {}", account.owner, account.balance, account.deposits); } func Main() -> int { var alice = Account { owner: "Alice", balance: 100, deposits: 0 }; var bob = Account { owner: "Bob", balance: 20, deposits: 0 }; // As with `&`, the call site writes nothing extra. The changes are visible right after. Deposit(alice, 50); Deposit(alice, 25); Deposit(bob, 5); Show(alice); Show(bob); Transfer(alice, bob, 70); Show(alice); Show(bob); Close(bob); Show(bob); var visits = 0; Tick(visits); Tick(visits); Tick(visits); PrintLine("visits: {}", visits); return 0; } ``` ## Run it ```sh cd Examples/Types/MutableReference rux run ``` ```text Alice: balance 175, deposits 2 Bob: balance 25, deposits 1 Alice: balance 105, deposits 2 Bob: balance 95, deposits 1 Bob: balance 0, deposits 0 visits: 3 ``` ## Common mistakes ::mistake **Lending a `let` for writing.**:br With `let savings = Account { … };`, the call `Deposit(savings, 10)` fails with: ```text error: argument 1 to 'Deposit' cannot borrow immutable 'savings' as '&var Account' ``` The compiler suggests declaring `savings` with `var`. :: ::mistake **Changing a by-value parameter.**:br`func Tick(count: int) { count += 1; }` fails with: ```text error: cannot modify parameter 'count' ``` A parameter is read-only, and even if it were not, it would be the function's own copy — the caller would never see the change. The compiler's help says it: take `count` as `&var int` to change the caller's value. :: ::mistake **Lending one value twice.**:br`Transfer(alice, alice, 5)` fails with: ```text error: call arguments create overlapping exclusive borrows of 'alice' ``` Each `&var` argument must be a different value. :: ::mistake **Passing a literal to `&var`.**:br`Tick(5)` fails with: ```text error: argument 1 to 'Tick' has type 'int', but parameter 'count' requires '&var int' ``` There is nowhere for the change to land: a `&var` needs a variable to write into. :: ## Try it yourself 1. Write `func Withdraw(account: &var Account, amount: int) -> bool` that refuses (returns `false`) when the balance is too small, and try it on both accounts. 2. Declare `var counts: int[3] = [0, 0, 0];` and call `Tick(counts[1])` twice, then print the three elements. An array element is a place, so it can be lent for writing too. 3. Change `var bob` to `let bob` and read the errors. 4. Write `func Swap(a: &var int, b: &var int)` and use it to swap two variables. Give the temporary its type, `let saved: int = a;` — written as plain `let saved = a;`, it would be one more reference to `a` rather than a copy of its number, and the compiler would refuse the swap. ## Learn more - [Reference](https://rux-lang.dev/docs/learn/reference) — the read-only kind - [Mutating method](https://rux-lang.dev/docs/learn/mutating-method) — a method that changes the value it is called on - [Exclusivity](https://rux-lang.dev/docs/learn/exclusivity) — why one value cannot be lent for writing twice - [Out parameter](https://rux-lang.dev/docs/learn/out-parameter) — the same idea with pointers # Method ::note **You'll need**: [Struct](https://rux-lang.dev/docs/learn/struct), [Reference](https://rux-lang.dev/docs/learn/reference) :: So far a function that works on a struct stands on its own and is handed the struct: `Area(card)`. A **method** is a function that belongs to a type and is called on a value of it: `card.Area()`. The value comes first, so the reader sees at once what is being asked about — and the type's behaviour is gathered in one place instead of scattered among free functions. ## The extend block Methods are declared in an `extend` block, apart from the struct. The struct stays a plain list of fields; the `extend` block holds what the type can do: ```rux struct Rectangle { width: float64; height: float64; } extend Rectangle { func Area(self: &Rectangle) -> float64 { return self.width * self.height; } } ``` ## The self receiver The value a method works on is its first parameter, called the **receiver**. It is always named `self`, and its type is written out like any other parameter's. `self: &Rectangle` is the read-only reference from the [Reference](https://rux-lang.dev/docs/learn/reference) lesson, so these methods may read the rectangle but not change it. Inside a method, fields are always reached through `self`. `self` is an ordinary parameter, not an implied scope — a bare `width` would be an unknown name. ## Calling a method The value before the dot becomes `self`, borrowed just as an argument would be. The remaining arguments go in the parentheses: ```rux PrintLine("card in envelope {}", card.FitsInside(envelope)); ``` ```mermaid flowchart LR invoke["`card.FitsInside(envelope)`"] --> self["`self = card`
(borrowed as `&Rectangle`)"] invoke --> other["`other = envelope`"] self --> body["body of `Rectangle`'s `FitsInside`"] other --> body ``` That call matches the declaration parameter for parameter — `self` first, then `other`: ```rux func FitsInside(self: &Rectangle, other: &Rectangle) -> bool { return self.width <= other.width && self.height <= other.height; } ``` ## Same name, different types Each type has its own methods. `Circle` can have an `Area` of its own without clashing with the one on `Rectangle`: ```rux extend Circle { func Area(self: &Circle) -> float64 { return 3.14159 * self.radius * self.radius; } } ``` Which one runs is decided by the value before the dot: `card.Area()` runs the rectangle's, `coin.Area()` the circle's. Two free functions named `Area` would have to be told apart by their parameter types, as [overloading](https://rux-lang.dev/docs/learn/overload) does; methods simply live with their type. | Free function | Method | | --------------------------------------- | ----------------------------------------- | | `func Area(card: &Rectangle)` | `func Area(self: &Rectangle)` in `extend` | | Called as `Area(card)` | Called as `card.Area()` | | Lives among all the package's functions | Lives with its type | ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Types/Method){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // So far a function that works on a struct stands on its own and is handed the struct: // `Area(card)`. A method is a function that belongs to a type and is called on a value of it: // `card.Area()`. The value comes first, and the reader sees at once what is being asked about. // // Methods are declared in an `extend` block, apart from the struct, which stays a plain list of // fields. The value a method works on is its first parameter, which is always named `self` and // has its type written out like any other parameter. `self: &Rectangle` is the read-only // reference from the Reference lesson, so these methods may read the rectangle but not change it. import Io::PrintLine; struct Rectangle { width: float64; height: float64; } extend Rectangle { // Inside a method, fields are always reached through `self`. A bare `width` would be an // unknown name: `self` is an ordinary parameter, not an implied scope. func Area(self: &Rectangle) -> float64 { return self.width * self.height; } func IsSquare(self: &Rectangle) -> bool { return self.width == self.height; } // Further parameters come after `self`. func FitsInside(self: &Rectangle, other: &Rectangle) -> bool { return self.width <= other.width && self.height <= other.height; } } struct Circle { radius: float64; } // Each type has its own methods, so `Circle` can have an `Area` of its own without clashing with // the one on `Rectangle`. Which one runs is decided by the value before the dot. extend Circle { func Area(self: &Circle) -> float64 { return 3.14159 * self.radius * self.radius; } } func Main() -> int { let card = Rectangle { width: 9.0, height: 6.0 }; let envelope = Rectangle { width: 11.0, height: 11.0 }; let coin = Circle { radius: 1.25 }; // The value before the dot becomes `self`, borrowed just as an argument would be. PrintLine("card area {}", card.Area()); PrintLine("envelope area {}", envelope.Area()); PrintLine("coin area {:.2}", coin.Area()); PrintLine("card square {}", card.IsSquare()); PrintLine("envelope square {}", envelope.IsSquare()); // The remaining arguments go in the parentheses, as for any call. PrintLine("card in envelope {}", card.FitsInside(envelope)); PrintLine("envelope in card {}", envelope.FitsInside(card)); return 0; } ``` ## Run it ```sh cd Examples/Types/Method rux run ``` ```text card area 54.0 envelope area 121.0 coin area 4.91 card square false envelope square true card in envelope true envelope in card false ``` ## Common mistakes ::mistake **Reaching a field without `self`.**:br`return width * self.height;` fails with: ```text error: name 'width' is not defined in this scope ``` Write `self.width`: fields are never in scope by themselves. :: ::mistake **Naming the receiver something else.**:br A first parameter called `this` is not a receiver, just an ordinary parameter. With `func Area(this: &Rectangle)`, the call `card.Area()` fails with: ```text error: call to 'Area' expects 1 argument, but 0 were provided ``` The receiver is always `self`. :: ::mistake **Calling a method like a free function.**:br`Area(card)` fails with: ```text error: name 'Area' is not defined in this scope ``` A method belongs to its type, so it is reached through a value: `card.Area()`. :: ::mistake **Leaving out the parentheses.**:br`card.Area` without `()` is read as a field, and fails with: ```text error: struct 'Rectangle' has no field 'Area' ``` A method is called, even when it takes no further arguments. :: ## Try it yourself 1. Add `func Perimeter(self: &Rectangle) -> float64` and print the card's perimeter. 2. Give `Circle` an `IsLargerThan(self: &Circle, other: &Circle) -> bool` method. 3. Add `func Scaled(self: &Rectangle, factor: float64) -> Rectangle` that returns a new rectangle, and print the area of `card.Scaled(2.0)`. 4. Remove `self.` from one field in `Area` and read the error. ## Learn more - [Methods](https://rux-lang.dev/docs/lang/structs/methods) in the Rux Reference - [Mutating method](https://rux-lang.dev/docs/learn/mutating-method) — a method that changes its receiver - [Extension](https://rux-lang.dev/docs/learn/extension) — adding methods to types you did not write - [Interface](https://rux-lang.dev/docs/learn/interface) — a set of methods that many types share # Mutating method ::note **You'll need**: [Method](https://rux-lang.dev/docs/learn/method), [Mutable reference](https://rux-lang.dev/docs/learn/mutable-reference) :: The methods in the last lesson only looked at their rectangle. A method that **changes** the value it is called on takes `self: &var T` — the writable reference from [Mutable reference](https://rux-lang.dev/docs/learn/mutable-reference). Its writes land in the value before the dot. This is where methods start to pay off. A `Stack` is an array plus a count of how much of it is in use, and the two must change together: ```rux struct Stack { items: int[4]; length: uint; } ``` If every caller updated `items` and `length` by hand, one of them would sooner or later forget the count. With `Push` and `Pop` as the only code that changes them, they stay in step. ## Reading and writing receivers The receiver's type says what a method may do: ```rux func IsEmpty(self: &Stack) -> bool { return self.length == 0; } ``` ```rux func Push(self: &var Stack, value: int) -> bool { if self.IsFull() { return false; } self.items[self.length] = value; self.length += 1; return true; } ``` `IsEmpty` takes `&Stack` and only reads. `Push` takes `&var Stack`, so it may assign `self.items[…]` and `self.length`. A writing method may also return a value — here, whether the push happened, since a full stack has no room left. `Push` calls `self.IsFull()` on its own receiver: a writing method can always use the reading ones. ## How the stack moves `Push` writes at position `length` and then counts the new item; `Pop` uncounts the top item and then reads it. The last value in is the first one out: ```mermaid flowchart LR e["length 0
`[ _ _ _ _ ]`"] -- "`Push(10)`" --> a["length 1
`[ 10 _ _ _ ]`"] a -- "`Push(20)`" --> b["length 2
`[ 10 20 _ _ ]`"] b -- "`Pop()` gives `20`" --> c["length 1
`[ 10 _ _ _ ]`"] ``` `Pop` does not erase the old value — it stays in the array, but past `length` it no longer counts. ## The caller needs a var A writing method needs a `var` to work on, just as assigning a field would: ```rux var stack = Stack { items: [0; 4], length: 0 }; ``` | Method | Receiver | On a `let stack` | On a `var stack` | | ------------------- | ------------ | ---------------- | ---------------- | | `IsEmpty`, `IsFull` | `&Stack` | allowed | allowed | | `Push`, `Pop` | `&var Stack` | refused | allowed | ## A rule the caller keeps `Pop` has a precondition: it is only to be called on a stack that is not empty. The program keeps it by asking first: ```rux while !stack.IsEmpty() { PrintLine("pop {}", stack.Pop()); } ``` Making a method report "there was nothing to pop" in its return type is what [Optionals](https://rux-lang.dev/docs/learn/optionals) are for, a couple of parts on. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Types/MutatingMethod){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // A method that changes the value it is called on takes `self: &var T`, the writable reference // from the MutableReference lesson. Its writes land in the value before the dot. // // This is where methods start to pay off. A `Stack` is an array plus a count of how much of it is // in use, and the two must change together. If every caller updated them by hand, one would // sooner or later forget the count. With `Push` and `Pop` as the only code that changes them, // they stay in step. import Io::PrintLine; struct Stack { items: int[4]; length: uint; } extend Stack { // A reading method still takes `&Stack`, and can be called on any stack. func IsEmpty(self: &Stack) -> bool { return self.length == 0; } func IsFull(self: &Stack) -> bool { return self.length == 4; } // A writing method takes `&var Stack`. It may also return a value: here, whether the push // happened, since a full stack has no room left. func Push(self: &var Stack, value: int) -> bool { if self.IsFull() { return false; } self.items[self.length] = value; self.length += 1; return true; } // Only to be called on a stack that is not empty; the caller checks `IsEmpty` first. func Pop(self: &var Stack) -> int { self.length -= 1; return self.items[self.length]; } } func Main() -> int { // A writing method needs a `var` to work on, just as assigning a field would. Had `stack` // been declared with `let`, every `Push` and `Pop` below would be rejected, while `IsEmpty` // and `IsFull` would still be allowed. var stack = Stack { items: [0; 4], length: 0 }; for value in 1..=5 { let pushed = stack.Push(value * 10); PrintLine("push {} accepted {}", value * 10, pushed); } PrintLine("full {}", stack.IsFull()); while !stack.IsEmpty() { PrintLine("pop {}", stack.Pop()); } PrintLine("empty {}", stack.IsEmpty()); return 0; } ``` ## Run it ```sh cd Examples/Types/MutatingMethod rux run ``` ```text push 10 accepted true push 20 accepted true push 30 accepted true push 40 accepted true push 50 accepted false full true pop 40 pop 30 pop 20 pop 10 empty true ``` ## Common mistakes ::mistake **Calling a writing method on a `let`.**:br With `let stack = …`, the call `stack.Push(1)` fails with: ```text error: cannot call 'Push' on immutable 'stack' ``` A note points out that `Push` declares a writable receiver `&var Stack`, and the help suggests declaring `stack` with `var`. `stack.IsEmpty()` is still fine. :: ::mistake **Writing through a read-only receiver.**:br A `Clear` method declared as `func Clear(self: &Stack)` that assigns `self.length = 0;` fails with: ```text error: cannot modify data through immutable reference '&Stack' ``` :: ::mistake **Taking the receiver by value.**:br`func Clear(self: Stack)` would get a copy, and changing a copy would change nothing. The compiler refuses the write with: ```text error: cannot modify immutable receiver 'self' ``` Its help says what to do: take the receiver as `self: &var Stack` to change the caller's value. :: ::mistake **Popping an empty stack.**:br`Pop` does not check. On an empty stack, `self.length -= 1` takes a `uint` below zero, it wraps round to a huge number, and the read stops the program with: ```text Panic: index out of range ``` Check `IsEmpty` first. :: ## Try it yourself 1. Add `func Peek(self: &Stack) -> int` that returns the top item without removing it. Which receiver does it need? 2. Add `func Clear(self: &var Stack)` and use it to empty a full stack in one call. 3. Change `var stack` to `let stack` and read which lines the compiler refuses — and which it still accepts. 4. Add a `Size(self: &Stack) -> uint` method and print the size after every push. ## Learn more - [Methods](https://rux-lang.dev/docs/lang/structs/methods) in the Rux Reference - [Mutable reference](https://rux-lang.dev/docs/learn/mutable-reference) — the `&var` behind the receiver - [Constructor](https://rux-lang.dev/docs/learn/constructor) — building a valid value in one place - [Optional](https://rux-lang.dev/docs/learn/optional) — a `Pop` that can say "nothing here" # Constructor ::note **You'll need**: [Method](https://rux-lang.dev/docs/learn/method), [Overload](https://rux-lang.dev/docs/learn/overload) :: A struct literal names every field at every place a value is built. That is fine for a `Point`, but some types have rules. A time of day has minutes from 0 to 59, and a literal will happily accept `Time { hours: 7, minutes: 95 }`. A **constructor** is a function that builds the value for you, so the rules are written once instead of at every literal. It is called by the type's name, like a function: `Time(9, 30)`. ## Declaring a constructor A constructor lives in the type's `extend` block, beside its methods, and differs from them in three ways: - it has the **same name as the type**; - it takes **no `self`** — there is no value yet to call it on; - it **returns the type**. ```rux extend Time { func Time(hours: int, minutes: int) -> Time { return Time(hours * 60 + minutes); } // The second constructor and the methods follow. } ``` | Kind of function | Name | First parameter | Called as | | ---------------- | -------------- | ---------------------------- | -------------- | | Method | anything | `self: &Time` or `&var Time` | `start.Show()` | | Constructor | `Time`, always | none | `Time(9, 30)` | ## Constructors overload A type can have several constructors, told apart by their parameters — the [overloading](https://rux-lang.dev/docs/learn/overload) you already know from ordinary functions. This one takes a single count of minutes and does the real work: ```rux func Time(totalMinutes: int) -> Time { let inDay = totalMinutes % (24 * 60); return Time { hours: inDay / 60, minutes: inDay % 60 }; } ``` The two-argument constructor turns its hours and minutes into a total and hands it to this one, so the wrapping is written exactly once: ```mermaid flowchart LR a["`Time(7, 95)`"] -- "`7 × 60 + 95`" --> b["`Time(515)`"] b -- "`515 % 1440 = 515`" --> c["`Time { hours: 8, minutes: 35 }`"] ``` At the end, the struct literal is still how the value is finally made. A constructor does not replace literals; it decides what goes into one. ## Building new values from old ones Since a constructor accepts any count of minutes, "135 minutes later" is just another call: ```rux let later = Time(start.TotalMinutes() + 135); ``` And past midnight the clock wraps, because `% (24 * 60)` keeps the total inside one day. ## A convenience, not a lock The struct literal is still allowed, rules or no rules: `Time { hours: 7, minutes: 95 }` compiles and makes a time that is not a time. A constructor is a convenience the type offers; it does not lock the door. Hiding the fields so the constructor is the only way in is what [Visibility](https://rux-lang.dev/docs/learn/visibility) is about. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Types/Constructor){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // A struct literal names every field at every place a value is built. That is fine for a `Point`, // but some types have rules: a time of day has minutes from 0 to 59, and a literal will happily // accept `Time { hours: 7, minutes: 95 }`. // // A constructor is a function that builds the value for you. It is declared inside the type's // `extend` block, has the same name as the type, takes no `self` (there is no value yet), and // returns the type. It is called by the type's name, like a function: `Time(9, 30)`. import Io::PrintLine; struct Time { hours: int; minutes: int; } extend Time { // The plain form: one argument per field, wrapped round the clock so the fields stay valid. func Time(hours: int, minutes: int) -> Time { return Time(hours * 60 + minutes); } // Constructors overload like any function. This one does real work, splitting a count of // minutes into hours and minutes, which is what the other constructor relies on. The struct // literal is still how the value is finally made. func Time(totalMinutes: int) -> Time { let inDay = totalMinutes % (24 * 60); return Time { hours: inDay / 60, minutes: inDay % 60 }; } func TotalMinutes(self: &Time) -> int { return self.hours * 60 + self.minutes; } func Show(self: &Time) { PrintLine("{:02}:{:02}", self.hours, self.minutes); } } func Main() -> int { let start = Time(9, 30); start.Show(); // Minutes past 59 carry into the hours, which a struct literal would not do. let odd = Time(7, 95); odd.Show(); // Building a new value from an old one is a matter of calling a constructor again. let later = Time(start.TotalMinutes() + 135); later.Show(); // Past midnight, the clock wraps. let overnight = Time(later.TotalMinutes() + 14 * 60); overnight.Show(); // The struct literal is still allowed, rules or no rules. A constructor is a convenience the // type offers; it does not lock the door. Hiding the fields so the constructor is the only // way in is what the Visibility lesson is about. return 0; } ``` ## Run it ```sh cd Examples/Types/Constructor rux run ``` ```text 09:30 08:35 11:45 01:45 ``` ## Common mistakes ::mistake **Calling a type that has no constructor.**:br Without a constructor, `Point(1, 2)` fails with: ```text error: type 'Point' cannot be called because it has no declared constructor ``` The help names both ways out: declare a receiverless constructor in its `extend` block, or build the value with a struct literal. :: ::mistake **Declaring the constructor outside `extend`.**:br A top-level `func Time(…) -> Time` fails with: ```text error: name 'Time' cannot be declared as a function because it is already a type in this scope ``` A constructor belongs inside the type's `extend` block. :: ::mistake **Returning something other than the type.**:br`func Time(hours: int, minutes: int) -> int` in `extend Time` fails with: ```text error: constructor 'Time' must return exactly 'Time' ``` :: ::mistake **No constructor matches the arguments.**:br With only the two-argument constructor declared, `Time(9)` fails with: ```text error: call to 'Time' expects 2 arguments, but 1 was provided ``` Each set of arguments needs a constructor of its own. :: ## Try it yourself 1. Write `Time { hours: 7, minutes: 95 }` as a literal, call `Show` on it, and compare with `Time(7, 95)`. 2. Add a method `func Later(self: &Time, minutes: int) -> Time` that uses a constructor, and print `start.Later(45)`. 3. Add `func Midnight() -> Time` to the `extend` block — no `self`, and a name that is not the type's. Call it as `Time::Midnight()`. 4. Make the one-argument constructor handle a negative count, so that `Time(-30)` shows `23:30`. ## Learn more - [Methods](https://rux-lang.dev/docs/lang/structs/methods) in the Rux Reference - [Overload](https://rux-lang.dev/docs/learn/overload) — several functions with one name - [Visibility](https://rux-lang.dev/docs/learn/visibility) — making the constructor the only way in - [Struct](https://rux-lang.dev/docs/learn/struct) — the struct literal a constructor fills in # Extension ::note **You'll need**: [Method](https://rux-lang.dev/docs/learn/method), [Slice](https://rux-lang.dev/docs/learn/slice) :: `extend` is not only for types you declared yourself. It can add methods to a type you did **not** write — the built-in ones included — and from then on, in this package, every value of that type has them. `42.IsEven()` reads better than `IsEven(42)`, and a slice that can `Sum()` itself saves passing it to a helper every time. ## Extending a built-in type The block looks exactly like the ones in [Method](https://rux-lang.dev/docs/learn/method), with a built-in type's name after `extend`: ```rux extend int { func IsEven(self: int) -> bool { return self % 2 == 0; } // Clamped follows in the same block. } ``` From here on, any `int` can be asked: `answer.IsEven()`, `volume.Clamped(0, 100)`. ## Receivers by value These receivers are taken **by value** — `self: int`, not `self: &int`. A number or a slice is small, and copying it is as cheap as borrowing it. The three receiver forms now on the table: | Receiver | The method gets | Typical for | | -------------- | ----------------------------- | ----------------------------------------- | | `self: T` | a copy | small values: numbers, slices, enum cases | | `self: &T` | the caller's value, to read | structs and arrays that only need reading | | `self: &var T` | the caller's value, to change | methods that update the value | A slice is a view, so even taken by value it still sees the caller's elements — copying the slice copies the view, not the numbers behind it. ## Extending a slice Any type can be extended, compound types included: ```rux extend int[..] { func Sum(self: int[..]) -> int { var total = 0; for value in self { total += value; } return total; } // CountEven follows in the same block. } ``` Inside `CountEven`, the `IsEven` added a few lines earlier is used like any other method: `value.IsEven()`. Extensions build on one another. ## One exact type The extended type must be one exact type, and methods do not spread to its relatives: ```mermaid flowchart LR ext["`extend int[..]`"] --> yes["`int[..]`
has `Sum` and `CountEven`"] ext -. "not" .-> no1["`uint8[..]`"] ext -. "not" .-> no2["`int32[..]`"] ext -. "not" .-> no3["`int[5]`
(an array, not a slice)"] ``` `int32` is not `int`, `uint8[..]` is not `int[..]`, and an array is not a slice. Each would need an `extend` of its own. An array reaches the slice methods through a view of itself: ```rux PrintLine("sum of the last 3: {}", scores[2..].Sum()); ``` The same view, `scores[..]` or the `let all: int[..] = scores;` in the program, gives the whole array. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Types/Extension){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // `extend` is not only for types you declared yourself. It can add methods to a type you did not // write, the built-in ones included, and from then on, in this package, every value of that type // has them. // // The receiver here is taken by value: `self: int`, not `self: &int`. A number or a slice is small, // and copying it is as cheap as borrowing it. A slice is a view, so even by value it still sees // the caller's elements. import Io::PrintLine; extend int { func IsEven(self: int) -> bool { return self % 2 == 0; } func Clamped(self: int, low: int, high: int) -> int { if self < low { return low; } if self > high { return high; } return self; } } // The extended type must be one exact type. `int[..]` gains these methods, but a `uint8[..]` or an // `int32[..]` does not: it is a different type, and would need an `extend` of its own. extend int[..] { func Sum(self: int[..]) -> int { var total = 0; for value in self { total += value; } return total; } func CountEven(self: int[..]) -> uint { var count: uint = 0; for value in self { // A method added above is used like any other. if value.IsEven() { count += 1; } } return count; } } func Main() -> int { let answer = 42; let volume = 130; PrintLine("{} is even: {}", answer, answer.IsEven()); PrintLine("{} clamped: {}", volume, volume.Clamped(0, 100)); let scores: int[5] = [7, 12, 9, 20, 4]; let all: int[..] = scores; PrintLine("sum of all: {}", all.Sum()); PrintLine("even scores: {}", all.CountEven()); // An array is not a slice, so `scores.Sum()` stops with // error: type 'int[5]' has no field 'Sum' // The slice methods are reached through a view of the array instead. PrintLine("sum of the last 3: {}", scores[2..].Sum()); return 0; } ``` ## Run it ```sh cd Examples/Types/Extension rux run ``` ```text 42 is even: true 130 clamped: 100 sum of all: 52 even scores: 3 sum of the last 3: 33 ``` ## Common mistakes ::mistake **Calling a slice method on an array.**:br`scores.Sum()` fails with: ```text error: type 'int[5]' has no field 'Sum' ``` `int[5]` is an array, a different type from `int[..]`. Take a view first: `scores[..].Sum()`. :: ::mistake **Expecting a method on a related type.**:br`extend int` does not reach `int32`: with `let small: int32 = 4;`, the call `small.Double()` fails with: ```text error: type 'int32' has no field 'Double' ``` Likewise a `uint8[..]` view has no `Sum` — the error is: ```text error: slice type 'uint8[..]' has no member 'Sum' ``` A note lists the members a slice does have. :: ## Try it yourself 1. Add `func IsPositive(self: int) -> bool` to `extend int` and use it. 2. Add `func Largest(self: int[..]) -> int` to the slice extension, and print the largest score. 3. Add `func Average(self: int[..]) -> float64` that reuses `Sum`. Convert with `as` before dividing. 4. Add `extend uint8[..]` with its own `Sum`, and call it on a `uint8` array through a view. ## Learn more - [Method](https://rux-lang.dev/docs/learn/method) — `extend` on your own types - [Slice](https://rux-lang.dev/docs/learn/slice) — the views these methods work on - [Methods](https://rux-lang.dev/docs/lang/structs/methods) in the Rux Reference - [Interface](https://rux-lang.dev/docs/learn/interface) — `extend` that also makes a promise # Enum ::note **You'll need**: [Match expression](https://rux-lang.dev/docs/learn/match-expression), [Method](https://rux-lang.dev/docs/learn/method) :: An **enum** is a type with a fixed list of named values, called its **cases**. A direction is north, east, south or west, and nothing else. Stored as an `int`, a direction could just as well be 47, and nothing would notice; stored as a `Direction`, it cannot — the type has exactly four values, and the compiler knows all of them. ## Declaring an enum The declaration is `enum`, a name, and the cases separated by commas: ```rux enum Direction { North, East, South, West } ``` The cases carry no data; each one is simply itself. A case that needs to carry something — a number, a name — is a [variant](https://rux-lang.dev/docs/learn/variant), two lessons on. ## Naming a case Outside a pattern, a case is named through its type, with `::`: ```rux var heading = Direction::North; ``` Cases compare with `==` and `!=`: ```rux PrintLine("back to north: {}", heading == Direction::North); ``` ## Matching on an enum A `match` on a `Direction` already knows the type, so its patterns may use the short form `.North`: ```rux func TurnRight(self: Direction) -> Direction { return match self { .North => Direction::East, .East => Direction::South, .South => Direction::West, .West => Direction::North }; } ``` The short form is for **patterns only**. The value an arm produces is written in full — `Direction::East`, not `.East`. | Where | Spelling | | ------------------------------------ | ------------------ | | A `match` pattern on a `Direction` | `.North` | | Anywhere else: a value, a comparison | `Direction::North` | ## Every case, no else Neither `match` in the program has an `else` arm, and neither needs one. Naming all four cases covers every value a `Direction` can hold: ```mermaid flowchart LR v(["`heading`"]) --> m{"`match heading`"} m -- "`.North`" --> n["`Direction::East`"] m -- "`.East`" --> e["`Direction::South`"] m -- "`.South`" --> s["`Direction::West`"] m -- "`.West`" --> w["`Direction::North`"] ``` This is the best thing about enums. Add a fifth case, `Up`, and every `match` that does not handle it stops compiling, pointing at the case it is missing. An `else` arm would have swallowed `Up` silently — so leave `else` out when you mean "every case". ## Methods on an enum An enum can be extended with methods like any other type. Taking `self` by value is natural here: a case is as small as a number. The program gives `Direction` a `TurnRight` and a `Name`, because an enum cannot be printed with `{}` directly. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Types/Enum){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // An enum is a type with a fixed list of named values, called its cases. A direction is north, // east, south or west, and nothing else. Stored as an `int`, a direction could just as well be // 47, and nothing would notice; stored as a `Direction`, it cannot. // // The cases carry no data; each one is simply itself. A case that needs to carry something is a // `variant`, two lessons on. import Io::PrintLine; enum Direction { North, East, South, West } // An enum can be extended with methods like any other type. Taking `self` by value is natural // here: a case is as small as a number. extend Direction { // Inside a `match` on a `Direction`, the type is already known, so a pattern may be written // `.North` rather than `Direction::North`. A value outside a pattern is written in full: // `.North => .East` stops with // error: '.East' must be written in full, as in 'Direction::East' func TurnRight(self: Direction) -> Direction { return match self { .North => Direction::East, .East => Direction::South, .South => Direction::West, .West => Direction::North }; } // An enum cannot be printed with `{}` directly, so it is given a name to print. func Name(self: Direction) -> char8[..] { return match self { .North => "north", .East => "east", .South => "south", .West => "west" }; } } func Main() -> int { // A case is named through its type. var heading = Direction::North; PrintLine("start facing {}", heading.Name()); for turn in 1..=4 { heading = heading.TurnRight(); PrintLine("turn {}: facing {}", turn, heading.Name()); } // Cases compare with `==` and `!=`. PrintLine("back to north: {}", heading == Direction::North); PrintLine("facing east: {}", heading == Direction::East); // Neither `match` above needs an `else`: naming all four cases covers every value a // `Direction` can hold. Add a fifth case, and both stop compiling until they handle it. return 0; } ``` ## Run it ```sh cd Examples/Types/Enum rux run ``` ```text start facing north turn 1: facing east turn 2: facing south turn 3: facing west turn 4: facing north back to north: true facing east: false ``` ## Common mistakes ::mistake **The short form outside a pattern.**:br`.North => .East` fails with: ```text error: '.East' must be written in full, as in 'Direction::East' ``` The same happens to `let d: Direction = .North;`. Only patterns may drop the type name. :: ::mistake **A case without its type.**:br`let d = North;` fails with: ```text error: name 'North' is not defined in this scope ``` Cases live inside their enum: `Direction::North`. :: ::mistake **Leaving a case out of a `match`.**:br A `match` naming only three directions fails with: ```text error: match on 'Direction' is not exhaustive; missing Direction::West ``` :: ::mistake **Printing an enum with `{}`.**:br`PrintLine("{}", heading)` fails with: ```text error: no matching overload for 'PrintLine' with argument types (char8[..], Direction) ``` Give the enum a `Name` method, as the program does. :: ## Try it yourself 1. Add a `TurnLeft` method, and check that turning left then right comes back to the same heading. 2. Add `func Opposite(self: Direction) -> Direction`. 3. Add a fifth case, `Up`, and read the errors from both `match`es. Then handle it. 4. Declare `enum Suit { Clubs, Diamonds, Hearts, Spades }` with a `Name` method, and print all four. ## Learn more - [Enumerations](https://rux-lang.dev/docs/lang/enums/overview) in the Rux Reference - [Match expression](https://rux-lang.dev/docs/learn/match-expression) — the `match` that produces a value - [Enum value](https://rux-lang.dev/docs/learn/enum-value) — the number behind each case - [Exhaustive](https://rux-lang.dev/docs/learn/exhaustive) — how the compiler checks that every case is handled # Enum value ::note **You'll need**: [Enum](https://rux-lang.dev/docs/learn/enum), [Convert](https://rux-lang.dev/docs/learn/convert) :: Behind every enum case is a number. Usually nobody needs to know it — the [Enum](https://rux-lang.dev/docs/learn/enum) lesson never mentioned it. But sometimes the number is the point: a web server answers 404 for "not found", and a program that reads or writes such codes needs its cases to be exactly those numbers. An enum can say how its numbers are stored, with an **underlying type** after a colon, and which number each case has. `as` then converts between a case and its number, in both directions. ## Underlying type and explicit numbers ```rux enum Status: uint16 { Ok = 200, Created, NotFound = 404, ServerError = 500 } ``` `: uint16` stores each `Status` in a `uint16`. A case may give its number with `=`. A case without a number of its own takes the one after the case before it, so `Created` is 201. With no numbers given at all, the cases count up from zero — which is why `Direction::South as int` would be 2. ```mermaid flowchart LR ok["`Ok = 200`"] -- "`+1`" --> cr["`Created`
`201`"] cr -. "set explicitly" .-> nf["`NotFound = 404`"] nf -. "set explicitly" .-> se["`ServerError = 500`"] ``` ## From a case to its number, and back ```rux PrintLine("Ok is {}", Status::Ok as uint16); ``` ```rux let received: uint16 = 404; let status = received as Status; ``` A case is not its number, though. `Status::Ok == 200` is refused: compare a case with a case, or convert first. ## Cases are ordered Cases order by their numbers, so a range of codes is a pair of comparisons: ```rux PrintLine("NotFound is an error: {}", status >= Status::NotFound); ``` ## as does not check Here is the surprise. `418 as Status` compiles and runs, and gives a `Status` that is none of its four cases. Nothing goes wrong until something asks which case it is — then a `match` naming all four has no arm for it, and the program stops with `Panic: no match arm matched value of 'Status'`. So a number from outside — a file, the network, the user — is checked **before** it becomes a case: ```rux func IsKnown(code: uint16) -> bool { return match code { 200 => true, 201 => true, 404 => true, 500 => true, else => false }; } ``` ```mermaid flowchart LR n["A `uint16` from outside"] --> k{"`IsKnown(code)?`"} k -- "yes" --> s["`code as Status`
a real case"] k -- "no" --> r["Reject it: report,
or use a fallback"] ``` ## Numbers are a promise Once other programs read these numbers, they are part of your interface. Inserting a case without a number in the middle of the list would quietly renumber every unnumbered case after it. When the numbers matter, write them all out. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Types/EnumValue){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // Behind every enum case is a number. Usually nobody needs to know it, but sometimes the number is // the point: a web server answers 404 for "not found", and a program that reads or writes such // codes needs its cases to be exactly those numbers. // // An enum can say how its numbers are stored, with an underlying type after a colon, and which // number each case has. `as` converts between a case and its number, in both directions. import Io::PrintLine; // A case without a number of its own takes the one after the case before it, so `Created` is 201. // With no numbers given at all, the cases count up from zero. enum Status: uint16 { Ok = 200, Created, NotFound = 404, ServerError = 500 } // A code read from outside should be checked before it becomes a `Status`, because `as` trusts it. func IsKnown(code: uint16) -> bool { return match code { 200 => true, 201 => true, 404 => true, 500 => true, else => false }; } func Main() -> int { // From a case to its number. PrintLine("Ok is {}", Status::Ok as uint16); PrintLine("Created is {}", Status::Created as uint16); PrintLine("NotFound is {}", Status::NotFound as uint16); PrintLine("ServerError is {}", Status::ServerError as uint16); // From a number to a case. let received: uint16 = 404; let status = received as Status; PrintLine("{} means not found: {}", received, status == Status::NotFound); // Cases order by their numbers, so a range of codes is a pair of comparisons. PrintLine("NotFound is an error: {}", status >= Status::NotFound); PrintLine("Created is an error: {}", Status::Created >= Status::NotFound); // The surprise: `as` does not check. `418 as Status` compiles and runs, and gives a `Status` // that is none of its four cases. A `match` naming all four has no arm for it, so the program // stops there with `Panic: no match arm matched value of 'Status'`. So check first. let strange: uint16 = 418; PrintLine("{} is a known status: {}", received, IsKnown(received)); PrintLine("{} is a known status: {}", strange, IsKnown(strange)); // The numbers are now a promise to whoever reads them. Inserting a case without a number in // the middle of the list would quietly renumber the ones after it. return 0; } ``` ## Run it ```sh cd Examples/Types/EnumValue rux run ``` ```text Ok is 200 Created is 201 NotFound is 404 ServerError is 500 404 means not found: true NotFound is an error: true Created is an error: false 404 is a known status: true 418 is a known status: false ``` ## Common mistakes ::mistake **Trusting `as` with an unchecked number.**:br`as` never refuses. `418 as Status` makes a value that no `match` arm fits, and the program stops later, far from the line that made it, with: ```text Panic: no match arm matched value of 'Status' ``` Check the number first, as `IsKnown` does. :: ::mistake **Comparing a case with a number.**:br`Status::Ok == 200` fails with: ```text error: operator '==' cannot compare left operand 'Status' with right operand 'int' ``` Write `Status::Ok as uint16 == 200`, or compare with another case. :: ::mistake **Inserting a case in a numbered list.**:br Add `Accepted` between `Ok` and `Created`, and `Accepted` becomes 201 while `Created` moves to 202 — no error, just different numbers. Give every case whose number matters an explicit `=`. :: ## Try it yourself 1. Add `Accepted = 202` and `NoContent = 204`, update `IsKnown`, and print their numbers. 2. Write `func IsError(self: Status) -> bool` in an `extend Status` block, using a comparison rather than a `match`. 3. Write `func Name(self: Status) -> char8[..]` and use it to print the name of `received as Status`. What happens if you call it on `strange as Status`? 4. Declare `enum Level: uint8 { Low, Medium, High }` and print each case's number. ## Learn more - [Backing type and explicit values](https://rux-lang.dev/docs/lang/enums/overview#backing-type-and-values) in the Rux Reference - [Convert](https://rux-lang.dev/docs/learn/convert) — `as` between numeric types - [Variant](https://rux-lang.dev/docs/learn/variant) — cases that carry data - [Checked convert](https://rux-lang.dev/docs/learn/checked-convert) — conversions that report whether the value fits # Variant ::note **You'll need**: [Enum](https://rux-lang.dev/docs/learn/enum), [Struct](https://rux-lang.dev/docs/learn/struct) :: An [enum](https://rux-lang.dev/docs/learn/enum) says a value is one of a fixed list of cases. A **variant** says the same, and lets each case carry data of its own. A thermometer reading might be missing, or an exact temperature, or a range between two temperatures. Those are three cases, and two of them hold numbers. A struct holds *all* of its fields at once. A variant holds *one* case at a time, and only that case's data. This lesson declares and builds variants; reading the data back out is the [next lesson](https://rux-lang.dev/docs/learn/variant-match). ## Three shapes of case ```rux variant Reading { Missing, Exact(float64), Between { low: float64; high: float64; } } ``` | Case | Shape | Carries | Built as | | --------- | -------------------------------- | ---------------- | -------------------------------------------- | | `Missing` | a bare name, like an enum case | nothing | `Reading::Missing` | | `Exact` | values by position, like a tuple | one `float64` | `Reading::Exact(21.5)` | | `Between` | named fields, like a struct | `low` and `high` | `Reading::Between { low: 20.0, high: 24.0 }` | A positional case may carry several values — `Jump(int, int)` in the next lesson carries two. ## Struct, enum, variant ```mermaid flowchart LR s["`struct Point`
`x` AND `y`,
always both"] e["`enum Direction`
`North` OR `East` OR …,
no data"] v["`variant Reading`
`Missing` OR `Exact(t)`
OR `Between { low, high }`"] s -. "fields" .-> v e -. "a fixed list of cases" .-> v ``` A variant borrows from both: the "one of a list" of an enum, and the data of a struct or tuple — but only for the case that is held. ## Choosing the case A variant is a type like any other, so a function can return one, choosing the case as it goes: ```rux func Measure(low: float64, high: float64) -> Reading { if low > high { return Reading::Missing; } if low == high { return Reading::Exact(low); } return Reading::Between { low: low, high: high }; } ``` Every `return` gives back a `Reading`; which case it is depends on the numbers. ## Comparing variants Two variant values are equal when they hold the same case with the same data. Different cases are never equal, whatever they carry: ```rux PrintLine("same case, same data {}", precise == Reading::Exact(21.5)); PrintLine("different cases {}", precise == absent); ``` ## No number behind the case Unlike an [enum with values](https://rux-lang.dev/docs/learn/enum-value), a variant has no number behind its cases that `as` could reach. Which case is held is the variant's own business. A value that must be written to a file or sent elsewhere as a number is encoded with an enum, whose numbers you choose. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Types/Variant){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // An enum says a value is one of a fixed list of cases. A variant says the same, and lets each // case carry data of its own. A thermometer reading might be missing, or an exact temperature, or // a range between two temperatures. Those are three cases, and two of them hold numbers. // // A struct holds all of its fields at once. A variant holds one case at a time, and only that // case's data. This lesson declares and builds variants; reading the data back out is the next. import Io::PrintLine; // A case can take one of three shapes. `Missing` carries nothing, like an enum case. `Exact` // carries one value by position, like a one-element tuple. `Between` carries named fields, // declared like a struct's. variant Reading { Missing, Exact(float64), Between { low: float64; high: float64; } } // A variant is a type like any other: a function can return one, choosing the case as it goes. func Measure(low: float64, high: float64) -> Reading { if low > high { return Reading::Missing; } if low == high { return Reading::Exact(low); } return Reading::Between { low: low, high: high }; } func Main() -> int { // Each case is built in its own shape: just its name, its values in parentheses, or its // fields in braces. let absent = Reading::Missing; let precise = Reading::Exact(21.5); let range = Reading::Between { low: 20.0, high: 24.0 }; // Two variant values are equal when they hold the same case with the same data. Different // cases are never equal. PrintLine("same case, same data {}", precise == Reading::Exact(21.5)); PrintLine("same case, different data {}", precise == Reading::Exact(9.0)); PrintLine("different cases {}", precise == absent); PrintLine("same fields {}", range == Reading::Between { low: 20.0, high: 24.0 }); PrintLine("Measure(5.0, 5.0) exact {}", Measure(5.0, 5.0) == Reading::Exact(5.0)); PrintLine("Measure(9.0, 1.0) missing {}", Measure(9.0, 1.0) == Reading::Missing); // Unlike an enum, a variant has no number behind its cases that `as` could reach: which case // is held is the variant's own business. A value that must be written to a file or sent // elsewhere is encoded with an enum, whose numbers you choose. return 0; } ``` ## Run it ```sh cd Examples/Types/Variant rux run ``` ```text same case, same data true same case, different data false different cases false same fields true Measure(5.0, 5.0) exact true Measure(9.0, 1.0) missing true ``` ## Common mistakes ::mistake **Reading a case's data with a dot.**:br`precise.0` fails with an error that the type `Reading` has no field `0`. A variant has no fields of its own to read: the data belongs to one case, and which case is held is only known at run time. Taking it out is a job for `match`, in [Variant match](https://rux-lang.dev/docs/learn/variant-match). :: ::mistake **Leaving out a field of a struct-shaped case.**:br`Reading::Between { low: 1.0 }` fails with: ```text error: initializer for 'Reading::Between' is missing required field 'high' ``` It is the same rule as a struct literal. :: ::mistake **An integer where a float is expected.**:br`Reading::Exact(1)` fails with: ```text error: argument 1 to variant case 'Reading::Exact' has type 'int', but field 1 requires 'float64' ``` A whole-number literal never becomes a float on its own; write `1.0`. :: ::mistake **Converting a variant with `as`.**:br`precise as int` fails with an error that the variant cannot be cast to the scalar type `int`. Only an enum's cases have numbers. :: ## Try it yourself 1. Add a case `Faulty(int)` that carries an error code, and build one. 2. Change `Measure` so that a range narrower than `0.5` counts as `Exact` at its midpoint. 3. Declare `variant Shape { Circle(float64), Rectangle { width: float64; height: float64; } }` and build one of each. 4. Check whether `Reading::Between { low: 1.0, high: 2.0 }` equals `Reading::Between { low: 2.0, high: 1.0 }`. Predict first. ## Learn more - [Variants with data](https://rux-lang.dev/docs/lang/variants/overview) in the Rux Reference - [Variant match](https://rux-lang.dev/docs/learn/variant-match) — taking the data back out - [Struct](https://rux-lang.dev/docs/learn/struct) and [Enum](https://rux-lang.dev/docs/learn/enum) — the two ideas a variant combines - [Sum type](https://rux-lang.dev/docs/learn/sum-type) — a value that is one of several *types* # Variant match ::note **You'll need**: [Variant](https://rux-lang.dev/docs/learn/variant), [Match expression](https://rux-lang.dev/docs/learn/match-expression) :: A variant's data can only be read once it is known which case is held. `match` does both in one step: an arm such as `.Forward(steps)` fits only a `Forward` value, and when it fits, the name in the parentheses is a **new binding** holding that case's data, ready to use in the arm. That is the guarantee a variant gives. There is no way to read the steps of a `Turn`, because no arm can both fit a `Turn` and bind a `Forward`'s data. ## A list of commands The program walks a robot through five commands. Each command carries what it needs and nothing more: ```rux variant Command { Forward(int), Turn, Jump(int, int), Stop } ``` ## Binding the data A match that produces a value, as in [Match expression](https://rux-lang.dev/docs/learn/match-expression): ```rux func Cost(command: Command) -> int { return match command { .Forward(steps) => steps, .Turn => 1, .Jump(across, _) => across * 2, .Stop => 0 }; } ``` ```mermaid flowchart LR c(["`Command::Jump(4, 1)`"]) --> f{"`.Forward(steps)?`"} f -- "no — not a `Forward`" --> t{"`.Turn?`"} t -- "no" --> j{"`.Jump(across, _)?`"} j -- "yes: `across = 4`,
the `1` is ignored" --> r["`across * 2 = 8`"] ``` The arms are tried in order, and the first whose case fits is the one that runs. Each pattern has one name per value the case carries: | Pattern | Fits | Binds | | ------------------ | ------------- | ------------------------------------------------ | | `.Forward(steps)` | any `Forward` | `steps` — its one `int` | | `.Turn` | `Turn` | nothing; the case carries nothing | | `.Jump(across, _)` | any `Jump` | `across` — the first value; `_` skips the second | | `.Stop` | `Stop` | nothing | `_` binds nothing. It is the way to say "a value goes here, and this arm does not need it" — the count of names must still match the case. ## A match as a statement When each case calls for actions rather than a value, the arms are blocks: ```rux .Jump(across, up) => { x += across; y += up; }, ``` The bindings exist only inside their own arm: `steps` is unknown in the `.Jump` arm, and `across` in all the others. ## Every case, named There is no `else` arm in either match, and none is needed. Every case is named, and a match on a variant must name them all — leave one out, and it does not compile. As with [enums](https://rux-lang.dev/docs/learn/enum), that is a feature: add a fifth command, and the compiler lists every `match` that has yet to handle it. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Types/VariantMatch){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // A variant's data can only be read once it is known which case is held. `match` does both in // one step: an arm such as `.Forward(steps)` fits only a `Forward` value, and when it fits, the // name in the parentheses is a new binding holding that case's data, ready to use in the arm. // // That is the guarantee a variant gives. There is no way to read the steps of a `Turn`, because // no arm can both fit a `Turn` and bind a `Forward`'s data. import Io::PrintLine; // A walk is a list of commands, and each command carries what it needs and nothing more. variant Command { Forward(int), Turn, Jump(int, int), Stop } // A match producing a value, as in the MatchExpression lesson. A case with several values binds // them by position, one name each. `_` binds nothing: it is the way to say "a value goes here, // and this arm does not need it". A case with no data has nothing to bind. func Cost(command: Command) -> int { return match command { .Forward(steps) => steps, .Turn => 1, .Jump(across, _) => across * 2, .Stop => 0 }; } func Main() -> int { let walk: Command[5] = [ Command::Forward(3), Command::Turn, Command::Jump(4, 1), Command::Forward(2), Command::Stop ]; var x = 0; var y = 0; var facingEast = true; var cost = 0; for command in walk { // A match as a statement, with a block for each arm. The bindings exist only inside // their own arm: `steps` is unknown in the `.Jump` arm, and `across` in the others. match command { .Forward(steps) => { if facingEast { x += steps; } else { y += steps; } }, .Turn => { facingEast = !facingEast; }, .Jump(across, up) => { x += across; y += up; }, .Stop => { PrintLine("stopped"); } } cost += Cost(command); PrintLine("at ({}, {}), cost so far {}", x, y, cost); } // There is no `else` arm in either match, and none is needed. Every case is named, and a // match on a variant must name them all: leave one out, and it does not compile. return 0; } ``` ## Run it ```sh cd Examples/Types/VariantMatch rux run ``` ```text at (3, 0), cost so far 3 at (3, 0), cost so far 4 at (7, 1), cost so far 12 at (7, 3), cost so far 14 stopped at (7, 3), cost so far 14 ``` ## Common mistakes ::mistake **Leaving a case out.**:br Drop the `.Stop` arm from `Cost` and it fails with: ```text error: match on 'Command' is not exhaustive; missing Command::Stop ``` :: ::mistake **The wrong number of names.**:br`.Jump(across)` fails with: ```text error: pattern for 'Command::Jump' expects 2 fields, but found 1 ``` Every value the case carries needs a name or an `_`. :: ::mistake **Using a binding from another arm.**:br`.Turn => steps` fails with: ```text error: name 'steps' is not defined in this scope ``` `steps` was bound by the `.Forward` arm and exists only there. :: ::mistake **Reaching for `else` too soon.**:br`.Forward(steps) => steps, else => 0` compiles — and a new case added later falls silently into the `else`. When every case matters, name them all. :: ## Try it yourself 1. Add a case `Back(int)` that moves the other way, and handle it in both matches. Let the compiler tell you where. 2. Change `Cost` so that a `Jump` costs `across + up` instead, using both bindings. 3. Add a case with named fields, `Teleport { x: int; y: int; }`. A pattern for it names the fields in braces, and can bind them under new names: `.Teleport { x: toX, y: toY }` — handy here, where `x` and `y` already name the robot's position. Make it move the robot straight to that spot. 4. Count how many `Turn` commands the walk contains, using a `match` with a single interesting arm. ## Learn more - [Variants with data](https://rux-lang.dev/docs/lang/variants/overview) and [`match`](https://rux-lang.dev/docs/lang/patterns/match) in the Rux Reference - [Patterns](https://rux-lang.dev/docs/learn/patterns) — everything a match arm can say - [Exhaustive](https://rux-lang.dev/docs/learn/exhaustive) — how the compiler checks that every case is handled - [Error variant](https://rux-lang.dev/docs/learn/error-variant) — a variant used to describe what went wrong # Type alias ::note **You'll need**: [Struct](https://rux-lang.dev/docs/learn/struct), [Slice](https://rux-lang.dev/docs/learn/slice) :: `type` gives an existing type a **second name**. It creates nothing new: a value of the alias and a value of the aliased type are the same type, and can be used in place of each other without a conversion. What an alias buys is a spelling, written once — one that says what a value is for. ## Naming what a value means A signature saying `Celsius` explains itself where one saying `float64` does not: ```rux type Celsius = float64; type Fahrenheit = float64; func ToFahrenheit(temperature: Celsius) -> Fahrenheit { return temperature * 9.0 / 5.0 + 32.0; } ``` Inside the function, `temperature` is a `float64` in every way — the arithmetic, the literals and the result all work as they would without the alias. ## Shortening compound types An alias is most useful on compound types, where the full spelling is long and repeated: ```rux type Bytes = uint8[..]; type Row = int32[3]; ``` `func Sum(values: Bytes) -> uint` reads as "sum some bytes", and a `uint8[4]` array is passed to it exactly as it would be to a `uint8[..]` parameter. ## Same type, not a new type ```mermaid flowchart LR subgraph alias ["`type Celsius = float64`"] c1["`Celsius`"] --- f1["`float64`"] --- h1["`Fahrenheit`"] end subgraph wrap ["`struct Celsius` and `struct Fahrenheit`,
one `float64` field each"] c2["`Celsius`"] h2["`Fahrenheit`"] end c2 x--x h2 ``` Here is the trap worth knowing before relying on aliases for safety: an alias is only a spelling, so it gives **no protection at all**. `Celsius` and `Fahrenheit` are both `float64`, which makes them the same type, and nothing stops one being passed where the other is meant: ```rux let mistake: Fahrenheit = 212.0; PrintLine("this compiles and is wrong: {}F treated as Celsius is {}F", mistake, ToFahrenheit(mistake)); ``` When two things must not be mixed up, they need to be different types. A struct with a single field, `struct Celsius { degrees: float64; }`, is one: two such structs are never the same type, whatever their fields. With structs, the same mistake is refused at compile time. | You want… | Use | | -------------------------------------------- | --------------------------- | | a shorter or clearer spelling of a type | `type Name = …;` | | a value that cannot be confused with another | `struct Name { value: …; }` | ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Types/TypeAlias){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // `type` gives an existing type a second name. It creates nothing new: a value // of the alias and a value of the aliased type are the same type, and can be // used in place of each other without a conversion. import Io::PrintLine; // The point is a spelling written once. A signature saying `Celsius` explains // itself where one saying `float64` does not. type Celsius = float64; type Fahrenheit = float64; // It is most useful on compound types, where the full spelling is long and // repeated. These two are the ones worth reaching for. type Bytes = uint8[..]; type Row = int32[3]; func ToFahrenheit(temperature: Celsius) -> Fahrenheit { return temperature * 9.0 / 5.0 + 32.0; } func Sum(values: Bytes) -> uint { var total: uint = 0; for i in 0..values.length { total += values[i] as uint; } return total; } func Main() -> int { let boiling: Celsius = 100.0; PrintLine("{}C is {}F", boiling, ToFahrenheit(boiling)); let data: uint8[4] = [ 1, 2, 3, 4 ]; PrintLine("sum of bytes {}", Sum(data)); let row: Row = [ 10, 20, 30 ]; PrintLine("row {} {} {}", row[0], row[1], row[2]); // The trap worth knowing before relying on aliases for safety: an alias is // only a spelling, so it gives no protection at all. `Celsius` and // `Fahrenheit` are both `float64`, which makes them the same type, and // nothing stops one being passed where the other is meant: let mistake: Fahrenheit = 212.0; PrintLine("this compiles and is wrong: {}F treated as Celsius is {}F", mistake, ToFahrenheit(mistake)); // When two things must not be mixed up, they need to be different types. // A struct with a single field, `struct Celsius { degrees: float64; }`, is // one: two such structs are never the same type, whatever their fields. return 0; } ``` ## Run it ```sh cd Examples/Types/TypeAlias rux run ``` ```text 100.0C is 212.0F sum of bytes 10 row 10 20 30 this compiles and is wrong: 212.0F treated as Celsius is 413.6F ``` ## Common mistakes ::mistake **Expecting an alias to keep values apart.**:br`ToFahrenheit(mistake)` with a `Fahrenheit` argument compiles and gives a wrong answer. If the two must not mix, make them structs: with `struct Celsius` and `struct Fahrenheit`, the same call fails with: ```text error: argument 1 to 'ToFahrenheit' has type 'Fahrenheit', but parameter 'temperature' requires 'Celsius' ``` :: ::mistake **Being surprised by the full type in an error.**:br Error messages speak of the real type, not the alias. Passing an `int[3]` to `Sum` fails with: ```text error: argument 1 to 'Sum' has type 'int[3]', but parameter 'values' requires 'uint8[..]' ``` `Bytes` does not appear. :: ::mistake **Extending an alias.**:br`extend Celsius { … }` adds its methods to `float64` itself, so every `float64` in the package gains them — temperature or not. Methods belong on a type of their own. :: ## Try it yourself 1. Add `type Kelvin = float64;` and a function `ToKelvin(temperature: Celsius) -> Kelvin`. 2. Write `func RowSum(row: Row) -> int32` and print the sum of `row`. 3. Replace the two aliases with single-field structs, `struct Celsius { degrees: float64; }` and its twin, and make the program compile again. Which line now refuses to compile? 4. Write `type Name = char8[..];` and use it in a function that greets someone. ## Learn more - [Type aliases](https://rux-lang.dev/docs/lang/types/aliases) and [Using type aliases](https://rux-lang.dev/docs/lang/types/aliases) in the Rux Reference - [Function type aliases](https://rux-lang.dev/docs/lang/functions/function-types) — naming a function type - [Struct](https://rux-lang.dev/docs/learn/struct) — a new type rather than a new name - [Function field](https://rux-lang.dev/docs/learn/function-field) — where a long function type is worth naming # Function field ::note **You'll need**: [Callback](https://rux-lang.dev/docs/learn/callback), [Method](https://rux-lang.dev/docs/learn/method) :: The [Callback](https://rux-lang.dev/docs/learn/callback) lesson passed a function as an argument and held one in a local. A struct field can hold one too. A value then carries its **behaviour** with it: an operation knows its symbol and also how to compute, and code that loops over operations needs to know neither in advance. ## A field of function type The field's type is a function type, exactly as for a parameter — the parameter types in parentheses, then the return type: ```rux struct Operation { symbol: char8[..]; apply: func(int, int) -> int; } ``` Any function that takes two `int`s and returns an `int` fits in `apply`: `Add`, `Subtract`, `Multiply` and `Larger` all do. ## Storing a function A function is stored by its name, without parentheses — as when passing one to a callback parameter: ```rux Operation { symbol: "+", apply: Add }, ``` `Add` is the function itself; `Add(…)` would call it and store the result, which is an `int`, not a function. ## Calling through the field Calling a field looks like calling a method, but `apply` is **data**: whatever function was stored in it is what runs. ```rux func Show(self: &Operation, a: int, b: int) { PrintLine("{} {} {} = {}", a, self.symbol, b, self.apply(a, b)); } ``` ```mermaid flowchart LR invoke["`operation.Show(7, 3)`"] --> field["`self.apply(7, 3)`"] field --> q{"What is stored
in `apply`?"} q -- "`Add`" --> a["`10`"] q -- "`Multiply`" --> m["`21`"] q -- "`Larger`" --> l["`7`"] ``` The loop that prints all four lines names none of the four functions: ```rux for operation in operations { operation.Show(7, 3); } ``` Adding a fifth operation means adding one line to the array — the loop does not change. ## Method or function field? | A method `Show` | A function field `apply` | | ----------------------------------- | ----------------------------------- | | Declared once in `extend Operation` | Set separately in every value | | The same code for every `Operation` | Different code in each `Operation` | | Cannot be changed | Assigned like any field, on a `var` | A function field is assigned like any other field, which changes what the value does from then on: ```rux var changing = Operation { symbol: "?", apply: Add }; changing.Show(6, 4); changing.apply = Multiply; changing.Show(6, 4); ``` ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Types/FunctionField){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // The Callback lesson passed a function as an argument and held one in a local. A struct field // can hold one too. A value then carries its behaviour with it: an operation knows its symbol and // also how to compute, and code that loops over operations needs to know neither in advance. // // The field's type is a function type, exactly as for a parameter: `func(int, int) -> int`. import Io::PrintLine; func Add(a: int, b: int) -> int { return a + b; } func Subtract(a: int, b: int) -> int { return a - b; } func Multiply(a: int, b: int) -> int { return a * b; } func Larger(a: int, b: int) -> int { return a > b ? a : b; } struct Operation { symbol: char8[..]; apply: func(int, int) -> int; } extend Operation { // Calling a field looks like calling a method, but `apply` is data: whatever function was // stored in it is what runs. func Show(self: &Operation, a: int, b: int) { PrintLine("{} {} {} = {}", a, self.symbol, b, self.apply(a, b)); } } func Main() -> int { // A function is stored by name, without parentheses, as when passing one. let operations: Operation[4] = [ Operation { symbol: "+", apply: Add }, Operation { symbol: "-", apply: Subtract }, Operation { symbol: "*", apply: Multiply }, Operation { symbol: "max", apply: Larger } ]; // One loop, four behaviours. Nothing in it names any of the four functions. for operation in operations { operation.Show(7, 3); } // The field is called directly from outside a method too. let first = operations[0]; PrintLine("through the field: {}", first.apply(20, 22)); // A function field is assigned like any other field, which changes what the value does. var changing = Operation { symbol: "?", apply: Add }; changing.Show(6, 4); changing.apply = Multiply; changing.Show(6, 4); return 0; } ``` ## Run it ```sh cd Examples/Types/FunctionField rux run ``` ```text 7 + 3 = 10 7 - 3 = 4 7 * 3 = 21 7 max 3 = 7 through the field: 42 6 ? 4 = 10 6 ? 4 = 24 ``` ## Common mistakes ::mistake **Calling the function instead of storing it.**:br`apply: Add()` fails with: ```text error: call to 'Add' expects 2 arguments, but 0 were provided ``` Write the name alone: `apply: Add`. :: ::mistake **A function of the wrong shape.**:br A one-argument `Negate` cannot go in `apply`: `apply: Negate` fails with: ```text error: field 'apply' in initializer for 'Operation' has type 'func(int) -> int', but its declaration requires 'func(int, int) -> int' ``` The parameter types and the return type must all match. :: ::mistake **Calling the field with the wrong arguments.**:br`first.apply(1)` fails with: ```text error: call to 'function value' expects 2 arguments, but 1 was provided ``` The field's type says how it must be called, whatever function is inside. :: ::mistake **Reassigning the field of a `let`.**:br With `let op = Operation { … };`, the line `op.apply = Add;` fails with: ```text error: cannot modify immutable variable 'op' ``` A function field follows the same rule as every other field. :: ## Try it yourself 1. Write `func Smaller(a: int, b: int) -> int` and add a `min` operation to the array. Nothing else should need to change. 2. Write `func Power(a: int, b: int) -> int` with a loop, and add `^` to the array. 3. Name the function type with an alias, `type Binary = func(int, int) -> int;`, and use it in the struct. 4. Give `Operation` a second function field, `check: func(int, int) -> bool`, that says whether the operation is safe for its arguments — for example, a division that refuses a zero divisor. ## Learn more - [Function type aliases](https://rux-lang.dev/docs/lang/functions/function-types) in the Rux Reference - [Callback](https://rux-lang.dev/docs/learn/callback) — a function passed as an argument - [Type alias](https://rux-lang.dev/docs/learn/type-alias) — a short name for a long function type - [Interface](https://rux-lang.dev/docs/learn/interface) — behaviour shared by many types, chosen by type rather than stored per value # Part 7: Patterns [Part 3](https://rux-lang.dev/docs/learn/control-flow) introduced `match` with literal arms, and [Part 6](https://rux-lang.dev/docs/learn/types) used it to take variants apart. This part is about everything else an arm can say. A pattern can test a range of numbers, look at two values at once, pick fields out by name, recognise a character, and carry a condition of its own. By the end you can turn a page of `if` / `else if` tests into a `match` that reads like a table — and you will know why the compiler refuses a match that forgets a case. ## What you will learn - Adding a condition to an arm with a guard, `pattern if condition =>`, and what happens when it is false. - Matching a whole run of integers with `1..=9` and `0..10`. - Deciding on several values at once by matching a tuple: `(0, 0)`, `(x, 0)`, `(_, y)`. - Taking a variant case apart by field name: `.Circle { radius }`, `{ radius: r }`, `{ radius: 0 }`. - Matching characters, and using a guard for a whole class of them. - Why a match on a variant must name every case, and when `else` is needed — or harmful. ## How an arm is chosen Each lesson adds a new kind of pattern, but the way a `match` uses them never changes: ```mermaid flowchart LR v(["The value"]) --> arm["Take the next arm,
top to bottom"] arm --> p{"Does its pattern fit?
(`else` always does)"} p -- "no" --> arm p -- "yes: its names
are bound" --> g{"Does it have a guard
that is false?"} g -- "yes" --> arm g -- "no" --> run["Run this arm
and leave the `match`"] arm -- "no arms left" --> skip["Nothing runs —
only a statement
may get here"] ``` The compiler checks the rest before the program ever runs. For a variant or a `bool`, every case must have an unguarded arm; a match that produces a value from a number must end with `else`. That is why a value-producing match can never reach "no arms left". ## Lessons | | Lesson | What you will learn | | --- | ---------------------------------------------------------------------- | ------------------------------------------------------------------------- | | 7.1 | [Guard](https://rux-lang.dev/docs/learn/guard) | add an `if` condition to a match arm | | 7.2 | [Range pattern](https://rux-lang.dev/docs/learn/range-pattern) | match a whole range of numbers in one arm | | 7.3 | [Tuple pattern](https://rux-lang.dev/docs/learn/tuple-pattern) | match several values at once as a tuple | | 7.4 | [Struct pattern](https://rux-lang.dev/docs/learn/struct-pattern) | take a struct-shaped variant case apart by field name | | 7.5 | [Character pattern](https://rux-lang.dev/docs/learn/character-pattern) | match single characters | | 7.6 | [Exhaustive](https://rux-lang.dev/docs/learn/exhaustive) | why a match on a variant must cover every case, and when `else` is needed | ## Before you start Finish [Part 3: Control flow](https://rux-lang.dev/docs/learn/control-flow) — especially [Match](https://rux-lang.dev/docs/learn/match) and [Match expression](https://rux-lang.dev/docs/learn/match-expression) — and [Part 6: Types](https://rux-lang.dev/docs/learn/types), whose [Variant](https://rux-lang.dev/docs/learn/variant) and [Variant match](https://rux-lang.dev/docs/learn/variant-match) lessons most of this part builds on. Tuples come from [Part 5](https://rux-lang.dev/docs/learn/sequences). Each lesson's package is in the Examples repository's `Patterns/` folder: ```sh cd Examples/Patterns/Guard rux run ``` ## After this part [Part 8: Optionals](https://rux-lang.dev/docs/learn/optionals) applies these patterns to a value that may be absent, `T?`, where the arm the compiler will never let you forget is `none`. [Part 10: Sum types](https://rux-lang.dev/docs/learn/sum-types) later adds patterns that match by type, such as `n: int32 =>`. The next checkpoint project, [Calculator](https://rux-lang.dev/docs/learn/calculator), comes after [Part 9: Errors](https://rux-lang.dev/docs/learn/errors). For the full rules, see [`match`](https://rux-lang.dev/docs/lang/patterns/match), [ranges](https://rux-lang.dev/docs/lang/ranges/overview) and [tuple destructuring](https://rux-lang.dev/docs/lang/bindings/destructuring) in the Rux Reference. # Guard ::note **You'll need**: [Variant match](https://rux-lang.dev/docs/learn/variant-match), [Match expression](https://rux-lang.dev/docs/learn/match-expression), [Comparison](https://rux-lang.dev/docs/learn/comparison) :: A pattern describes the *shape* of a value: "a deposit", "the number zero". Sometimes the shape is not enough, and what you really mean is "a deposit, but only a large one". A **guard** adds that extra condition to an arm. It is the first of the tools in this part for saying more in a `match` arm than a plain literal can. ## A condition after the pattern Write `if` and a `bool` expression after the pattern, just before the `=>`: ```rux .Deposit(amount) if amount >= 10000 => "deposit, held for a check", ``` The arm is taken only when the pattern matches **and** the guard is true. The guard runs after the pattern, so it can use the names the pattern has just bound — here `amount`, the data the `.Deposit` case carries. ## A false guard moves on When the guard turns out false, nothing is lost: the match simply tries the next arm, exactly as if this one had not matched at all. That is what makes the pair of `.Deposit` arms in `Review` work: ```rux func Review(entry: Transaction) -> char8[..] { return match entry { .Deposit(amount) if amount >= 10000 => "deposit, held for a check", .Deposit(_) => "deposit", .Withdrawal(amount) if amount > 500 => "withdrawal, over the daily limit", .Withdrawal(_) => "withdrawal", .Fee => "fee" }; } ``` Follow two deposits through it: ```mermaid flowchart LR a["`Deposit(12000)`"] --> g1{"Arm 1: `.Deposit(amount)`
`if amount >= 10000`"} b["`Deposit(250)`"] --> g1 g1 -- "pattern fits,
guard true" --> held["deposit, held for a check"] g1 -- "pattern fits,
guard false" --> p2{"Arm 2: `.Deposit(_)`"} p2 -- "pattern fits" --> plain["deposit"] ``` Arms are tried from top to bottom, so each guarded arm sits **above** the plain arm that catches the rest of the same case. The plain arm is the safety net for every deposit the guard turned away. ## A guard on a plain name A plain name is a pattern too: it matches any value and binds it. Add a guard, and it becomes a condition on the whole value — something a literal pattern cannot express: ```rux func Parity(number: int32) -> char8[..] { return match number { 0 => "zero", value if value % 2 == 0 => "even", else => "odd" }; } ``` `0` is checked first and claims zero. Every other number reaches the second arm, is bound to `value`, and is accepted only if it is even. The odd ones fall through to `else`. | Arm | Matches when | | ---------------------------- | ------------------------------------------------- | | `0 =>` | the value is exactly 0 | | `value if value % 2 == 0 =>` | any value, bound to `value`, for which `% 2` is 0 | | `.Deposit(amount) if … =>` | a `Deposit`, and the guard holds for its `amount` | | `else =>` | anything that no arm above it took | ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Patterns/Guard){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // A pattern describes the shape of a value: "a deposit", "the number zero". Sometimes the shape is // not enough, and you want "a deposit, but only a large one". A guard adds that condition: write // `if` and a `bool` expression after the pattern, just before the `=>`. // // The arm is taken only when the pattern matches *and* the guard is true. The guard runs after the // pattern, so it can use the names the pattern has just bound. When the guard turns out false, // nothing is lost: the match moves on and tries the next arm, exactly as if this one had not // matched at all. import Io::PrintLine; variant Transaction { Deposit(int32), Withdrawal(int32), Fee } // Arms are tried from top to bottom, so each guarded arm sits above the plain arm that catches the // rest of the same case. Swap them and the guarded arm could never be reached. func Review(entry: Transaction) -> char8[..] { return match entry { .Deposit(amount) if amount >= 10000 => "deposit, held for a check", .Deposit(_) => "deposit", .Withdrawal(amount) if amount > 500 => "withdrawal, over the daily limit", .Withdrawal(_) => "withdrawal", .Fee => "fee" }; } // A plain name is a pattern too: it matches any value and binds it. Add a guard and it becomes a // condition on the whole value, something a literal pattern cannot express. func Parity(number: int32) -> char8[..] { return match number { 0 => "zero", value if value % 2 == 0 => "even", else => "odd" }; } func Main() -> int { let entries: Transaction[5] = [ Transaction::Deposit(250), Transaction::Deposit(12000), Transaction::Withdrawal(80), Transaction::Withdrawal(900), Transaction::Fee ]; for index in 0..5 { PrintLine("{}", Review(entries[index])); } PrintLine("0 is {}, 14 is {}, -7 is {}", Parity(0), Parity(14), Parity(-7)); return 0; } ``` ## Run it ```sh cd Examples/Patterns/Guard rux run ``` ```text deposit deposit, held for a check withdrawal withdrawal, over the daily limit fee 0 is zero, 14 is even, -7 is odd ``` ## Common mistakes ::mistake **A guarded arm below its plain arm.**:br Put `.Deposit(_)` above `.Deposit(amount) if amount >= 10000` and the program still compiles — but every deposit is taken by the plain arm first, so the guarded one can never run, and `Deposit(12000)` prints just `deposit`. The compiler does not warn about it. Specific arms go first. :: ::mistake **Counting a guarded arm as covering its case.**:br A guard might be false, so a guarded arm never counts towards covering a case. Delete `.Deposit(_) => "deposit",` and the match fails with: ```text error: match on 'Transaction' is not exhaustive; missing Transaction::Deposit ``` It fails even though a `.Deposit` arm is still there. :: ::mistake **A guarded number match with no `else`.**:br Guards cannot prove that every integer is covered. Remove `else => "odd"` from `Parity` and the compiler stops with: ```text error: match on 'int32' is not exhaustive; its arms do not cover every value ``` :: ## Try it yourself 1. Swap the two `.Deposit` arms and predict what `Deposit(12000)` prints before you run it. 2. Add an arm to `Review` that labels a withdrawal of more than 5000 as `"withdrawal, blocked"`. Where must it go so that it can be reached? 3. Extend `Parity` so that even numbers above 100 print `"large even"`. ## Learn more - [`match`](https://rux-lang.dev/docs/lang/patterns/match) in the Rux Reference — its Guards section - [Range pattern](https://rux-lang.dev/docs/learn/range-pattern) — matching a whole run of numbers, with or without a guard - [Exhaustive](https://rux-lang.dev/docs/learn/exhaustive) — which arms count when the compiler checks that every case is covered # Range pattern ::note **You'll need**: [Match](https://rux-lang.dev/docs/learn/match), [Range](https://rux-lang.dev/docs/learn/range), [Match expression](https://rux-lang.dev/docs/learn/match-expression), [Guard](https://rux-lang.dev/docs/learn/guard) :: A literal pattern matches one value. A **range pattern** matches a whole run of them. It turns the question "is the value between these two numbers?" into a single arm instead of a pair of comparisons, and a ladder of ranges reads like the table it came from. ## Two kinds of range A range pattern is written with the same two operators as a range in a [`for` loop](https://rux-lang.dev/docs/learn/range): | Pattern | Matches | Suits | | ----------- | ---------------------------------------------- | ----------------------------------------- | | `200..=299` | 200 up to **and including** 299 | tables whose rows name first and last | | `0..10` | 0 up to, but **not including**, 10 (so 0 to 9) | boundaries where one range starts another | ## Inclusive ranges: a table HTTP status codes come in blocks of a hundred, and each block is described by its first and last code. `..=` writes those rows exactly as a reference table would: ```rux func Status(code: int32) -> char8[..] { return match code { 100..=199 => "informational", 200..=299 => "success", 300..=399 => "redirection", 400..=499 => "client error", 500..=599 => "server error", else => "not a status code" }; } ``` An `int32` has billions of values the arms do not reach, so the match ends with `else`, which decides what all of them mean. ## Exclusive ranges: boundaries `..` stops just before its end, so when each range ends where the next one starts, no value falls between two arms and none is claimed twice: ```rux func Size(count: int32) -> char8[..] { return match count { 0 => "none", 1..10 => "a few", 10..100 => "dozens", 100..1000 => "hundreds", -1000..0 => "a debt", else => "a lot" }; } ``` Two more things show here. Ranges mix freely with literal arms — `0` has an arm of its own — and a negative end is written with its minus sign, as in `-1000..0`. ```mermaid flowchart LR n["`count`"] --> z["`0`
none"] n --> a["`1..10`
a few"] n --> b["`10..100`
dozens"] n --> c["`100..1000`
hundreds"] n --> d["`-1000..0`
a debt"] n --> e["`else`
a lot"] ``` Ten is the end of `1..10` but not part of it, so `Size(10)` is `"dozens"`, as the output shows. ## Ranges take guards A range is a pattern like any other, so it can carry a [guard](https://rux-lang.dev/docs/learn/guard). The arm is chosen only when the value is in the range **and** the condition holds; otherwise the match moves on: ```rux func Fare(age: int32, student: bool) -> int32 { return match age { 0..=5 => 0, 6..=17 => 5, 18..=25 if student => 5, 65..=120 => 6, else => 10 }; } ``` A student of 20 takes the third arm and pays 5. A non-student of 20 fails the guard, matches no other range, and reaches `else`: full fare. ## Only literal numbers Both ends must be literal integers. A named constant is not accepted as an end, because a bare name in a pattern means "bind a new variable" — that is how `value if …` worked in the previous lesson. Ranges also work on integers only; characters are matched one at a time, as [Character pattern](https://rux-lang.dev/docs/learn/character-pattern) shows. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Patterns/RangePattern){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // A literal pattern matches one value. A range pattern matches a whole run of them, written with // the same two operators as a range in a `for` loop: // // 200..=299 from 200 up to and including 299 // 0..10 from 0 up to, but not including, 10 // // That turns "is the value between these two numbers?" into a single arm instead of a pair of // comparisons, and a ladder of ranges reads like the table it came from. // // Both ends must be literal numbers. A named constant is not accepted as an end, because a bare // name in a pattern means "bind a new variable". With `const Low = 100;`, the arm `Low..=199 =>` // stops with // error: pattern 'Low' cannot bind a new variable because 'Low' already names a constant // Ranges work on integers only; characters are matched one at a time (see the CharacterPattern // lesson). import Io::PrintLine; // Inclusive ranges, `..=`, suit a table whose rows name their first and last value. func Status(code: int32) -> char8[..] { return match code { 100..=199 => "informational", 200..=299 => "success", 300..=399 => "redirection", 400..=499 => "client error", 500..=599 => "server error", else => "not a status code" }; } // Exclusive ranges, `..`, suit boundaries: each range stops where the next one starts, so no value // falls between two arms and none is claimed twice. Ranges mix freely with literal arms, and a // negative end is written with its minus sign. func Size(count: int32) -> char8[..] { return match count { 0 => "none", 1..10 => "a few", 10..100 => "dozens", 100..1000 => "hundreds", -1000..0 => "a debt", else => "a lot" }; } // A range takes a guard like any other pattern. The arm is chosen only when the age is in the range // *and* the condition holds; otherwise the match moves on, so a non-student of 20 pays full fare. func Fare(age: int32, student: bool) -> int32 { return match age { 0..=5 => 0, 6..=17 => 5, 18..=25 if student => 5, 65..=120 => 6, else => 10 }; } func Main() -> int { let codes: int32[4] = [204, 302, 404, 99]; for index in 0..4 { PrintLine("{} {}", codes[index], Status(codes[index])); } let counts: int32[5] = [0, 9, 10, 250, -3]; for index in 0..5 { PrintLine("{} is {}", counts[index], Size(counts[index])); } PrintLine("fares: age 4 pays {}, 12 pays {}, 70 pays {}", Fare(4, false), Fare(12, false), Fare(70, false)); PrintLine("age 20 pays {} as a student, {} otherwise", Fare(20, true), Fare(20, false)); return 0; } ``` ## Run it ```sh cd Examples/Patterns/RangePattern rux run ``` ```text 204 success 302 redirection 404 client error 99 not a status code 0 is none 9 is a few 10 is dozens 250 is hundreds -3 is a debt fares: age 4 pays 0, 12 pays 5, 70 pays 6 age 20 pays 5 as a student, 10 otherwise ``` ## Common mistakes ::mistake **A named constant as a range end.**:br With `const Low = 100;`, the arm `Low..=199 =>` stops with: ```text error: pattern 'Low' cannot bind a new variable because 'Low' already names a constant ``` Write the number itself. :: ::mistake **Inclusive ranges that share an end.**:br`0..=10 => "low", 10..=20 => "mid"` compiles, but both arms claim 10 and the first one wins, so `10` is `"low"`. Use `..` for ranges that meet, or make sure each inclusive range starts one past the previous end. :: ::mistake **Ends written the wrong way round.**:br`10..1 =>` is accepted, but no number is at least 10 and below 1, so the arm never matches and every value goes on to the next arm. The smaller end comes first. :: ::mistake **A range of the wrong character width.**:br`'a'..='z'` is a range of `char32` values, so matching a `char8` with it stops with: ```text error: pattern has type 'char32', but the matched value has type 'char8' ``` Give the bounds the value's width, `c8'a'..=c8'z'` — [Character pattern](https://rux-lang.dev/docs/learn/character-pattern) shows more. :: ## Try it yourself 1. Add a `1000..10000 => "thousands"` arm to `Size` and print `Size(4096)`. 2. Rewrite `Status` with exclusive ranges, `100..200` and so on. Does the output change? 3. Give `Fare` a guarded arm that lets anyone of 60 to 64 travel for 6 when they hold a pass, adding a `pass: bool` parameter. ## Learn more - [`match`](https://rux-lang.dev/docs/lang/patterns/match) and [ranges](https://rux-lang.dev/docs/lang/ranges/overview) in the Rux Reference - [Range](https://rux-lang.dev/docs/learn/range) — the same `..` and `..=` in a `for` loop - [Tuple pattern](https://rux-lang.dev/docs/learn/tuple-pattern) — ranges as parts of a bigger pattern # Tuple pattern ::note **You'll need**: [Tuple](https://rux-lang.dev/docs/learn/tuple), [Guard](https://rux-lang.dev/docs/learn/guard), [Range pattern](https://rux-lang.dev/docs/learn/range-pattern) :: A `match` looks at one value. Some decisions depend on two: where a point lies depends on both of its coordinates, and FizzBuzz on two remainders at once. Put the values in a [tuple](https://rux-lang.dev/docs/learn/tuple) and match the tuple, and every arm can talk about all of them together. ## One part per member Each arm is then a **tuple pattern** with one part per member, and the arm is taken only when every part matches its member: | Pattern | Matches when | | -------- | ----------------------------------------------------- | | `(0, 0)` | both members are 0 | | `(x, 0)` | the second member is 0; the first is bound to `x` | | `(_, y)` | any first member, ignored; the second is bound to `y` | A part can be any pattern you have met so far: a literal, a name, `_` or a [range](https://rux-lang.dev/docs/learn/range-pattern). Literal parts test a member, names bind one, and `_` ignores one. ## Where a point lies ```rux func Locate(point: (int32, int32)) { match point { (0, 0) => PrintLine("the origin"), (x, 0) => PrintLine("on the x axis, {} across", x), (0, y) => PrintLine("on the y axis, {} up", y), (x, y) if x == y => PrintLine("on the diagonal, {} each way", x), (_, y) if y > 0 => PrintLine("above the x axis, {} up", y), else => PrintLine("below the x axis") } } ``` Arms are tried from top to bottom, so the most specific ones go first. `(0, 0)` would also fit `(x, 0)` and `(0, y)`, which is why it comes before both. A [guard](https://rux-lang.dev/docs/learn/guard) follows the pattern as usual and can compare the members with each other: `(x, y) if x == y` is something no literal pattern can say. A pair of `int32`s has far more combinations than any list of arms, so this match ends with `else`, which decides what all the others mean. ## Building the tuple in the match The tuple need not exist beforehand. Build it right in the `match` from the values the decision depends on — here, FizzBuzz decided by both remainders at once: ```rux match (n % 3, n % 5) { (0, 0) => Print("FizzBuzz"), (0, _) => Print("Fizz"), (_, 0) => Print("Buzz"), else => Print("{}", n) } ``` Compare it with the `if` / `else if` version from [the FizzBuzz project](https://rux-lang.dev/docs/learn/fizz-buzz): the four outcomes are now four lines that read like a truth table. ## Covering every combination Two `bool`s make only four combinations, so the arms can list them all and need no `else`: ```rux let advice = match (raining, windy) { (true, true) => "a raincoat", (true, false) => "an umbrella", (false, true) => "a jacket", (false, false) => "nothing extra" }; ``` The compiler checks the list. Leave one combination out and it names the missing one exactly. ## Structs work by name A struct can be taken apart the same way, by field name instead of position: `Point { x: 0, y } =>` tests `x` and binds `y`. A field written alone, like `y`, is short for `y: y`. The next lesson, [Struct pattern](https://rux-lang.dev/docs/learn/struct-pattern), uses this form on variant cases. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Patterns/TuplePattern){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // A `match` looks at one value. To decide on two values together, put them in a tuple and match // the tuple. Each arm is then a tuple pattern with one part per member, and the arm is taken only // when every part matches its member: // // (0, 0) both members are 0 // (x, 0) the second member is 0, and the first is bound to `x` // (_, y) any first member, ignored, and the second bound to `y` // // A part can be any pattern you have met so far: a literal, a name, `_` or a range. Arms are tried // from top to bottom, so the most specific ones go first, and a guard can follow the pattern as // usual. A pair of numbers has far more combinations than any list of arms, so a match on one ends // with `else`, which decides what all the others mean. A pair of `bool`s has only four, so its // arms can list them all, and the compiler checks that none is missing. import Io::{ Print, PrintLine }; // Where a point lies. Literal parts test a member, names bind one, and `_` ignores one. func Locate(point: (int32, int32)) { match point { (0, 0) => PrintLine("the origin"), (x, 0) => PrintLine("on the x axis, {} across", x), (0, y) => PrintLine("on the y axis, {} up", y), (x, y) if x == y => PrintLine("on the diagonal, {} each way", x), (_, y) if y > 0 => PrintLine("above the x axis, {} up", y), else => PrintLine("below the x axis") } } func Main() -> int { let points: (int32, int32)[6] = [(0, 0), (4, 0), (0, 6), (3, 3), (-1, 5), (2, -7)]; for point in points { Print("({}, {}) is ", point.0, point.1); Locate(point); } // The tuple need not exist beforehand: build it right in the `match` from the values the // decision depends on. This is FizzBuzz, decided by both remainders at once. for n in 1..=15 { match (n % 3, n % 5) { (0, 0) => Print("FizzBuzz"), (0, _) => Print("Fizz"), (_, 0) => Print("Buzz"), else => Print("{}", n) } if n < 15 { Print(" "); } } PrintLine(""); // Two `bool`s make four combinations, and these arms list them all, so no `else` is needed. // Leave one out and the compiler names it: // error: match on '(bool8, bool8)' is not exhaustive; missing (true, false) let raining = true; let windy = false; let advice = match (raining, windy) { (true, true) => "a raincoat", (true, false) => "an umbrella", (false, true) => "a jacket", (false, false) => "nothing extra" }; PrintLine("rain without wind: take {}", advice); // A struct can be taken apart the same way, by field name instead of position: // `Point { x: 0, y } =>` tests `x` and binds `y`. A field written alone, like `y`, is short // for `y: y`. return 0; } ``` ## Run it ```sh cd Examples/Patterns/TuplePattern rux run ``` ```text (0, 0) is the origin (4, 0) is on the x axis, 4 across (0, 6) is on the y axis, 6 up (3, 3) is on the diagonal, 3 each way (-1, 5) is above the x axis, 5 up (2, -7) is below the x axis 1 2 Fizz 4 Buzz Fizz 7 8 Fizz Buzz 11 Fizz 13 14 FizzBuzz rain without wind: take an umbrella ``` ## Common mistakes ::mistake **A missing combination.**:br Leave `(true, false)` out of the weather match and the compiler stops with: ```text error: match on '(bool8, bool8)' is not exhaustive; missing (true, false) ``` Either add the arm or, if the remaining combinations really share an answer, an `else`. :: ::mistake **The wrong number of parts.**:br A pattern needs exactly one part per member. Matching a pair with `(0, 0, 0) =>` fails with: ```text error: tuple pattern has 3 elements, but matched tuple has 2 ``` :: ::mistake **A general arm above a specific one.**:br`(x, 0)` also fits `(0, 0)`. Put it first and the origin is reported as "on the x axis, 0 across" — the compiler accepts the order, so the arms must be arranged from most to least specific by you. :: ## Try it yourself 1. Add an arm to `Locate` for points on the other diagonal, where `x == -y`. Where does it have to go to be reached by `(-2, 2)`? 2. Rewrite FizzBuzz to also print `"Bazz"` for multiples of 7, matching a three-member tuple `(n % 3, n % 5, n % 7)`. 3. Match a `(bool, int32)` pair — say, `(member, age)` — using a range for the age, such as `(true, 0..=17) =>`. ## Learn more - [Tuples](https://rux-lang.dev/docs/lang/tuples/overview) and [destructuring](https://rux-lang.dev/docs/lang/bindings/destructuring) in the Rux Reference - [Tuple](https://rux-lang.dev/docs/learn/tuple) and [Destructure](https://rux-lang.dev/docs/learn/destructure) — building and taking apart tuples outside a `match` - [Struct pattern](https://rux-lang.dev/docs/learn/struct-pattern) — the same idea by field name # Struct pattern ::note **You'll need**: [Variant](https://rux-lang.dev/docs/learn/variant), [Variant match](https://rux-lang.dev/docs/learn/variant-match) :: [Variant](https://rux-lang.dev/docs/learn/variant) showed that a case can carry **named fields**, declared like a struct's, as in `Between { low: float64; high: float64; }`. [Variant match](https://rux-lang.dev/docs/learn/variant-match) then took cases apart by position, as in `.Jump(across, _)`. Named fields deserve a pattern that uses their names: with two or three values of the same type, a name says far more than a position — is the second number the height or the base? This lesson shows that pattern. ## Cases with named fields ```rux variant Shape { Circle { radius: int32; }, Rectangle { width: int32; height: int32; }, Triangle { base: int32; height: int32; } } ``` A value is built with the same braces, naming each field: `Shape::Circle { radius: 5 }`. The pattern that matches it looks just like that literal, with names where the values were. ## Binding fields by name The shorthand writes each field alone, and each one arrives as a variable of the same name: ```rux func Area(shape: Shape) -> int32 { return match shape { .Circle { radius } => 3 * radius * radius, .Rectangle { width, height } => width * height, .Triangle { base, height } => base * height / 2 }; } ``` A field written alone, `radius`, is short for `radius: radius`: "read the `radius` field into a variable called `radius`". ## Renaming and leaving out Fields are found by **name**, so their order in the pattern does not matter, and you are free to skip the ones you do not need: ```rux func Width(shape: Shape) -> int32 { return match shape { .Circle { radius: r } => 2 * r, .Rectangle { width } => width, .Triangle { height: _, base } => base }; } ``` `radius: r` reads the radius into `r`. The rectangle leaves its `height` out, and a field left out matches anything, as if it were written `height: _`. The triangle writes `height: _` anyway — that says "I know about this field and I do not need it" — and lists its fields in the opposite order from the declaration. ## Testing a field A literal in a field's place picks out the cases holding that value: ```rux func Kind(shape: Shape) -> char8[..] { return match shape { .Circle { radius: 0 } => "dot", .Circle {} => "circle", .Rectangle {} => "rectangle", .Triangle {} => "triangle" }; } ``` Arms are tried in order, so the circle with radius `0` comes first and the plain circle arm below it catches every other radius. The other arms test nothing, and `{}` leaves every field out. ## Four spellings | Field in the pattern | Means | | ----------------------- | --------------------------------------------- | | `radius` | bind the field to a variable of the same name | | `radius: r` | bind the field to a name of your choosing | | `height: _` or left out | ignore the field | | `radius: 0` | match only when the field holds this value | ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Patterns/StructPattern){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // A variant case can carry named fields, declared like a struct's: `Rectangle { width: int32; // height: int32; }`. The pattern for such a case looks like the literal that builds it, with // names where the values were: `.Rectangle { width, height } =>`. // // Each field in the pattern binds a variable or tests a value. Four spellings cover what you // usually need: // // .Circle { radius } bind the field to a variable of the same name // .Circle { radius: r } bind the field to a name of your choosing // .Rectangle { width } leave out a field you do not need // .Circle { radius: 0 } match only when the field holds this value // // Fields are found by name, so their order in the pattern does not matter. A field left out // matches anything, as if it were written `height: _`, and `.Rectangle {}` leaves out every field. // Writing `height: _` anyway says "I know about this field and I do not need it". import Io::PrintLine; variant Shape { Circle { radius: int32; }, Rectangle { width: int32; height: int32; }, Triangle { base: int32; height: int32; } } // The shorthand: each field arrives under its own name. func Area(shape: Shape) -> int32 { return match shape { .Circle { radius } => 3 * radius * radius, .Rectangle { width, height } => width * height, .Triangle { base, height } => base * height / 2 }; } // Renaming and ignoring. `radius: r` reads the radius into `r`; the rectangle leaves out the // height this question does not need; and the triangle skips it with `height: _`, listing its // fields in the opposite order. func Width(shape: Shape) -> int32 { return match shape { .Circle { radius: r } => 2 * r, .Rectangle { width } => width, .Triangle { height: _, base } => base }; } // Testing. A literal in a field picks out the cases holding that value. Arms are tried in order, so // the circle with a `0` comes first and the plain circle arm below it catches every other radius. // The other arms test no field, so `{}` leaves every field out. func Kind(shape: Shape) -> char8[..] { return match shape { .Circle { radius: 0 } => "dot", .Circle {} => "circle", .Rectangle {} => "rectangle", .Triangle {} => "triangle" }; } func Main() -> int { let shapes: Shape[4] = [ Shape::Circle { radius: 5 }, Shape::Rectangle { width: 4, height: 6 }, Shape::Triangle { base: 10, height: 3 }, Shape::Circle { radius: 0 } ]; for index in 0..4 { PrintLine("{:9} width {:2}, area {}", Kind(shapes[index]), Width(shapes[index]), Area(shapes[index])); } return 0; } ``` ## Run it ```sh cd Examples/Patterns/StructPattern rux run ``` ```text circle width 10, area 75 rectangle width 4, area 24 triangle width 10, area 15 dot width 0, area 0 ``` ## Common mistakes ::mistake **A misspelt field name.**:br Fields are found by name, so a name the case does not have is an error: `.Circle { radiuss } =>` stops with: ```text error: unknown field 'radiuss' in variant pattern ``` :: ::mistake **Leaving out the braces.**:br`.Circle =>` names a case with no data. For a case with fields it fails with: ```text error: pattern for 'Shape::Circle' expects 1 field, but found 0 ``` Write `.Circle {}` to match any circle without reading its fields. :: ::mistake **Testing a field without a catch-all arm.**:br`.Circle { radius: 0 }` covers only the circles of radius 0. If no plain `.Circle {}` (or `.Circle { radius }`) arm follows, the match fails with: ```text error: match on 'Shape' is not exhaustive; missing Shape::Circle ``` :: ## Try it yourself 1. Add a `Square { side: int32; }` case to `Shape`. Run `rux check` first and read which matches the compiler sends you to. 2. Add an arm to `Kind` that names a rectangle whose `width` and `height` are equal a `"square"`. You will need a [guard](https://rux-lang.dev/docs/learn/guard). 3. Write a function `Perimeter` that renames every field it reads, as in `.Rectangle { width: w, height: h }`. ## Learn more - [Variants with data](https://rux-lang.dev/docs/lang/variants/overview) and [structs](https://rux-lang.dev/docs/lang/structs/overview) in the Rux Reference - [Variant](https://rux-lang.dev/docs/learn/variant) and [Variant match](https://rux-lang.dev/docs/learn/variant-match) — building and matching cases - [Exhaustive](https://rux-lang.dev/docs/learn/exhaustive) — why every case of `Shape` needs an arm # Character pattern ::note **You'll need**: [Character](https://rux-lang.dev/docs/learn/character), [Match](https://rux-lang.dev/docs/learn/match), [Guard](https://rux-lang.dev/docs/learn/guard) :: A character literal is a pattern, just as a number is. That makes `match` the natural way to react to a key press, a command letter or a separator in some text: one arm per character, and `else` for the rest. This lesson shows the arms, the one rule about their type, and how to match a whole class of characters such as "any digit". ## One arm per character `'w' =>` matches the character w. Escapes work the same way they do in a [literal](https://rux-lang.dev/docs/learn/character): `' '` is a space and `'\n'` a line break, and any Unicode character can have an arm, `'λ'` included. ```rux func Command(key: char32) -> char8[..] { return match key { 'w' => "move up", 'a' => "move left", 's' => "move down", 'd' => "move right", ' ' => "jump", 'λ' => "cast a spell", else => "ignored" }; } ``` Uppercase and lowercase are different characters, so `'W'` does not reach the first arm. Anything without an arm of its own falls through to `else`. A match that produces a value from a character should always end with one: a `char32` has far too many values to list, and `else` is where you decide what all the others mean. ## The pattern and the value share a width A pattern must have the same character width as the value it is matched against: | Value type | Pattern | Example | | ---------------------------------------- | ------- | ---------- | | `char32` — an unprefixed literal's type | `'w'` | `'w' =>` | | `char8` — such as a byte out of a string | `c8'w'` | `c8'w' =>` | `Command` takes a `char32`, so its plain `'w'` patterns fit. A `char8` value is matched with the `c8` prefix you met in [Character](https://rux-lang.dev/docs/learn/character) — `c8'w'`. Every byte of a string literal is a `char8`, as [String literal](https://rux-lang.dev/docs/learn/string-literal) shows later in the course. ## A class of characters is a range A range of characters is a pattern, just as a range of numbers is: `'a'..='z'` matches every lowercase ASCII letter. ```rux func Kind(key: char32) -> char8[..] { return match key { '\n' => "line break", '0'..='9' => "digit", 'a'..='z' => "lowercase letter", else => "something else" }; } ``` This works because characters are ordered by their code, and the digits, like the letters `a` to `z`, have consecutive codes. The bounds follow the width rule above, so a `char8` value is matched with `c8'a'..=c8'z'`. A class that no single range spells, such as "a vowel", is still a job for a [guard](https://rux-lang.dev/docs/learn/guard). `'7'` lies between `'0'` and `'9'`; `'K'` is an uppercase letter, whose codes come before the lowercase ones, so it is "something else". ```mermaid flowchart LR k["`key`"] --> lf{"a line break?"} lf -- "yes" --> l1["line break"] lf -- "no" --> d{"`'0' ≤ c ≤ '9'?`"} d -- "yes" --> l2["digit"] d -- "no" --> a{"`'a' ≤ c ≤ 'z'?`"} a -- "yes" --> l3["lowercase letter"] a -- "no" --> l4["something else"] ``` ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Patterns/CharacterPattern){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // A character literal is a pattern, just as a number is. `'w' =>` matches the character w, and // escapes work the same way they do in a literal: `' '` is a space, `'\n'` a line break. // // The pattern must have the same character width as the value. An unprefixed `'w'` is a `char32`, // so it matches a `char32` value; a `char8` value, such as a byte read out of a text literal, is // matched with `c8'w'` instead. Mix the two and the compiler stops with // error: pattern has type 'char32', but the matched value has type 'char8' // // A range of characters is a pattern too: `'a'..='z' =>` matches every lowercase ASCII letter. Its // bounds follow the same width rule, so a `char8` value is matched with `c8'a'..=c8'z'`. A class that // no single range spells is still a guard's job. import Io::PrintLine; // One arm per key. Uppercase and lowercase are different characters, so `'W'` would not reach the // first arm, and anything without an arm of its own falls through to `else`. func Command(key: char32) -> char8[..] { return match key { 'w' => "move up", 'a' => "move left", 's' => "move down", 'd' => "move right", ' ' => "jump", 'λ' => "cast a spell", else => "ignored" }; } // A range pattern covers a whole class at once. Characters are ordered by their code, and the // digits, like the letters, have consecutive codes. func Kind(key: char32) -> char8[..] { return match key { '\n' => "line break", '0'..='9' => "digit", 'a'..='z' => "lowercase letter", else => "something else" }; } func Main() -> int { let keys: char32[6] = ['w', 'd', ' ', 'λ', 'W', 'q']; for index in 0..6 { PrintLine("'{}' -> {}", keys[index], Command(keys[index])); } PrintLine("'7' is a {}, 'k' is a {}, 'K' is {}", Kind('7'), Kind('k'), Kind('K')); PrintLine("'\\n' is a {}", Kind('\n')); return 0; } ``` ## Run it ```sh cd Examples/Patterns/CharacterPattern rux run ``` ```text 'w' -> move up 'd' -> move right ' ' -> jump 'λ' -> cast a spell 'W' -> ignored 'q' -> ignored '7' is a digit, 'k' is a lowercase letter, 'K' is something else '\n' is a line break ``` ## Common mistakes ::mistake **A pattern of the wrong width.**:br Each character of a string literal is a `char8`, while an unprefixed `'a'` is a `char32`. Matching one with the other stops with: ```text error: pattern has type 'char32', but the matched value has type 'char8' ``` Write `c8'a'` for a `char8` value. :: ::mistake **A backwards range.**:br`'z'..='a' =>` is accepted, but no character lies between its bounds, so the arm never matches. Write the lower code first: `'a'..='z'`. :: ::mistake **Forgetting the other case.**:br`'w'` and `'W'` are different characters, so an arm for one never matches the other. Give each its own arm; an arm holds exactly one pattern, so there is no `'w' | 'W'`. :: ## Try it yourself 1. Make `Command` accept the uppercase keys `W`, `A`, `S` and `D` as well. 2. Extend `Kind` so that `'K'` is reported as an `"uppercase letter"`. 3. Loop over the text `"pattern matching"` with `for c in …` — each `c` is a `char8` — and count its vowels with arms such as `c8'a' =>`. ## Learn more - [`char32`](https://rux-lang.dev/docs/lang/types/characters), [`char8`](https://rux-lang.dev/docs/lang/types/characters) and [`match`](https://rux-lang.dev/docs/lang/patterns/match) in the Rux Reference - [Character](https://rux-lang.dev/docs/learn/character) — character literals, escapes and widths - [Word count](https://rux-lang.dev/docs/learn/word-count) — a checkpoint project that sorts characters into letters and the rest # Exhaustive ::note **You'll need**: [Enum](https://rux-lang.dev/docs/learn/enum), [Variant match](https://rux-lang.dev/docs/learn/variant-match), [Guard](https://rux-lang.dev/docs/learn/guard), [Range pattern](https://rux-lang.dev/docs/learn/range-pattern) :: A `match` is **exhaustive** when every value it could meet has an arm. You have already seen the compiler insist on it — a missing case in [Variant match](https://rux-lang.dev/docs/learn/variant-match), a missing `else` in [Match expression](https://rux-lang.dev/docs/learn/match-expression). This lesson collects the rules in one place and, more importantly, explains why the check is a feature you want: it is what lets a program grow without silently breaking. ## A closed list of cases A variant or an enum has a closed list of cases, so the compiler knows every value a match on it could meet, and it insists that every one has an arm: ```rux variant Player { Stopped, Playing(int32), Paused(int32) } ``` ```rux func Describe(player: Player) -> char8[..] { return match player { .Stopped => "stopped", .Playing(second) if second < 5 => "just started", .Playing(_) => "playing", .Paused(_) => "paused" }; } ``` Every case has an arm, so no `else` is needed — and none should be written. Notice the two `.Playing` arms. A **guarded arm does not count** towards covering its case, because the guard might be false; `.Playing(second)` still needs the unguarded `.Playing(_)` below it. ## Why the check helps That check is what makes a variant safe to grow. Suppose you add a `Buffering` case to `Player` next year: ```mermaid flowchart LR add["Add a `Buffering` case"] --> q{"How does each
match end?"} q -- "names every case" --> err["Fails to build: missing
`Player::Buffering`,
pointing at the spot to fix"] q -- "ends with `else`" --> quiet["Builds silently:
`Buffering` takes the
`else` arm's answer"] ``` Every match that names its cases one by one fails to compile, and the error points at the exact place to decide what buffering means. A match with `else` keeps compiling — and quietly gives `Buffering` whatever answer `else` gives. ## else on a variant is a promise That is the trade-off in `IsPlaying`: ```rux func IsPlaying(player: Player) -> bool { return match player { .Playing(_) => true, else => false }; } ``` An `else` on a variant is allowed, but it is a promise you make on behalf of cases that do not exist yet: a future `Buffering` would count as "not playing" with no error to warn you. Use it only when that is truly the right answer for any new case. ## else is for the values you cannot list An integer has billions of values, so a match that produces a value from an integer must end with `else`, and deciding what the leftovers mean is up to you: ```rux func Loudness(volume: int32) -> char8[..] { return match volume { 0 => "muted", 1..=3 => "quiet", 10 => "maximum", else => "normal" }; } ``` Even ranges that happened to reach every value would not do instead: an integer match producing a value needs its `else`. | Matched type | Covered by | `else` | | -------------------- | ------------------------------ | ---------------------------- | | A variant or an enum | one unguarded arm per case | allowed, but hides new cases | | `bool` | a `true` arm and a `false` arm | not needed | | A tuple of `bool`s | every combination | not needed | | An integer | nothing short of `else` | required to produce a value | A match used as a **statement**, producing no value, is more relaxed about integers and `bool`s: a value with no arm simply skips the match, as in [Match](https://rux-lang.dev/docs/learn/match). A match on a variant must still name every case. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Patterns/Exhaustive){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // A variant or an enum has a closed list of cases, so the compiler knows every value a match on it // could meet, and it insists that every one has an arm. Leave a case out and the program does not // build. Delete the `.Paused` arm below and the compiler names what is missing: // error: match on 'Player' is not exhaustive; missing Player::Paused // // That check is what makes a variant safe to grow. Add a case such as `Buffering` to `Player` next // year, and every match that forgot it fails to compile, pointing at the exact spot to fix. A match // that names every case therefore has no `else`, and should not have one. // // `else` is for the values you cannot list. An integer has billions of them, so a match that // produces a value from an integer must end with `else`, and deciding what the leftovers mean is // up to you. Delete the `else` arm in `Loudness` and the compiler stops with // error: match on 'int32' is not exhaustive; its arms do not cover every value // A `bool` has just two values, so `true` and `false` arms cover it, and a missing one is named: // error: match on 'bool8' is not exhaustive; missing false // A match used as a statement, producing no value, may leave integers and bools out: a value with // no arm simply skips it. import Io::PrintLine; variant Player { Stopped, Playing(int32), Paused(int32) } // Every case has an arm, so no `else` is needed. A guarded arm does not count towards that: the // guard might be false, so `.Playing(second)` still needs an unguarded arm of its own. Without it // the error would read `missing Player::Playing`. func Describe(player: Player) -> char8[..] { return match player { .Stopped => "stopped", .Playing(second) if second < 5 => "just started", .Playing(_) => "playing", .Paused(_) => "paused" }; } // An `else` on a variant is allowed, but it is a promise you make on behalf of cases that do not // exist yet: a future `Buffering` would quietly count as "not playing" here, with no error to // warn you. Use it only when that is truly the right answer for any new case. func IsPlaying(player: Player) -> bool { return match player { .Playing(_) => true, else => false }; } // The arms name a few volume levels, and `else` covers the rest. Even ranges that happened to reach // every value would not do instead: an integer match producing a value needs its `else`. func Loudness(volume: int32) -> char8[..] { return match volume { 0 => "muted", 1..=3 => "quiet", 10 => "maximum", else => "normal" }; } func Main() -> int { let states: Player[4] = [ Player::Stopped, Player::Playing(2), Player::Playing(95), Player::Paused(95) ]; for index in 0..4 { PrintLine("{:12} playing: {}", Describe(states[index]), IsPlaying(states[index])); } PrintLine("0 {}, 2 {}, 7 {}, 10 {}", Loudness(0), Loudness(2), Loudness(7), Loudness(10)); return 0; } ``` ## Run it ```sh cd Examples/Patterns/Exhaustive rux run ``` ```text stopped playing: false just started playing: true playing playing: true paused playing: false 0 muted, 2 quiet, 7 normal, 10 maximum ``` ## Common mistakes ::mistake **A case with no arm.**:br Delete the `.Paused` arm and the program does not build: ```text error: match on 'Player' is not exhaustive; missing Player::Paused ``` The message names the case, so the fix is to add its arm — not an `else`. :: ::mistake **Only a guarded arm for a case.**:br Delete `.Playing(_) => "playing",` and the guarded `.Playing(second) if second < 5` arm is left alone. It might not match, so the error reads `missing Player::Playing`. :: ::mistake **An integer match with no `else`.**:br Delete the `else` arm in `Loudness` and the compiler stops with: ```text error: match on 'int32' is not exhaustive; its arms do not cover every value ``` A `bool` match is held to the same rule, but there two arms are enough; leave one out and it is named: ```text error: match on 'bool8' is not exhaustive; missing false ``` :: ## Try it yourself 1. Add a `Buffering` case to `Player` and run `rux check`. Which function fails, and which one keeps compiling? 2. Rewrite `IsPlaying` without `else`, so that a future case is reported instead of quietly counted as "not playing". 3. Give `Loudness` arms that between them cover `0..=10`, then delete the `else`. Read why it still does not compile. ## Learn more - [`match`](https://rux-lang.dev/docs/lang/patterns/match) and [enumerations](https://rux-lang.dev/docs/lang/enums/overview) in the Rux Reference - [Enum](https://rux-lang.dev/docs/learn/enum) and [Variant match](https://rux-lang.dev/docs/learn/variant-match) — the closed lists that make the check possible - [Presence](https://rux-lang.dev/docs/learn/presence) — the same rule for optionals, where the case you cannot forget is `none` # Part 8: Optionals Some questions have no answer: the first even number in a list of odd ones, the score of a player nobody signed. Rux writes "a value that may be absent" as `T?` — an `int?` holds an `int` or `none` — and the compiler will not let you use it as an `int` until you have said what happens when it is missing. This part covers every tool for saying so, from a full `match` to a single character. ## What you will learn - What `int?` is, how a plain value becomes a present optional, and how to write `none`. - Opening an optional with `match` and the presence patterns `value?` and `none`. - Replacing absence with a fallback using `??`, which runs the fallback only when it is needed. - Leaving a function or loop with `?? return`, `?? continue` or `?? break`. - Passing absence on to the caller with a postfix `?`. - Telling "nothing found" from "found nothing" with `int??`. ## What to do with an optional Every lesson after the first answers one question — what should happen when the value is `none`? ```mermaid flowchart LR o(["An `int?`"]) --> m["`match`
`value? => …`
`none => …`"] o --> c["`?? fallback`"] o --> x["`?? return / continue / break`"] o --> p["`?` (postfix)"] m --> m2["Each case gets
its own code"] c --> c2["A plain `int`:
the value, or the fallback"] x --> x2["A plain `int`,
or control leaves here"] p --> p2["A plain `int`,
or the function
returns `none`"] ``` | You want to… | Use | Lesson | | -------------------------------- | -------------------------------------- | ------------------------------------------------------------------------ | | run different code for each case | `match` with `value?` / `none` | [Presence](https://rux-lang.dev/docs/learn/presence) | | carry on with a stand-in value | `?? fallback` | [Coalesce](https://rux-lang.dev/docs/learn/coalesce) | | stop this function or loop | `?? return`, `?? continue`, `?? break` | [Coalesce exit](https://rux-lang.dev/docs/learn/coalesce-exit) | | let the caller decide | postfix `?` | [Optional propagate](https://rux-lang.dev/docs/learn/optional-propagate) | ## Lessons | | Lesson | What you will learn | | --- | ------------------------------------------------------------------------ | --------------------------------------------------------------------------- | | 8.1 | [Optional](https://rux-lang.dev/docs/learn/optional) | a value that may be missing: `int?` and `none` | | 8.2 | [Presence](https://rux-lang.dev/docs/learn/presence) | match an optional with `value?` and `none` arms | | 8.3 | [Coalesce](https://rux-lang.dev/docs/learn/coalesce) | supply a fallback for a missing value with `??` | | 8.4 | [Coalesce exit](https://rux-lang.dev/docs/learn/coalesce-exit) | leave with `?? return`, `?? continue` or `?? break` when a value is missing | | 8.5 | [Optional propagate](https://rux-lang.dev/docs/learn/optional-propagate) | pass absence to the caller with `?` | | 8.6 | [Nested optional](https://rux-lang.dev/docs/learn/nested-optional) | `int??`: telling "nothing found" from "found nothing" | ## Before you start Finish [Part 7: Patterns](https://rux-lang.dev/docs/learn/patterns): an optional is opened with the same `match`, guards and exhaustiveness rules, and the first lesson assumes [Variant](https://rux-lang.dev/docs/learn/variant) and [Variant match](https://rux-lang.dev/docs/learn/variant-match) from Part 6. Each lesson's package is in the Examples repository's `Optionals/` folder: ```sh cd Examples/Optionals/Optional rux run ``` ## After this part An optional says only *that* a value is missing. [Part 9: Errors](https://rux-lang.dev/docs/learn/errors) adds the fallible `T ! E`, which also says *why* — with its own `?`, its own fallbacks, and [Absence to error](https://rux-lang.dev/docs/learn/absence-to-error) to turn a `none` into a failure. After Part 9 you are ready for the checkpoint project [Calculator](https://rux-lang.dev/docs/learn/calculator). For the patterns used here, see [`match`](https://rux-lang.dev/docs/lang/patterns/match) in the Rux Reference. # Optional ::note **You'll need**: [Variant](https://rux-lang.dev/docs/learn/variant), [Variant match](https://rux-lang.dev/docs/learn/variant-match) :: Some questions have no answer. "Which is the first even number here?" has none when every number is odd. A function returning `int` cannot say so: every value an `int` holds is a perfectly good answer, so any "special" number you pick — `0`, `-1` — could also be a real result. Rux gives absence a type of its own, and this part is about using it. ## int? — an int, or nothing `int?` is an **optional** `int`. It either holds an `int`, and is then called *present*, or it holds nothing, and is *absent*. Absence has its own spelling, `none`. ```mermaid flowchart LR opt["`int?`"] --> some["present:
holds an `int`, such as `42`"] opt --> none["absent:
`none`"] ``` Any type can be made optional by adding `?`: `float64?`, `bool?`, `char8[..]?`. You can write an optional down directly, as a plain value or as `none`: ```rux let known: int? = 42; let unknown: int? = none; ``` ## A plain value becomes present on its own A plain `int` turns into a present `int?` by itself wherever an `int?` is expected, so there is nothing to wrap. `FirstEven` returns `value`, an ordinary `int`, and it arrives as a present answer: ```rux func FirstEven(values: int[..]) -> int? { for value in values { if value % 2 == 0 { // A plain `int`, returned where an `int?` is expected: it becomes present. return value; } } return none; } ``` The return type says, right in the signature, that this function may find nothing. A caller cannot miss it. ## Looking inside An optional cannot be printed or added up as it is. First you have to find out whether there is a value inside, and the smallest way to do that is a `match` with two arms: ```rux match answer { value? => PrintLine("{}: {}", label, value), none => PrintLine("{}: none", label) } ``` `value?` means "present, and call what it holds `value`"; `none` means absent. The [next lesson](https://rux-lang.dev/docs/learn/presence) explains these patterns fully. ## The type keeps the two apart An `int?` is not an `int` until a match has shown that a value is there. Arithmetic on it is refused, because the optional might be `none`: | You have | You can | You cannot | | -------- | ------------------------------------- | ------------------------------- | | `int` | add, compare, print it | store `none` in it | | `int?` | store an `int` or `none`, match on it | add to it, or print it directly | That refusal is the point. In languages where any value may secretly be "null", forgetting the check is a crash at run time; here it is a compile error, at the line that forgot. ## Absent, but not why An optional says only *that* a value is missing, never *why*. "No even number" needs no explanation, but "could not open the file" does. When the reason matters, the fallible `int ! E` of [Part 9: Errors](https://rux-lang.dev/docs/learn/errors) carries it. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Optionals/Optional){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // Some questions have no answer. "Which is the first even number here?" has none when every // number is odd, and no `int` can mean "there wasn't one" — every value an `int` holds is a // perfectly good answer. // // `int?` is the type for that: an optional `int`. It either holds an `int`, and is then called // present, or it holds nothing, and is absent. Absence has its own spelling, `none`. A plain // `int` turns into a present `int?` by itself wherever an `int?` is expected, so there is nothing // to wrap. import Io::PrintLine; // The return type says, right in the signature, that this may find nothing. func FirstEven(values: int[..]) -> int? { for value in values { if value % 2 == 0 { // A plain `int`, returned where an `int?` is expected: it becomes present. return value; } } return none; } // An optional cannot be printed or added up as it is; first you have to find out whether there // is a value inside. This is the smallest `match` that does it. `value?` means "present, and call // what it holds `value`", and `none` means absent. The next lesson, Presence, explains it fully. func Show(label: char8[..], answer: int?) { match answer { value? => PrintLine("{}: {}", label, value), none => PrintLine("{}: none", label) } } func Main() -> int { // Optionals can be written down directly, too: a plain value or `none`. let known: int? = 42; let unknown: int? = none; Show("known", known); Show("unknown", unknown); Show("first even of 3, 7, 8, 9", FirstEven([ 3, 7, 8, 9 ])); Show("first even of 1, 3, 5, 7", FirstEven([ 1, 3, 5, 7 ])); // The type keeps the two apart. `let doubled = known * 2;` is rejected — "operator '*' // cannot combine left operand 'int?' with right operand 'int'" — because `known` might be // `none`. An `int?` is not an `int` until a match has shown that a value is there. // // An optional says only that a value is missing, never why. When the reason matters, the // fallible `int ! E` of the Errors part carries it. return 0; } ``` ## Run it ```sh cd Examples/Optionals/Optional rux run ``` ```text known: 42 unknown: none first even of 3, 7, 8, 9: 8 first even of 1, 3, 5, 7: none ``` ## Common mistakes ::mistake **Doing arithmetic on an optional.**:br`let doubled = known * 2;` is rejected with: ```text error: operator '*' cannot combine left operand 'int?' with right operand 'int' ``` `known` might be `none`; open it with a `match` first, or give it a fallback with [`??`](https://rux-lang.dev/docs/learn/coalesce). :: ::mistake **Printing an optional directly.**:br`PrintLine("{}", known);` fails with: ```text error: no matching overload for 'PrintLine' with argument types (char8[..], int?) ``` Only the value inside can be printed, once a match has found it. :: ::mistake **Inventing a "no value" number.**:br Returning `-1` or `0` for "not found" from a function declared `-> int` compiles, but every caller has to know the convention, and nothing stops one from adding the `-1` to a total. Return `int?` and the compiler makes every caller deal with absence. :: ## Try it yourself 1. Write `FirstNegative(values: int[..]) -> int?` and show its answer for `[3, -2, 5]` and `[1, 2, 3]`. 2. Write `Divide(a: int, b: int) -> int?` that returns `none` when `b` is 0. 3. Try `let doubled = known * 2;` and the direct `PrintLine` of an optional, and read both errors. ## Learn more - [Presence](https://rux-lang.dev/docs/learn/presence) — opening an optional with `match` - [Coalesce](https://rux-lang.dev/docs/learn/coalesce) — replacing absence with a fallback in one line - [Fallible](https://rux-lang.dev/docs/learn/fallible) — when the caller needs to know *why* there is no value # Presence ::note **You'll need**: [Optional](https://rux-lang.dev/docs/learn/optional), [Variant match](https://rux-lang.dev/docs/learn/variant-match), [Guard](https://rux-lang.dev/docs/learn/guard) :: An `int?` holds either an `int` or nothing, and the program cannot do sums with it until it knows which. `match` is how you find out. It opens the optional and hands you what is inside — but only in the arm where something is actually there. Everything you learnt about patterns in [Part 7](https://rux-lang.dev/docs/learn/patterns) carries over. ## Two arms The lesson's `ScoreOf` looks up the player wearing a number and returns their score, or `none` when nobody wears it. Opening its answer takes two arms: ```rux match ScoreOf(players, number) { score? => PrintLine("#{} scored {}", number, score), none => PrintLine("#{} is not on the team", number) } ``` | Arm | Taken when | Inside the arm | | ----------- | ----------------------- | ----------------------------------- | | `score? =>` | the optional is present | `score` is the plain `int` it holds | | `none =>` | the optional is absent | there is nothing to bind | `score?` is a pattern, not a question. Read the `?` as "a present …": "a present value, called `score`". The name before it becomes an ordinary `int`, but only inside its own arm — there is no way to reach a `score` in the `none` arm, because there is none to reach. ## The long spelling An optional is a two-case type, much like a [variant](https://rux-lang.dev/docs/learn/variant-match), and its present case has a name: `.Some`. These two arms mean exactly the same thing: ```rux .Some(score) => PrintLine("#{} scored {}", number, score), ``` ```rux score? => PrintLine("#{} scored {}", number, score), ``` The short form is the usual one. The long one is worth recognising, because the compiler uses it in its messages, and [Nested optional](https://rux-lang.dev/docs/learn/nested-optional) needs it to explain two levels of absence. ## Any pattern can be present The `?` wraps any pattern, so a literal and a [guard](https://rux-lang.dev/docs/learn/guard) work as usual: ```rux func Rating(players: Player[..], number: int) -> char8[..] { return match ScoreOf(players, number) { 0? => "has not scored yet", score? if score >= 20 => "is the top scorer", score? => "is a regular", none => "is not on the team" }; } ``` `0?` is "a present 0". The arms are tried from the top, so the general `score?` arm comes after the specific ones, exactly as in [Exhaustive](https://rux-lang.dev/docs/learn/exhaustive). ```mermaid flowchart LR r["`ScoreOf(…)`"] --> q{"Present?"} q -- "no" --> n["`none`
is not on the team"] q -- "yes" --> z{"Is it 0?"} z -- "yes" --> a["`0?`
has not scored yet"] z -- "no" --> t{"`score >= 20?`"} t -- "yes" --> b["`score? if …`
is the top scorer"] t -- "no" --> c["`score?`
is a regular"] ``` ## none cannot be forgotten A match on an optional must be exhaustive, like a match on a variant — even when it is a statement. The `none` arm is required, because absence is the case the optional exists to make you handle. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Optionals/Presence){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // An `int?` holds either an `int` or nothing, and the program cannot do sums // with it until it knows which. `match` is how you find out. It opens the // optional and hands you what is inside, but only in the arm where something // is actually there. // // There are two arms to write: // // score? => ... present: `score` is the `int` inside // none => ... absent: there is nothing to bind // // `score?` is a pattern, not a question. Read the `?` as "a present ...". The // name before it becomes an ordinary `int`, but only inside its arm. import Io::PrintLine; struct Player { number: int; score: int; } // The score of the player wearing `number`, or `none` when nobody does. func ScoreOf(players: Player[..], number: int) -> int? { for player in players { if player.number == number { return player.score; } } return none; } func Report(players: Player[..], number: int) { match ScoreOf(players, number) { score? => PrintLine("#{} scored {}", number, score), none => PrintLine("#{} is not on the team", number) } } // The same match with the long spelling. `.Some(score)` and `score?` mean the // same thing, much as a variant case is matched by name. The short form is the // usual one. func ReportLong(players: Player[..], number: int) { match ScoreOf(players, number) { .Some(score) => PrintLine("#{} scored {}", number, score), none => PrintLine("#{} is not on the team", number) } } // The `?` wraps any pattern, so a literal and a guard work as usual. The arms // are tried from the top, so the general `score?` arm comes after the // specific ones. func Rating(players: Player[..], number: int) -> char8[..] { return match ScoreOf(players, number) { 0? => "has not scored yet", score? if score >= 20 => "is the top scorer", score? => "is a regular", none => "is not on the team" }; } func Main() -> int { let players = [ Player { number: 4, score: 0 }, Player { number: 7, score: 12 }, Player { number: 10, score: 25 } ]; Report(players, 7); Report(players, 9); ReportLong(players, 10); for number in [ 4, 7, 10, 9 ] { let rating = Rating(players, number); PrintLine("#{} {}", number, rating); } // Watch out: the `none` arm is required. If you leave it out, the // compiler stops with "match on 'int?' is not exhaustive; missing none", // because that is the case the optional exists to make you handle. return 0; } ``` ## Run it ```sh cd Examples/Optionals/Presence rux run ``` ```text #7 scored 12 #9 is not on the team #10 scored 25 #4 has not scored yet #7 is a regular #10 is the top scorer #9 is not on the team ``` ## Common mistakes ::mistake **Leaving out the `none` arm.**:br Without it the compiler stops with: ```text error: match on 'int?' is not exhaustive; missing none ``` That happens even for a match used as a statement. :: ::mistake **Leaving out the present arm.**:br The other half is required too. A match with only `none =>` fails with: ```text error: match on 'int?' is not exhaustive; missing .Some(_) ``` That is the long spelling at work. :: ::mistake **Only specific present arms.**:br`0?` and a guarded `score? if …` do not cover every present value. Without a plain `score?` arm the match is still missing `.Some(_)`. :: ## Try it yourself 1. Delete the `none` arm from `Report` and read the error. 2. Give `Rating` an arm for players who scored exactly 1, reading `"has scored once"`. Where does it go? 3. Write `Bench(players: Player[..], number: int) -> bool` that is `true` for a player with no goals and `false` otherwise — including for numbers nobody wears. ## Learn more - [`match`](https://rux-lang.dev/docs/lang/patterns/match) in the Rux Reference - [Optional](https://rux-lang.dev/docs/learn/optional) — what `int?` is - [Coalesce](https://rux-lang.dev/docs/learn/coalesce) — when all you need is a fallback, `??` is shorter than a match # Coalesce ::note **You'll need**: [Optional](https://rux-lang.dev/docs/learn/optional), [Function](https://rux-lang.dev/docs/learn/function) :: Often absence has an obvious stand-in. With no frost reading there is no frost, so report zero; with no nickname, use the real name. A whole `match` for that is a lot of code for a small idea. The **coalescing operator** `??` says it in one line. ## optional ?? fallback ```rux PrintLine("monday: {}", FirstFrost(monday) ?? 0); PrintLine("tuesday: {}", FirstFrost(tuesday) ?? 0); ``` When the optional is present you get what is inside it. When it is `none` you get the fallback. Either way the result is a plain `int` — not an `int?` — so the rest of the program never has to think about absence again. Monday has a frost and prints `-4`; Tuesday has none and prints `0`. It is a shorter way to write a match you already know: | With `??` | Means the same as | | ---------------------- | ---------------------------------------------- | | `FirstFrost(day) ?? 0` | `match FirstFrost(day) { t? => t, none => 0 }` | The fallback must have the type of the value inside: an `int?` takes an `int` fallback. ## The fallback is lazy The fallback is evaluated only when it is needed. `Forecast` prints a line whenever it runs, so you can see when that is: ```rux PrintLine(" {}", FirstFrost(monday) ?? Forecast()); PrintLine(" {}", FirstFrost(tuesday) ?? Forecast()); ``` ```mermaid flowchart LR o["`FirstFrost(day)`"] --> q{"Present?"} q -- "yes" --> v["its value
(`Forecast` never runs)"] q -- "no" --> f["run `Forecast()`
and use its result"] ``` Monday has a frost, so the forecast is never asked. Tuesday has none, so it is — and `(asking the forecast)` appears in the output only once. That matters when the fallback is slow, or does something you can see, such as printing or reading a file. ## Chaining `??` chains. The optionals are tried from left to right, the first present one wins, and the last fallback covers the case where every one is absent: ```rux let either = FirstFrost(tuesday) ?? FirstFrost(monday) ?? 0; ``` Tuesday is `none`, Monday is `-4`, so `either` is `-4`, and the final `0` is never needed. ## Mind the precedence `==` binds more tightly than `??`, so a comparison next to a fallback needs parentheses: ```rux let mild = (FirstFrost(tuesday) ?? 0) == 0; ``` Without them, `FirstFrost(tuesday) ?? 0 == 0` would mean `FirstFrost(tuesday) ?? (0 == 0)` — an `int` optional with a `bool` fallback. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Optionals/Coalesce){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // Often absence has an obvious stand-in. With no reading there is no frost, // so report zero. A whole `match` for that is a lot of code, and `??` says it // in one line: // // optional ?? fallback // // When the optional is present you get what is inside it. When it is `none` // you get the fallback. Either way the result is a plain `int`, so the rest of // the program never has to think about absence again. import Io::PrintLine; // The first temperature below zero, or `none` on a mild day. func FirstFrost(readings: int[..]) -> int? { for reading in readings { if reading < 0 { return reading; } } return none; } // A slow fallback, which prints so that you can see when it runs. func Forecast() -> int { PrintLine(" (asking the forecast)"); return -2; } func Main() -> int { let monday = [ 3, 1, -4, -1 ]; let tuesday = [ 5, 6, 4, 2 ]; PrintLine("monday: {}", FirstFrost(monday) ?? 0); PrintLine("tuesday: {}", FirstFrost(tuesday) ?? 0); // The fallback is lazy: it is evaluated only when it is needed. Monday has // a frost, so the forecast is never asked. Tuesday has none, so it is. PrintLine("monday or forecast:"); PrintLine(" {}", FirstFrost(monday) ?? Forecast()); PrintLine("tuesday or forecast:"); PrintLine(" {}", FirstFrost(tuesday) ?? Forecast()); // `??` chains. The optionals are tried from left to right, the first // present one wins, and the last fallback covers the case where every one // is absent. let either = FirstFrost(tuesday) ?? FirstFrost(monday) ?? 0; PrintLine("first frost this week: {}", either); // Watch out: `==` binds more tightly than `??`. Without the parentheses, // `FirstFrost(tuesday) ?? 0 == 0` would mean `FirstFrost(tuesday) ?? (0 == 0)`, // which mixes an `int` with a `bool` and does not compile. let mild = (FirstFrost(tuesday) ?? 0) == 0; PrintLine("tuesday was mild: {}", mild); return 0; } ``` ## Run it ```sh cd Examples/Optionals/Coalesce rux run ``` ```text monday: -4 tuesday: 0 monday or forecast: -4 tuesday or forecast: (asking the forecast) -2 first frost this week: -4 tuesday was mild: true ``` ## Common mistakes ::mistake **A comparison without parentheses.**:br`let mild = FirstFrost(tuesday) ?? 0 == 0;` reads as `FirstFrost(tuesday) ?? (0 == 0)` and stops with: ```text error: coalescing fallback has type 'bool8', but the optional payload is 'int' ``` Wrap the coalescing part: `(FirstFrost(tuesday) ?? 0) == 0`. :: ::mistake **`??` on a value that is not optional.**:br A plain `int` is never absent, so there is nothing to fall back from: `count ?? 0` fails with: ```text error: operator '??' requires an optional left operand, but found 'int' ``` Remove the `??`. :: ::mistake **A fallback that always runs — in your head.**:br The fallback runs only for `none`. If it has an effect you rely on, such as a line of output, that effect happens only on the absent path, as the forecast shows. :: ## Try it yourself 1. Print the first frost of a week of three days, `FirstFrost(a) ?? FirstFrost(b) ?? FirstFrost(c) ?? 0`, with only the last day frosty. 2. Make `Forecast` return `-9` and check that Monday's line still prints `-4`. 3. Declare `let nickname: char8[..]? = none;` and print `nickname ?? "anonymous"`. ## Learn more - [Presence](https://rux-lang.dev/docs/learn/presence) — the `match` that `??` abbreviates - [Coalesce exit](https://rux-lang.dev/docs/learn/coalesce-exit) — a fallback that leaves the function or loop instead of producing a value - [Precedence](https://rux-lang.dev/docs/learn/precedence) — how Rux decides which operator binds first # Coalesce exit ::note **You'll need**: [Coalesce](https://rux-lang.dev/docs/learn/coalesce), [Return](https://rux-lang.dev/docs/learn/return), [Break](https://rux-lang.dev/docs/learn/break), [Continue](https://rux-lang.dev/docs/learn/continue) :: Sometimes there is no sensible stand-in for a missing value. A bonus for a player who does not exist is not 0 — there is simply nothing more to compute. The fallback after `??` does not have to be a value: it can also be a **way out**. That turns the most common shape of optional code — "if it is missing, stop here" — into a single line. ## Three ways out Any of these three can follow `??`: ```rux let score = ScoreOf(players, number) ?? return 0; // leave the function let score = ScoreOf(players, number) ?? continue; // skip to the next turn let score = ScoreOf(players, number) ?? break; // leave the loop ``` If the optional is present, `score` is the `int` inside it and the code below runs as normal. If it is `none`, control leaves right there, and the line never produces a value at all. That is why `score` is a plain `int` with no `?`: by the next line, absence has already been dealt with. | Written | When the optional is `none` | Allowed in | | ------------- | ---------------------------------- | ------------------------------------------------------ | | `?? return x` | the function returns `x` | any function — plain `?? return` in one with no result | | `?? continue` | the loop moves on to its next turn | a `for`, `while` or `loop` | | `?? break` | the loop ends; code after it runs | a `for`, `while` or `loop` | ## ?? return: a guard at the top `?? return` deals with the missing case first, so the rest of the function can be written as if the value were always there: ```rux func Bonus(players: Player[..], number: int) -> int { let score = ScoreOf(players, number) ?? return 0; if score >= 20 { return 5; } return 1; } ``` ```mermaid flowchart LR s["`ScoreOf(players, number)`"] --> q{"Present?"} q -- "yes" --> b["`score` is a plain `int`;
the function goes on"] q -- "no" --> r["`return 0`
— nothing below runs"] ``` \#3 is not on the team, so `Bonus(players, 3)` returns 0 on its first line. #10 is, with 25, and earns 5. ## ?? continue and ?? break in a loop Inside a loop, the same idea skips one turn or ends the loop. `requested` holds `7, 3, 10, 4`, and #3 is unknown: ```rux var total = 0; for number in requested { let score = ScoreOf(players, number) ?? continue; total += score; } ``` `?? continue` skips #3 and the loop goes on, so the total is 12 + 25 + 8 = 45. ```rux var counted = 0; for number in requested { let score = ScoreOf(players, number) ?? break; PrintLine(" #{} scored {}", number, score); counted++; } ``` `?? break` stops at the first unknown number instead: #7 is printed, #3 ends the loop, and #10 and #4 are never looked at. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Optionals/CoalesceExit){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // The fallback after `??` does not have to be a value. It can also be a way // out: // // let score = ScoreOf(players, number) ?? return 0; leave the function // let score = ScoreOf(players, number) ?? continue; skip to the next turn // let score = ScoreOf(players, number) ?? break; leave the loop // // If the optional is present, `score` is the `int` inside it and the code // below runs as normal. If it is `none`, control leaves right there, and the // line never produces a value at all. That is why `score` is a plain `int` // with no `?`: by the next line, absence has already been dealt with. import Io::PrintLine; struct Player { number: int; score: int; } func ScoreOf(players: Player[..], number: int) -> int? { for player in players { if player.number == number { return player.score; } } return none; } // `?? return` is a guard at the top of a function: deal with the missing case // first, then write the rest as if the value were always there. func Bonus(players: Player[..], number: int) -> int { let score = ScoreOf(players, number) ?? return 0; if score >= 20 { return 5; } return 1; } func Main() -> int { let players = [ Player { number: 4, score: 8 }, Player { number: 7, score: 12 }, Player { number: 10, score: 25 } ]; let requested = [ 7, 3, 10, 4 ]; PrintLine("bonus for #10: {}", Bonus(players, 10)); PrintLine("bonus for #3: {}", Bonus(players, 3)); // `?? continue` skips a number nobody wears, and the loop goes on. var total = 0; for number in requested { let score = ScoreOf(players, number) ?? continue; total += score; } PrintLine("total, skipping unknown numbers: {}", total); // `?? break` stops at the first unknown number instead. var counted = 0; for number in requested { let score = ScoreOf(players, number) ?? break; PrintLine(" #{} scored {}", number, score); counted++; } PrintLine("counted {} before the first unknown number", counted); // Watch out: these exits only make sense where they are allowed. Outside // a loop, `?? continue` and `?? break` are errors, just as a bare // `continue;` would be. return 0; } ``` ## Run it ```sh cd Examples/Optionals/CoalesceExit rux run ``` ```text bonus for #10: 5 bonus for #3: 0 total, skipping unknown numbers: 45 #7 scored 12 counted 1 before the first unknown number ``` ## Common mistakes ::mistake **Leaving a loop that is not there.**:br Outside a loop, `?? continue` and `?? break` are errors, just as a bare `continue;` would be: ```text error: 'continue' can only be used inside 'while', 'for', or 'loop' ``` :: ::mistake **Returning `none` from a function that does not return an optional.**:br In a function declared `-> int`, `?? return none` fails with: ```text error: 'none' needs an expected optional type, but found 'int' ``` Return a value of the function's own type, or make the function return `int?` — and then [`?`](https://rux-lang.dev/docs/learn/optional-propagate) says the same thing more briefly. :: ::mistake **Expecting `?? break` to skip.**:br`break` ends the whole loop at the first `none`; it does not move on to the next item. Reach for `?? continue` when the other items should still be processed. :: ## Try it yourself 1. Change `requested` so that the unknown number comes last. What do the two loops print now? 2. Write `Describe(players: Player[..], number: int) -> char8[..]` that begins with `?? return "unknown"` and then labels the score. 3. Make the `?? continue` loop also report how many numbers it skipped. Hint: count every turn before the `??` line and every success after it. ## Learn more - [Coalesce](https://rux-lang.dev/docs/learn/coalesce) — a fallback that is a value - [Return](https://rux-lang.dev/docs/learn/return), [Break](https://rux-lang.dev/docs/learn/break) and [Continue](https://rux-lang.dev/docs/learn/continue) — the exits themselves - [Absence to error](https://rux-lang.dev/docs/learn/absence-to-error) — a fourth way out, `?? fail`, from the Errors part # Optional propagate ::note **You'll need**: [Presence](https://rux-lang.dev/docs/learn/presence), [Coalesce](https://rux-lang.dev/docs/learn/coalesce) :: Sometimes a function cannot do anything useful with a missing value except report that it is missing too. How far ahead of #7 is #10? If either player is unknown there is no answer, and the honest result is `none`. A postfix `?` writes exactly that: "if this is absent, so is my answer". ## Two matches, or one ? With `match`, `Lead` would need two nested matches and two `none` arms that say the same thing. A `?` after an optional says it for you: ```rux func Lead(players: Player[..], a: int, b: int) -> int? { return ScoreOf(players, a)? - ScoreOf(players, b)?; } ``` If the optional is present, `ScoreOf(players, a)?` is the `int` inside it. If it is `none`, the function returns `none` straight away, and nothing after it runs. The subtraction can therefore be written as if both scores were plain numbers. ```mermaid flowchart LR e["`ScoreOf(players, a)?`"] --> q{"Present?"} q -- "yes" --> v["the `int` inside;
the expression goes on"] q -- "no" --> r["`Lead` returns `none`
at once"] r --> c["the caller decides:
`match` or `??`"] ``` ## Each line produces its value or ends the function `?` works anywhere in the function, including in a `let` inside a loop: ```rux func TeamTotal(players: Player[..], numbers: int[..]) -> int? { var total = 0; for number in numbers { let score = ScoreOf(players, number)?; total += score; } return total; } ``` For the starters `4, 7, 10` every lookup succeeds and the total is 45. For `4, 9, 10`, #9 is unknown: the `?` returns `none` from `TeamTotal` in the middle of the loop, and the partial total is never seen. ## The caller handles it `?` only moves absence up one level. Somewhere a caller has to deal with it, with a [match](https://rux-lang.dev/docs/learn/presence) or a [fallback](https://rux-lang.dev/docs/learn/coalesce): ```rux PrintLine("starters total: {}", TeamTotal(players, starters) ?? -1); PrintLine("mixed total: {}", TeamTotal(players, mixed) ?? -1); ``` ## ? compared with ?? return The two look alike, and the difference is what the function returns: | Written | When the value is `none` | The function must return | | ------------------------ | -------------------------- | --------------------------- | | `ScoreOf(…)?` | returns `none` | an optional, such as `int?` | | `ScoreOf(…) ?? return 0` | returns the value you name | anything that value fits | So `?` can only appear in a function whose own result is optional: it needs a `none` it can return. `Main` returns a plain `int`, which is why `Main` opens the results with `match` and `??` instead. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Optionals/OptionalPropagate){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // Sometimes a function cannot do anything useful with a missing value except // report that it is missing too. How far ahead is #7 of #10? If either player // is unknown, there is no answer, and the honest result is `none`. // // Writing that with `match` takes two nested matches and two `none` arms that // say the same thing. A `?` after an optional says it for you: // // ScoreOf(players, a)? // // If the optional is present, this is the `int` inside it. If it is `none`, the // function returns `none` straight away, and nothing after it runs. So `?` can // only appear in a function whose own result is optional: it needs a `none` it // can return. import Io::PrintLine; struct Player { number: int; score: int; } func ScoreOf(players: Player[..], number: int) -> int? { for player in players { if player.number == number { return player.score; } } return none; } // Both scores are needed, and either may be missing. The `?`s let the sum be // written as if they were plain numbers. func Lead(players: Player[..], a: int, b: int) -> int? { return ScoreOf(players, a)? - ScoreOf(players, b)?; } // `?` works anywhere in the function, including in a `let`. Each line either // produces its value or ends the function. func TeamTotal(players: Player[..], numbers: int[..]) -> int? { var total = 0; for number in numbers { let score = ScoreOf(players, number)?; total += score; } return total; } func Main() -> int { let players = [ Player { number: 4, score: 8 }, Player { number: 7, score: 12 }, Player { number: 10, score: 25 } ]; // The caller is where absence is finally handled, with `match` or `??`. match Lead(players, 10, 7) { lead? => PrintLine("#10 leads #7 by {}", lead), none => PrintLine("no answer") } match Lead(players, 10, 3) { lead? => PrintLine("#10 leads #3 by {}", lead), none => PrintLine("#10 against #3: no answer, #3 is not on the team") } let starters = [ 4, 7, 10 ]; let mixed = [ 4, 9, 10 ]; PrintLine("starters total: {}", TeamTotal(players, starters) ?? -1); PrintLine("mixed total: {}", TeamTotal(players, mixed) ?? -1); // Watch out: `?` is not available in `Main`, or in any function that // returns a plain `int`. There is no `none` to hand back, so the compiler // rejects it. Use `match` or `??` there instead. return 0; } ``` ## Run it ```sh cd Examples/Optionals/OptionalPropagate rux run ``` ```text #10 leads #7 by 13 #10 against #3: no answer, #3 is not on the team starters total: 45 mixed total: -1 ``` ## Common mistakes ::mistake **`?` in a function that cannot return `none`.**:br In `Main`, or any function returning a plain `int`, `let v = ScoreOf(players, 7)?;` stops with: ```text error: '?' propagates the absence of 'int?', but the enclosing function returns 'int' ``` The compiler's help says what to do: declare an optional result, as in `-> T?`, or supply a fallback with `??`. :: ::mistake **Propagating when a fallback is meant.**:br`?` makes the whole function's answer `none`. If one missing score should simply count as zero, write `ScoreOf(players, number) ?? 0` and keep the rest of the total. :: ## Try it yourself 1. Write `Average(players: Player[..], a: int, b: int) -> int?` with two `?`s, and show it for a known and an unknown pair. 2. Rewrite `Lead` with nested `match`es and compare the length. 3. Change `TeamTotal` so that an unknown number is skipped rather than ending the total. Which operator did you use instead of `?`? ## Learn more - [Presence](https://rux-lang.dev/docs/learn/presence) and [Coalesce](https://rux-lang.dev/docs/learn/coalesce) — the two ways a caller finally handles absence - [Coalesce exit](https://rux-lang.dev/docs/learn/coalesce-exit) — `?? return` for functions that do not return an optional - [Propagate](https://rux-lang.dev/docs/learn/propagate) — the same `?` passing an error up, in the Errors part # Nested optional ::note **You'll need**: [Presence](https://rux-lang.dev/docs/learn/presence), [Coalesce](https://rux-lang.dev/docs/learn/coalesce) :: A player who has not played yet has no score, so this lesson's team sheet stores each score as an `int?`. Now look a player up by number. The answer can be missing for two quite different reasons — nobody wears that number, or the player exists but has no score yet. An optional of an optional, `int??`, keeps the two apart. ## Three answers, one type ```rux struct Player { number: int; score: int?; } ``` A lookup that returns the player's `score` must also be able to say "not found", so its result wraps the `int?` in one more optional: ```mermaid flowchart TD r["`int??`"] --> n["`none`
nobody wears that number"] r --> s["`.Some(…)` — the player exists"] s --> sn["`.Some(none)`
no score yet"] s --> ss["`.Some(.Some(score))`
has scored"] ``` Rux never squashes the two levels into one. In some languages "a missing missing value" collapses into plain "missing", and the difference is lost; here the two kinds of "nothing" stay different, and you can tell them apart. ## Building one `player.score` is an `int?`. Returned where an `int??` is expected it becomes a present `int??` on its own, even when the score inside is `none` — the same rule that turned an `int` into a present `int?` in [Optional](https://rux-lang.dev/docs/learn/optional). Only the `none` at the bottom means "not found": ```rux func ScoreOf(players: Player[..], number: int) -> int?? { for player in players { if player.number == number { return player.score; } } return none; } ``` ## Opening one, level by level Each `?` in a pattern opens one level: ```rux match ScoreOf(players, number) { score?? => PrintLine("#{} scored {}", number, score), none? => PrintLine("#{} has not played yet", number), none => PrintLine("#{} is not on the team", number) } ``` | Short | Long | Meaning | | --------- | --------------------- | ----------------------------------------- | | `score??` | `.Some(.Some(score))` | a present, present score | | `none?` | `.Some(none)` | a present `none`: found, but no score yet | | `none` | `none` | the outer absence: not on the team | The long spelling, used in `ReportLong`, shows the nesting plainly; the short one is the usual one. ## ?? opens one level too `??` removes exactly one level, so on an `int??` its result is still an `int?`: ```rux let once = ScoreOf(players, 9) ?? 0; let twice = once ?? 0; ``` For #9 the outer level is present, so the fallback is not used, and `once` is the inner `none`. A second `??` deals with that one, and `twice` is a plain `int`, `0`. That first `?? 0` looks as if it gives an `int`, and it does compile — but only because the `0` is made into a present `int?` to match the inner level. `once` is an `int?`, which is why the program compares it with `none` instead of printing it. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Optionals/NestedOptional){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // A player who has not played yet has no score, so the team sheet stores each // score as an `int?`. Now look a player up by number. The answer can be // missing for two different reasons: // // none nobody wears that number // .Some(none) the player exists, but has no score yet // .Some(.Some(score)) the player exists and has scored // // The type that holds all three is `int??`, an optional of an optional. Rux // never squashes the two levels into one, so the two kinds of "nothing" stay // different and you can tell them apart. import Io::PrintLine; struct Player { number: int; score: int?; } // `player.score` is an `int?`. Returned from here it becomes a present `int??` // on its own, even when the score inside is `none`. Only the `none` at the // bottom means "not found". func ScoreOf(players: Player[..], number: int) -> int?? { for player in players { if player.number == number { return player.score; } } return none; } // Each `?` in a pattern opens one level. `score??` is "a present, present // score". `none?` is "a present `none`": the player was found but has no // score. Plain `none` is the outer absence. func Report(players: Player[..], number: int) { match ScoreOf(players, number) { score?? => PrintLine("#{} scored {}", number, score), none? => PrintLine("#{} has not played yet", number), none => PrintLine("#{} is not on the team", number) } } // The same three cases in the long spelling. func ReportLong(players: Player[..], number: int) { match ScoreOf(players, number) { .Some(.Some(score)) => PrintLine("#{} scored {}", number, score), .Some(none) => PrintLine("#{} has not played yet", number), none => PrintLine("#{} is not on the team", number) } } func Main() -> int { let players = [ Player { number: 7, score: 12 }, Player { number: 9, score: none } ]; Report(players, 7); Report(players, 9); Report(players, 3); ReportLong(players, 9); // `??` opens just one level too. For #9 the outer level is present, so // the fallback is not used and `once` is the inner `none`, still an // `int?`. A second `??` deals with that one. let once = ScoreOf(players, 9) ?? 0; let twice = once ?? 0; PrintLine("#9 opened once is still none: {}", once == none); PrintLine("#9 opened twice: {}", twice); // Watch out: that first `?? 0` looks as if it gives an `int`, and it does // compile, but only because the `0` is made into a present `int?` to // match the inner level. Try printing `once` directly: the compiler // refuses, because an `int?` is not something `PrintLine` can show. return 0; } ``` ## Run it ```sh cd Examples/Optionals/NestedOptional rux run ``` ```text #7 scored 12 #9 has not played yet #3 is not on the team #9 has not played yet #9 opened once is still none: true #9 opened twice: 0 ``` ## Common mistakes ::mistake **Treating the result of one `??` as plain.**:br`PrintLine("{}", once);` fails with: ```text error: no matching overload for 'PrintLine' with argument types (char8[..], int?) ``` One `??` opened only the outer level; open the inner one too. :: ::mistake **Chaining the two fallbacks without parentheses.**:br`??` groups from the right, so `ScoreOf(players, 9) ?? 0 ?? 0` means `ScoreOf(players, 9) ?? (0 ?? 0)` and fails with: ```text error: operator '??' requires an optional left operand, but found 'int' ``` Write `(ScoreOf(players, 9) ?? 0) ?? 0`, or use two `let`s as the lesson does. :: ::mistake **Forgetting the middle case.**:br A match with only `score??` and `none` arms is not exhaustive: ```text error: match on 'int??' is not exhaustive; missing .Some(none) ``` The player who exists but has no score needs its own arm. :: ## Try it yourself 1. Add a player `Player { number: 11, score: 0 }` and check that #11 is reported as having scored 0, not as "has not played yet". 2. Write `Played(players: Player[..], number: int) -> bool?` that is `none` for an unknown number, and `true` or `false` otherwise. 3. Replace the three-arm match with `??`: print `-1` for "not on the team" and `0` for "has not played yet". ## Learn more - [Presence](https://rux-lang.dev/docs/learn/presence) — the one-level patterns `score?` and `none` - [Optional pointer](https://rux-lang.dev/docs/learn/optional-pointer) — the same care with `(*T)?` and `*T?`, in the Memory part - [Nested fallible](https://rux-lang.dev/docs/learn/nested-fallible) — an optional inside a fallible, `int? ! E`, in the Errors part # Part 9: Errors An [optional](https://rux-lang.dev/docs/learn/optional) can say that a value is missing, but never why. This part gives a failure a voice. A *fallible* `T ! E` is an answer of type `T` or an error of type `E` saying what went wrong, and the compiler makes sure no failure is ever dropped without the code saying so. By the end of the part you can write functions that fail precisely, decide at each step whether to handle a failure or pass it on, and tell a failure the caller can fix from a bug that should stop the program. ## What you will learn - Declaring a fallible with `T ! E`, or `! E` when there is no answer, and failing with `fail`. - Opening an outcome with `.Success` and `.Failure`, and why a fallible result cannot be ignored. - Recovering with `catch` — one arm per case, or one `else` fallback for all. - Passing a failure to the caller with `?`, and adding context on the way with `? else (e => ...)`. - Designing error types: a variant of cases, or a sum of unrelated errors `A | B`. - A fallible `Main`, turning absence into an error with `?? fail`, and nested fallibles. - `Panic`, `Assert` and `DebugAssert` for the situations only a bug can reach. ## Which error tool? Most of this part is choosing the right tool for one moment in the code. The questions run in this order: ```mermaid flowchart TD start(["Something can go wrong"]) --> bug{"Can it happen in a
program with no bugs?"} bug -- "no, only a bug" --> stop["`Panic`, `Assert`, `DebugAssert`
9.15–9.16"] bug -- "yes" --> why{"Does the caller need
to know why?"} why -- "no" --> opt["An optional `T?`
Part 8"] why -- "yes" --> fal["A fallible `T ! E`, or `! E`
9.1–9.3"] fal --> who{"Who decides what
the failure means?"} who -- "this function" --> reason{"Does the reason
matter here?"} reason -- "yes" --> arms["`match`, or `catch` with
one arm per case
9.4, 9.6"] reason -- "no" --> fallback["`catch { else => fallback }`
or a deliberate discard
9.5, 9.7"] who -- "the caller" --> same{"Does the error already
fit the caller's type?"} same -- "yes" --> q["`?` passes it on
9.8, 9.11"] same -- "no, or context to add" --> mapped["`? else (e => ...)`
9.10"] ``` ## Lessons | | Lesson | What you will learn | | ---- | -------------------------------------------------------------------- | -------------------------------------------------------------------------------------- | | 9.1 | [Fallible](https://rux-lang.dev/docs/learn/fallible) | return either a value or an error with `T ! E` | | 9.2 | [Fail](https://rux-lang.dev/docs/learn/fail) | report a failure with `fail` | | 9.3 | [Unit fallible](https://rux-lang.dev/docs/learn/unit-fallible) | a function that returns nothing but can still fail: `! E` | | 9.4 | [Outcome](https://rux-lang.dev/docs/learn/outcome) | match a result as `.Success` or `.Failure` | | 9.5 | [Discard](https://rux-lang.dev/docs/learn/discard) | why the compiler refuses to let a result be ignored, and how to discard one on purpose | | 9.6 | [Catch](https://rux-lang.dev/docs/learn/catch) | handle the ways an operation can fail with `catch` | | 9.7 | [Catch fallback](https://rux-lang.dev/docs/learn/catch-fallback) | turn any failure into a default value with `catch { else => ... }` | | 9.8 | [Propagate](https://rux-lang.dev/docs/learn/propagate) | hand a failure straight to the caller with `?` instead of matching it | | 9.9 | [Error variant](https://rux-lang.dev/docs/learn/error-variant) | describe the ways an operation can fail with a variant | | 9.10 | [Error mapping](https://rux-lang.dev/docs/learn/error-mapping) | add context to an error as it passes through with `? else (e => ...)` | | 9.11 | [Error sum](https://rux-lang.dev/docs/learn/error-sum) | fail in more than one way with an error sum `A | B` | | 9.12 | [Fallible main](https://rux-lang.dev/docs/learn/fallible-main) | let `Main` itself fail, and see the exit status | | 9.13 | [Absence to error](https://rux-lang.dev/docs/learn/absence-to-error) | turn a missing value into a failure with `?? fail` | | 9.14 | [Nested fallible](https://rux-lang.dev/docs/learn/nested-fallible) | results inside results: `T? ! E` and `(T ! E1) ! E2` | | 9.15 | [Panic](https://rux-lang.dev/docs/learn/panic) | stop the program when something impossible happens | | 9.16 | [Assert](https://rux-lang.dev/docs/learn/assert) | check an assumption while the program runs | ## Before you start Finish [Part 8: Optionals](https://rux-lang.dev/docs/learn/optionals) first — fallibles are built on the same ideas, and several lessons compare the two side by side. You also need [variants](https://rux-lang.dev/docs/learn/variant) from Part 6 and the patterns of [Part 7](https://rux-lang.dev/docs/learn/patterns). Each lesson's package is in the Examples repository's `Errors/` folder: ```sh cd Examples/Errors/Fallible rux run ``` ## After this part [Part 10: Sum types](https://rux-lang.dev/docs/learn/sum-types) takes the `A | B` you met in [Error sum](https://rux-lang.dev/docs/learn/error-sum) and makes it a type of its own, usable anywhere. Before moving on, try the checkpoint project [Calculator](https://rux-lang.dev/docs/learn/calculator): it evaluates sums and key-press tapes where every way a calculation can fail is a case of an error variant. For the rules behind this part, see [Error handling](https://rux-lang.dev/docs/lang/errors/overview) and [Fatal errors](https://rux-lang.dev/docs/lang/errors/panics) in the Rux Reference, and [Panic](https://rux-lang.dev/docs/api/core/diagnostics#panic) and [Assert](https://rux-lang.dev/docs/api/core/diagnostics#assert) in the API reference. # Fallible ::note **You'll need**: [Optional](https://rux-lang.dev/docs/learn/optional), [Variant](https://rux-lang.dev/docs/learn/variant) :: An [optional](https://rux-lang.dev/docs/learn/optional) says that a value is missing, but never *why*. Often the why is exactly what the caller needs. Dividing 12 by 0 and dividing 13 by 4 both fail to give an exact answer — for different reasons that deserve different replies. A *fallible* type carries the reason with it. `int ! DivideError` reads "an `int`, or else a `DivideError`". This lesson introduces the type and shows how a caller finds out which of the two it got; the rest of Part 9 is about the many ways of handling the second one. ## Two channels A fallible has two channels. The **success** channel holds the answer. The **failure** channel holds an *error* — an ordinary value describing what went wrong. The error type is whatever suits, and a [variant](https://rux-lang.dev/docs/learn/variant) is a natural fit: one case for each way the operation can go wrong. ```rux variant DivideError { ByZero, NotExact(int) } ``` `NotExact` carries the remainder with it, so the caller can say how far off the division was. The signature puts the two channels side by side, success type first, error type after the `!`: ```rux func ExactDivide(numerator: int, denominator: int) -> int ! DivideError { ``` | Type | Holds | | ------------------- | --------------------------------------------------- | | `int` | always an `int` | | `int?` | an `int`, or nothing — with no reason given | | `int ! DivideError` | an `int`, or a `DivideError` saying what went wrong | ## The success needs no ceremony Inside a fallible function, `return value;` is the success, just as a plain value returned from an `int?` function is a present one. `fail`, the subject of the [next lesson](https://rux-lang.dev/docs/learn/fail), leaves through the failure channel instead: ```rux if denominator == 0 { fail DivideError::ByZero; } if numerator % denominator != 0 { fail DivideError::NotExact(numerator % denominator); } return numerator / denominator; ``` ```mermaid flowchart LR invoke["`ExactDivide(12, 0)`"] --> body{"Which way does
the function leave?"} body -- "`return value;`" --> s["`.Success(value)`
the success channel"] body -- "`fail error;`" --> f["`.Failure(error)`
the failure channel"] s --> caller["The caller opens it:
`match`, `catch` or `?`"] f --> caller ``` ## Opening the result What comes back is not yet an `int`. To use the answer, find out which channel it came through. `.Success(value)` matches the answer and binds it; `.Failure(error)` matches an error and binds that: ```rux match ExactDivide(numerator, denominator) { .Success(value) => PrintLine("{} / {} = {}", numerator, denominator, value), .Failure(error) => Explain(numerator, denominator, error) } ``` The error is an ordinary `DivideError`, so `Explain` uses a second `match` to pick out its case — the same [variant match](https://rux-lang.dev/docs/learn/variant-match) you already know: ```rux match error { DivideError::ByZero => PrintLine("{} / {} fails: no dividing by zero", numerator, denominator), DivideError::NotExact(remainder) => PrintLine("{} / {} fails: {} left over", numerator, denominator, remainder) } ``` The match must cover both channels. A failure can never slip past unnoticed: the compiler refuses a match that forgets `.Failure`, and — as you will see in [Discard](https://rux-lang.dev/docs/learn/discard) — a call whose result nobody looks at. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Errors/Fallible){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // An optional says that a value is missing, but never why. Often the why is exactly what the // caller needs: dividing 12 by 0 and dividing 13 by 4 both fail to give an exact answer, for // different reasons that deserve different replies. // // `int ! DivideError` reads "an `int`, or else a `DivideError`". A fallible like this has two // channels. The success channel holds the answer. The failure channel holds an error, a value // describing what went wrong. The error type is whatever suits, and a variant is a natural fit: // one case for each way the operation can go wrong. // // The success needs no ceremony. `return value;` in a fallible function is the success, just as a // plain value returned from an `int?` function is a present one. import Io::PrintLine; // The ways an exact division can go wrong. `NotExact` carries the remainder with it. variant DivideError { ByZero, NotExact(int) } // The signature says it all: this produces an `int`, or a `DivideError`. `fail`, the subject of // the next lesson, leaves through the failure channel; an ordinary `return` is the success. func ExactDivide(numerator: int, denominator: int) -> int ! DivideError { if denominator == 0 { fail DivideError::ByZero; } if numerator % denominator != 0 { fail DivideError::NotExact(numerator % denominator); } return numerator / denominator; } // To use the answer, find out which channel it came through. `.Success(value)` matches the answer // and binds it; `.Failure(error)` matches an error and binds that. The error is an ordinary // `DivideError`, so a second match picks out its case. func Report(numerator: int, denominator: int) { match ExactDivide(numerator, denominator) { .Success(value) => PrintLine("{} / {} = {}", numerator, denominator, value), .Failure(error) => Explain(numerator, denominator, error) } } func Explain(numerator: int, denominator: int, error: DivideError) { match error { DivideError::ByZero => PrintLine("{} / {} fails: no dividing by zero", numerator, denominator), DivideError::NotExact(remainder) => PrintLine("{} / {} fails: {} left over", numerator, denominator, remainder) } } func Main() -> int { Report(12, 4); Report(12, 0); Report(13, 4); // A fallible is not an `int` until it has been opened. `let half = ExactDivide(12, 2) / 2;` // is rejected, and so is calling `ExactDivide(12, 4);` and ignoring what comes back: a // failure can never be dropped without the code saying so. return 0; } ``` ## Run it ```sh cd Examples/Errors/Fallible rux run ``` ```text 12 / 4 = 3 12 / 0 fails: no dividing by zero 13 / 4 fails: 1 left over ``` ## Common mistakes ::mistake **Using a fallible as if it were the answer.**:br`let half = ExactDivide(12, 2) / 2;` fails with: ```text error: operator '/' cannot combine left operand 'int ! DivideError' with right operand 'int' ``` The `int` is inside the success channel and has to be taken out first — with `match` here, and later with `catch` or `?`. :: ::mistake **Calling it and ignoring what comes back.**:br`ExactDivide(12, 4);` on its own is an error, with a note: ```text error: fallible result of type 'int ! DivideError' is discarded a failure that nothing handles is lost ``` [Discard](https://rux-lang.dev/docs/learn/discard) shows how to ignore a result on purpose. :: ::mistake **Returning the error.**:br`return DivideError::ByZero;` is refused with: ```text error: 'return' value must have type 'int ! DivideError', but found 'DivideError' ``` `return` is the success channel; an error leaves with `fail`. :: ## Try it yourself 1. Add `Report(0, 5);` to `Main`. Predict the line it prints before you run it. 2. Delete the `.Failure` arm from `Report`'s match and read the error. Which pattern does the compiler say is missing? 3. Add a case `Negative` to `DivideError` and fail with it when the denominator is below zero. Where does the compiler send you next, and why? ## Learn more - [Fail](https://rux-lang.dev/docs/learn/fail) — the failure channel's `return` - [Outcome](https://rux-lang.dev/docs/learn/outcome) — storing, passing and building a fallible's result - [Optional](https://rux-lang.dev/docs/learn/optional) — the simpler form, for a value that may be missing with no reason given - [Error handling](https://rux-lang.dev/docs/lang/errors/overview) in the Rux Reference # Fail ::note **You'll need**: [Fallible](https://rux-lang.dev/docs/learn/fallible), [Struct](https://rux-lang.dev/docs/learn/struct) :: A fallible function has two ways out. `return value;` is the success, as the [previous lesson](https://rux-lang.dev/docs/learn/fallible) showed. `fail` is the other one: it leaves the function at once through the failure channel, carrying an error value for the caller. This lesson is a cash machine. A withdrawal either answers with the new balance or refuses — and when it refuses, it says exactly how much money was missing. ## The error is plain data An error can be any type you like. Here it is a [struct](https://rux-lang.dev/docs/learn/struct), so it can report exactly what went wrong — how much the account held and how much was asked for: ```rux struct ShortOfFunds { balance: int; requested: int; } ``` There is nothing special about the type itself. It becomes an error only because a signature names it after the `!`: ```rux func Withdraw(balance: int, amount: int) -> int ! ShortOfFunds { ``` ## fail leaves at once `fail` builds the error and hands it over in one statement. Nothing after a `fail` runs, just as nothing after a `return` does: ```rux if amount > balance { fail ShortOfFunds { balance: balance, requested: amount }; } // Only reached when the money is there. return balance - amount; ``` | Statement | Leaves through | The caller sees | | ---------------------------- | ------------------- | ----------------- | | `return balance - amount;` | the success channel | `.Success(left)` | | `fail ShortOfFunds { ... };` | the failure channel | `.Failure(error)` | ## Reading the details Because the error is a struct, the caller reads its fields like any other. The refusal message works out the shortfall from the two numbers the error carried: ```rux .Failure(error) => PrintLine("take {} from {}: refused, {} short", amount, balance, error.requested - error.balance) ``` Taking exactly the whole balance is fine — `amount > balance` is false for 100 and 100, so `Report(100, 100)` leaves 0. An empty account refuses even 5. ## Where fail is allowed `fail` has two rules, and the compiler enforces both. Its value must have the error type named after the `!` — a `ShortOfFunds` here, not a number. And it belongs only in a function that can fail: `Main` returns a plain `int`, so a `fail` there has nowhere to go. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Errors/Fail){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // A fallible function has two ways out. `return value;` is the success, as the previous lesson // showed. `fail` is the other one: it leaves the function at once through the failure channel, // carrying an error value for the caller. // // The error can be any type you like. Here it is a struct, so it can report exactly what went // wrong — how much money the account held and how much was asked for. `fail ShortOfFunds { ... };` // builds that struct and hands it over in one statement. Nothing after a `fail` runs, just as // nothing after a `return` does. import Io::PrintLine; // The error: plain data describing the problem, nothing special about the type itself. struct ShortOfFunds { balance: int; requested: int; } // Answers with the new balance, or fails with the details of why it could not. func Withdraw(balance: int, amount: int) -> int ! ShortOfFunds { if amount > balance { fail ShortOfFunds { balance: balance, requested: amount }; } // Only reached when the money is there. return balance - amount; } func Report(balance: int, amount: int) { match Withdraw(balance, amount) { .Success(left) => PrintLine("take {} from {}: {} left", amount, balance, left), .Failure(error) => PrintLine("take {} from {}: refused, {} short", amount, balance, error.requested - error.balance) } } func Main() -> int { Report(100, 30); Report(100, 100); Report(100, 130); Report(0, 5); // `fail` must carry a value of the error type named after the `!`. `fail 30;` inside // `Withdraw` is rejected — "'fail' value must have type 'ShortOfFunds', but found 'int'". // And `fail` belongs only in a function that can fail: here in `Main`, which returns a plain // `int`, it is an error too — "'fail' needs an enclosing fallible function, but this // function returns 'int'". return 0; } ``` ## Run it ```sh cd Examples/Errors/Fail rux run ``` ```text take 30 from 100: 70 left take 100 from 100: 0 left take 130 from 100: refused, 30 short take 5 from 0: refused, 5 short ``` ## Common mistakes ::mistake **Failing with the wrong type.**:br`fail 30;` inside `Withdraw` is rejected: ```text error: 'fail' value must have type 'ShortOfFunds', but found 'int' ``` The error type is part of the signature, and every `fail` must match it. :: ::mistake **fail in a function that cannot fail.**:br In `Main`, which returns `int`, a `fail` is an error: ```text error: 'fail' needs an enclosing fallible function, but this function returns 'int' ``` The help line says what to do: ```text declare the function's error channel, as in '-> T ! E' or '-> ! E' ``` :: ## Try it yourself 1. Add `Report(100, 101);` and predict the shortfall it prints. 2. Write `Deposit(balance: int, amount: int) -> int ! TooMuch` that refuses when the new balance would pass 1000, with a `TooMuch` struct that says by how much. 3. Make `Withdraw` refuse a negative amount too. Is `ShortOfFunds` the right error for that? [Error variant](https://rux-lang.dev/docs/learn/error-variant) shows the better shape. ## Learn more - [Unit fallible](https://rux-lang.dev/docs/learn/unit-fallible) — a fallible function with no answer to give back - [Error variant](https://rux-lang.dev/docs/learn/error-variant) — one error type for several ways to fail - [Absence to error](https://rux-lang.dev/docs/learn/absence-to-error) — `fail` as the fallback of `??` - [Struct](https://rux-lang.dev/docs/learn/struct) — the type the error is built from # Unit fallible ::note **You'll need**: [Fail](https://rux-lang.dev/docs/learn/fail), [Mutable reference](https://rux-lang.dev/docs/learn/mutable-reference) :: Some operations have no answer to give back. When a withdrawal works, the money is gone from the account and there is nothing more to say. But it can still fail, and the caller still needs to know. Such a function is written `-> ! E`: an error type after the `!`, and nothing before it. ## ! E is () ! E `! E` is short for `() ! E`. The `()` is the *unit* — the empty [tuple](https://rux-lang.dev/docs/learn/tuple), whose only value is also written `()`. It is a success that carries no information beyond "it worked". Both spellings compile and mean the same type; the short one is what you will see everywhere: ```rux func Withdraw(account: &var Account, amount: int) -> ! ShortOfFunds { ``` The account is a [mutable reference](https://rux-lang.dev/docs/learn/mutable-reference), so the function changes the caller's account in place. The only thing left to report is whether that happened. ## Three ways out Because there is no value to return, the function succeeds simply by reaching its end. A bare `return;` succeeds early, and only `fail` makes it fail: ```rux if amount == 0 { // Nothing to do, and that counts as success. return; } if amount > account.balance { fail ShortOfFunds { missing: amount - account.balance }; } account.balance -= amount; // Falling off the end: success. ``` | The function… | The outcome | | ------------------------- | ------------------------- | | reaches its closing brace | success | | runs `return;` | success, early | | runs `fail error;` | failure, carrying `error` | ## Matching a unit success The success channel still holds a value — the unit — so its pattern has parentheses with `()` inside: ```rux match Withdraw(account, amount) { .Success(()) => PrintLine("take {}: done, {} left", amount, account.balance), .Failure(error) => PrintLine("take {}: refused, {} short", amount, error.missing) } ``` `.Success(_)` works too, since `_` matches any value, the unit included. What does not work is leaving the parentheses out: `.Success` alone is a pattern with no payload, and the success channel always has one. The output follows the balance as it changes. Taking 0 succeeds without touching anything, 80 is refused while 60 is left, and the next 60 empties the account — so even 1 is refused after that. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Errors/UnitFallible){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // Some operations have no answer to give back. When a withdrawal works, the money is gone from // the account and there is nothing more to say. Such a function is written `-> ! E`: an error // type after the `!`, and nothing before it. // // `! E` is short for `() ! E`. The `()` is the unit, the empty tuple, whose only value is also // `()` — a success that carries no information beyond "it worked". Because there is no value to // return, the function succeeds simply by reaching its end. A bare `return;` succeeds early, and // only `fail` makes it fail. import Io::PrintLine; struct Account { balance: int; } struct ShortOfFunds { missing: int; } // Changes the account in place; the only thing to report is whether that happened. func Withdraw(account: &var Account, amount: int) -> ! ShortOfFunds { if amount == 0 { // Nothing to do, and that counts as success. return; } if amount > account.balance { fail ShortOfFunds { missing: amount - account.balance }; } account.balance -= amount; // Falling off the end: success. } func Attempt(account: &var Account, amount: int) { // The success pattern holds the unit, so it is written `.Success(())`. match Withdraw(account, amount) { .Success(()) => PrintLine("take {}: done, {} left", amount, account.balance), .Failure(error) => PrintLine("take {}: refused, {} short", amount, error.missing) } } func Main() -> int { var account = Account { balance: 100 }; Attempt(account, 40); Attempt(account, 0); Attempt(account, 80); Attempt(account, 60); Attempt(account, 1); return 0; } ``` ## Run it ```sh cd Examples/Errors/UnitFallible rux run ``` ```text take 40: done, 60 left take 0: done, 60 left take 80: refused, 20 short take 60: done, 0 left take 1: refused, 1 short ``` ## Common mistakes ::mistake **Returning a value from a ! E function.**:br`return 0;` inside `Withdraw` is an error: ```text error: 'return' value must have type '! ShortOfFunds', but found 'int' ``` There is no success value to give; write `return;` or let the function reach its end. :: ::mistake **Writing .Success without the unit.**:br`.Success => ...` is refused with: ```text error: pattern '.Success' expects 1 field, but found 0 ``` Write `.Success(())` or `.Success(_)`. :: ::mistake **Calling it as a plain statement.**:br`Withdraw(account, 40);` on its own is an error: ```text error: fallible result of type '! ShortOfFunds' is discarded ``` No value comes back, but the failure still does. [Discard](https://rux-lang.dev/docs/learn/discard) explains how to ignore it on purpose. :: ## Try it yourself 1. Change the signature to the long spelling `-> () ! ShortOfFunds` and check that the program still compiles and prints the same. 2. Add `Deposit(account: &var Account, amount: int) -> ! TooMuch` that refuses when the balance would pass 1000. 3. Replace `.Success(())` with `.Success(_)`. Does anything change? ## Learn more - [Fail](https://rux-lang.dev/docs/learn/fail) — the failure channel's `return` - [Discard](https://rux-lang.dev/docs/learn/discard) — the deliberate way to ignore a `! E` result - [Tuple](https://rux-lang.dev/docs/learn/tuple) — the empty tuple `()` is the unit - [Mutable reference](https://rux-lang.dev/docs/learn/mutable-reference) — how `Withdraw` changes the caller's account # Outcome ::note **You'll need**: [Fail](https://rux-lang.dev/docs/learn/fail), [Match expression](https://rux-lang.dev/docs/learn/match-expression) :: What a fallible call hands back is an *outcome*: one value that is either a success or a failure. So far every outcome was matched the moment it arrived, but nothing requires that. An outcome is an ordinary value. It can sit in a variable, be passed to a function, and be looked at later — and you can even build one by hand. ## Store first, look later Each call's outcome is stored first and examined afterwards: ```rux let party = Share(12, 4); let empty = Share(12, 0); Describe(party); Describe(empty); ``` `Describe` takes the outcome as a parameter like any other value. Its type is written exactly as a return type would be: ```rux func Describe(outcome: int ! NobodyToShare) { ``` ## Patterns look inside `.Success(...)` and `.Failure(...)` are the two shapes an outcome can have. In a `match` they are patterns, and whatever is written inside the parentheses is matched against the payload — a name binds it, a literal compares it, `_` ignores it: ```rux match outcome { .Success(0) => PrintLine("not even one slice each"), .Success(each) => PrintLine("{} slices each", each), .Failure(error) => PrintLine("{} slices and nobody to eat them", error.slices) } ``` | Pattern | Matches | Binds | | ----------------- | -------------------------- | --------- | | `.Success(0)` | a success whose value is 0 | nothing | | `.Success(each)` | any success | the value | | `.Failure(error)` | any failure | the error | | `.Failure(_)` | any failure | nothing | Order matters, as in every [match](https://rux-lang.dev/docs/learn/match-expression): `.Success(0)` comes before `.Success(each)`, because the general arm would otherwise take the zero too. The compiler catches that order and calls the specific arm unreachable. ## Building an outcome by hand Outside a match, the same two shapes are constructors. No function needs to be called: ```rux let promised: int ! NobodyToShare = .Success(2); let refused: int ! NobodyToShare = .Failure(NobodyToShare { slices: 8 }); ``` The type annotation is required. `.Success(2)` says which channel the value goes in, but not what the other channel would have held — and an outcome's type needs both. ## A match that produces a value A `match` on an outcome can be an expression, with one value per shape: ```rux let eaten = match party { .Success(each) => each * 4, .Failure(_) => 0 }; ``` Twelve slices shared among four is three each, so four people eat 12. A match on an outcome must cover both shapes — a failure can never slip through unnoticed. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Errors/Outcome){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // What a fallible call hands back is an outcome: one value that is either a success or a // failure. It is an ordinary value. It can sit in a variable, be passed to a function, and be // looked at later. // // `.Success(...)` and `.Failure(...)` are the two shapes an outcome can have. In a `match` they // are patterns, and whatever is written inside the parentheses is matched against the payload — // a name binds it, a literal compares it. Outside a match they are constructors, so an outcome // can also be built by hand, without calling anything. import Io::PrintLine; struct NobodyToShare { slices: int; } // Shares out pizza slices evenly. It fails when there is nobody to share them with. func Share(slices: int, people: int) -> int ! NobodyToShare { if people == 0 { fail NobodyToShare { slices: slices }; } return slices / people; } // An outcome arrives as a parameter like any other value. func Describe(outcome: int ! NobodyToShare) { match outcome { .Success(0) => PrintLine("not even one slice each"), .Success(each) => PrintLine("{} slices each", each), .Failure(error) => PrintLine("{} slices and nobody to eat them", error.slices) } } func Main() -> int { // Each call's outcome is stored first and examined afterwards. let party = Share(12, 4); let empty = Share(12, 0); Describe(party); Describe(empty); Describe(Share(3, 4)); // The same two shapes as constructors. The type annotation says which fallible is meant. let promised: int ! NobodyToShare = .Success(2); let refused: int ! NobodyToShare = .Failure(NobodyToShare { slices: 8 }); Describe(promised); Describe(refused); // A match can also produce a value, one per shape. let eaten = match party { .Success(each) => each * 4, .Failure(_) => 0 }; PrintLine("eaten at the party: {}", eaten); // A match on an outcome must cover both shapes. Drop the `.Failure` arm above and the // compiler refuses: "match on 'int ! NobodyToShare' is not exhaustive; missing .Failure(_)". // A failure can never slip through unnoticed. return 0; } ``` ## Run it ```sh cd Examples/Errors/Outcome rux run ``` ```text 3 slices each 12 slices and nobody to eat them not even one slice each 2 slices each 8 slices and nobody to eat them eaten at the party: 12 ``` ## Common mistakes ::mistake **Forgetting the failure arm.**:br Drop the `.Failure` arm and the compiler refuses: ```text error: match on 'int ! NobodyToShare' is not exhaustive; missing .Failure(_) ``` :: ::mistake **A constructor with nothing to say what it builds.**:br`let promised = .Success(2);` is an error: ```text error: cannot infer the type of 'promised' from a native constructor with an unknown channel ``` Annotate the variable, as the help line shows: ```text let value: int32 ! ParseError = .Success(1i32); ``` :: ::mistake **The general arm first.**:br Swap the two success arms and `.Success(0)` is rejected: ```text error: match arm is unreachable because earlier arms already match every value it matches ``` Put specific patterns before general ones. :: ## Try it yourself 1. Add an arm that prints `"exactly one slice each"`. Where in the match must it go? 2. Build an outcome by hand with `.Failure(NobodyToShare { slices: 0 })` and pass it to `Describe`. 3. Store `Share(7, 2)` in a variable, then use one `match` expression to work out how many slices are eaten and another to print it. ## Learn more - [Match expression](https://rux-lang.dev/docs/learn/match-expression) — a `match` that produces a value - [Catch](https://rux-lang.dev/docs/learn/catch) — a shorter way to deal with only the failure - [Generic outcome](https://rux-lang.dev/docs/learn/generic-outcome) — functions that accept any `T ! E` # Discard ::note **You'll need**: [Unit fallible](https://rux-lang.dev/docs/learn/unit-fallible), [Outcome](https://rux-lang.dev/docs/learn/outcome) :: A fallible result cannot be ignored. Calling a fallible function as a bare statement, with nothing looking at what it returns, is a compile error — otherwise a failure could vanish without anyone noticing. Sometimes ignoring it is exactly right, though. A cash machine whose receipt printer has run out of paper should still hand over the money. This lesson shows why the compiler is strict and how to tell it, in the code, that you mean it. ## A bare call is refused `PrintReceipt` is a [unit fallible](https://rux-lang.dev/docs/learn/unit-fallible): it either printed the receipt or it did not. Call it the way you call `PrintLine` and the compiler stops you: ```rux PrintReceipt(printer, amount); ``` ```text error: fallible result of type '! OutOfPaper' is discarded note: a failure that nothing handles is lost help: propagate it with '?', recover with 'catch', or match both '.Success' and '.Failure' ``` Binding the result to `_` does not help: `let _ = PrintReceipt(printer, amount);` is refused the same way, with the note `binding a fallible to '_' does not handle its failure`. A `_` only throws the value away; it does nothing about the failure inside it. ## Discarding on purpose The deliberate discard is one phrase: ```rux PrintReceipt(printer, amount) catch { else => {} }; ``` It says "I know this can fail, and it does not matter here". `catch` is the subject of the [next lesson](https://rux-lang.dev/docs/learn/catch); for now, read the line as that one phrase. The third withdrawal in the output finds the paper gone, hands over the money anyway, and prints no receipt. ## Only for a unit success The empty block `{}` stands in for the missing success, and an empty block has no value — it completes with `()`. So this phrase works only for a `! E` function. One that succeeds with a value, such as `ExactDivide` from [Fallible](https://rux-lang.dev/docs/learn/fallible), is discarded with a match that names both channels and does nothing in either: ```rux match ExactDivide(12, 4) { .Success(_) => {}, .Failure(_) => {} } ``` | What you write | Result | | ---------------------------------------------------------- | ------------------------------------- | | `PrintReceipt(printer, amount);` | error: the result is discarded | | `let _ = PrintReceipt(printer, amount);` | error: binding to `_` handles nothing | | `let r = PrintReceipt(printer, amount);` | a warning if `r` is never read | | `PrintReceipt(printer, amount) catch { else => {} };` | a deliberate discard of a `! E` | | a `match` with `.Success(_) => {}` and `.Failure(_) => {}` | a deliberate discard of any fallible | ## Why PrintLine was never a problem `PrintLine` is not fallible. It returns an optional, `IoError?`, saying whether the console write had trouble — and an optional may be ignored. That is why every lesson so far could call it as a bare statement. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Errors/Discard){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // A fallible result cannot be ignored. Calling a fallible function as a bare statement, with // nothing looking at what it returns, is a compile error — otherwise a failure could vanish // without anyone noticing. // // Sometimes ignoring it is exactly right, though. A cash machine whose receipt printer has run // out of paper should still hand over the money. For that there is a deliberate discard: // `F() catch { else => {} };`. It says, in the code, "I know this can fail and it does not // matter here". `catch` is the subject of a later lesson; for now, read it as that one phrase. import Io::PrintLine; struct Printer { paper: int; } struct OutOfPaper { } // A unit fallible: it either printed the receipt or it did not. func PrintReceipt(printer: &var Printer, amount: int) -> ! OutOfPaper { if printer.paper == 0 { fail OutOfPaper {}; } printer.paper -= 1; PrintLine(" receipt: {} taken", amount); } func Withdraw(printer: &var Printer, amount: int) { PrintLine("hand over {}", amount); // The line below does not compile: // // PrintReceipt(printer, amount); // // error: fallible result of type '! OutOfPaper' is discarded // note: a failure that nothing handles is lost // help: propagate it with '?', recover with 'catch', or match both '.Success' and '.Failure' // // Writing `let _ = PrintReceipt(printer, amount);` is refused the same way: binding a // fallible to `_` does not handle its failure either. // The deliberate discard: a missing receipt is not worth stopping for. The empty block `{}` // stands in for the missing success, so this works only for a `! E` function. One that // succeeds with a value, such as an `int`, is discarded with a match whose arms are // `.Success(_) => {}` and `.Failure(_) => {}`. PrintReceipt(printer, amount) catch { else => {} }; } func Main() -> int { var printer = Printer { paper: 2 }; Withdraw(printer, 20); Withdraw(printer, 50); Withdraw(printer, 10); // `PrintLine` itself is not fallible. It returns an optional, `IoError?`, saying whether // the console write had trouble, and an optional may be ignored — which is why every lesson // so far could call it as a bare statement. return 0; } ``` ## Run it ```sh cd Examples/Errors/Discard rux run ``` ```text hand over 20 receipt: 20 taken hand over 50 receipt: 50 taken hand over 10 ``` ## Common mistakes ::mistake **Hiding the result behind `_`.**:br`let _ = PrintReceipt(printer, amount);` is an error, with a note: ```text error: fallible result of type '! OutOfPaper' is discarded binding a fallible to '_' does not handle its failure ``` Write the `catch { else => {} }` phrase instead. :: ::mistake **The unit phrase on a fallible with a value.**:br On an `int ! E` result, `catch { else => {} }` is an error: ```text error: a block arm completes with '()', but 'catch' must recover a value of type 'int' ``` Use the two-arm `match` above. :: ::mistake **Storing the result and forgetting it.**:br`let r = ExactDivide(12, 4);` with `r` never read compiles, but warns: ```text fallible local 'r' is never read; its failure is never handled ``` Take the warning seriously — the failure is just as lost. :: ## Try it yourself 1. Start the printer with no paper at all. What does the output look like? 2. Replace the discard with a `match` that prints `" no receipt: out of paper"` on failure. 3. Write the bare call `PrintReceipt(printer, amount);` back in and read all three lines of the error. ## Learn more - [Catch](https://rux-lang.dev/docs/learn/catch) — the full form of `catch`, with one arm per error - [Catch fallback](https://rux-lang.dev/docs/learn/catch-fallback) — `catch { else => ... }` with a real fallback value - [Optional](https://rux-lang.dev/docs/learn/optional) — the type `PrintLine` returns, which may be ignored # Catch ::note **You'll need**: [Outcome](https://rux-lang.dev/docs/learn/outcome), [Variant match](https://rux-lang.dev/docs/learn/variant-match), [Guard](https://rux-lang.dev/docs/learn/guard) :: `catch` turns a fallible back into a plain value. `outcome catch { arms }` lets a success straight through, unchanged. A failure goes to the arms, which see only the error and must produce a value of the success type in its place. The example reads a digit someone typed. A few typing slips are easy to forgive: a capital O was surely meant as 0, and a lower-case l as 1. Anything else becomes -1, meaning unreadable. ## Success passes, failure goes to the arms ```rux func ForgivingDigit(c: char) -> int { return ReadDigit(c) catch { DigitError::Letter(letter) if letter == 'O' => 0, DigitError::Letter(letter) if letter == 'l' => 1, DigitError::Letter(_) => -1, DigitError::Symbol(_) => -1, DigitError::Blank => -1 }; } ``` `ForgivingDigit` returns a plain `int`. After the `catch` there is no failure left to handle, so the function itself cannot fail. ```mermaid flowchart LR invoke["`ReadDigit(c)`"] --> q{"Success or failure?"} q -- "success" --> pass["the digit, unchanged"] q -- "failure" --> arms["the arms see only
the `DigitError`"] arms --> value["each arm gives
an `int` in its place"] pass --> result["a plain `int`"] value --> result ``` ## The arms are match arms When the error is a [variant](https://rux-lang.dev/docs/learn/variant), each arm names a case, just as in a [variant match](https://rux-lang.dev/docs/learn/variant-match), and an arm may add a [guard](https://rux-lang.dev/docs/learn/guard) with `if`. Together the arms must cover every error, so no failure is left over. The order is doing real work here. The two guarded `Letter` arms come first; `DigitError::Letter(_)` catches every other letter after them. Put `Letter(_)` first and it takes every letter, the O and the l included — and the compiler does not point it out. Every letter would quietly read as -1. | | `match` | `catch` | | ------------ | -------------------------------- | ------------------------ | | Its arms see | the whole outcome | only the error | | A success | needs an arm of its own | passes through unchanged | | Patterns | `.Success(...)`, `.Failure(...)` | the error's own patterns | | The result | whatever the arms produce | the success type | ## An arm may leave instead Every arm has to give back an `int`, because that is what a success would have been. An arm that has no sensible value may leave the function instead, with `return`: ```rux func DigitOrStop(c: char) -> int { let digit = ReadDigit(c) catch { DigitError::Blank => return 0, else => -1 }; return digit * 2; } ``` A blank makes `DigitOrStop` return 0 at once; any other failure carries on with -1. The `else` arm is the default arm, as in `match`, and covers whatever cases are left. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Errors/Catch){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // `catch` turns a fallible back into a plain value. `outcome catch { arms }` lets a success // straight through, unchanged. A failure goes to the arms, which see only the error and must // produce a value of the success type in its place. // // When the error is a variant, each arm names a case, just as in a `match`, and an arm may add a // guard with `if`. Together the arms must cover every error, so no failure is left over. // // The example reads a digit someone typed. A few typing slips are easy to forgive: a capital O // was surely meant as 0, and a lower-case l as 1. Anything else becomes -1, meaning unreadable. import Io::PrintLine; variant DigitError { Blank, Letter(char), Symbol(char) } func ReadDigit(c: char) -> int ! DigitError { if c == ' ' { fail DigitError::Blank; } if (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') { fail DigitError::Letter(c); } if c < '0' || c > '9' { fail DigitError::Symbol(c); } return (c as int) - ('0' as int); } // The result is a plain `int`: after the `catch`, there is no failure left to handle. func ForgivingDigit(c: char) -> int { return ReadDigit(c) catch { DigitError::Letter(letter) if letter == 'O' => 0, DigitError::Letter(letter) if letter == 'l' => 1, DigitError::Letter(_) => -1, DigitError::Symbol(_) => -1, DigitError::Blank => -1 }; } func Show(c: char) { PrintLine("'{}' reads as {}", c, ForgivingDigit(c)); } func Main() -> int { Show('7'); Show('O'); Show('l'); Show('x'); Show('#'); Show(' '); // Every arm has to give back an `int`, because that is what a success would have been; an // arm that has no sensible value may leave the function instead, with `return`. And the // arms must cover every case: drop the `Blank` arm and the compiler says "match on // 'DigitError' is not exhaustive; missing DigitError::Blank". return 0; } ``` ## Run it ```sh cd Examples/Errors/Catch rux run ``` ```text '7' reads as 7 'O' reads as 0 'l' reads as 1 'x' reads as -1 '#' reads as -1 ' ' reads as -1 ``` ## Common mistakes ::mistake **An arm of the wrong type.**:br`DigitError::Blank => "blank"` is an error: ```text error: 'catch' arm produces 'char8[..]', but the recovered value has type 'int' ``` A `catch` arm replaces the success, so it must have the success type. :: ::mistake **Missing a case.**:br Drop the `Blank` arm and the compiler says: ```text error: match on 'DigitError' is not exhaustive; missing DigitError::Blank ``` Add the arm, or an `else` arm for everything left. :: ::mistake **A catch-all before the specific arms.**:br`DigitError::Letter(_)` above the guarded `Letter` arms compiles, but swallows them: `'O'` then reads as -1. Specific arms first, general ones after. :: ## Try it yourself 1. Forgive a capital `S` as 5 and a capital `B` as 8. 2. Make a blank read as 0 instead of -1. Predict the last line of the output before you run it. 3. Replace the last three arms with a single `else => -1`. Does the output change? ## Learn more - [Catch fallback](https://rux-lang.dev/docs/learn/catch-fallback) — one `else` arm for every error - [Propagate](https://rux-lang.dev/docs/learn/propagate) — when the failure is the caller's to handle - [Guard](https://rux-lang.dev/docs/learn/guard) — the `if` that refines an arm - [Variant match](https://rux-lang.dev/docs/learn/variant-match) — the patterns `catch` arms use # Catch fallback ::note **You'll need**: [Catch](https://rux-lang.dev/docs/learn/catch), [Coalesce](https://rux-lang.dev/docs/learn/coalesce) :: Often the reason for a failure does not matter, only that there is a value to carry on with. `outcome catch { else => fallback }` says exactly that: the success if there is one, otherwise the fallback. The single `else` arm takes every error alike, so nothing needs listing. ## One arm for every error A settings form where every field is one typed digit, each with a sensible default: ```rux let volume = ReadDigit('7') catch { else => 5 }; let brightness = ReadDigit('x') catch { else => 8 }; let contrast = ReadDigit(' ') catch { else => 5 }; ``` `'7'` reads fine, so `volume` is 7. `'x'` is not a digit and `' '` is blank — two different errors, and both get the field's default. The fallback must have the success type, an `int` here. ## The twin of ?? If you have done [Coalesce](https://rux-lang.dev/docs/learn/coalesce), the shape is familiar. `catch { else => ... }` is the fallible twin of `option ?? fallback`: | You have | Value or default | The fallback runs | | -------- | ------------------------------------ | ----------------- | | `T?` | `option ?? fallback` | only when absent | | `T ! E` | `outcome catch { else => fallback }` | only on a failure | Like `??`, the fallback is worked out only when it is needed. A fallback that calls a function which prints something prints nothing at all when the read succeeds. Why not just `??` on a fallible, then? Because `??` would drop the error without a word, and the compiler will not do that silently. On a fallible it says `operator '??' cannot take 'int ! DigitError'`, and the note explains: `coalescing tests one optional level and would silently discard an error`. Writing `catch { else => ... }` is how you say that dropping it is intended. ## catch binds tightly `catch` binds tightly to the call right before it, so several of them can sit in one expression without parentheses. Adding up a code, where a digit that cannot be read counts as nothing: ```rux let total = ReadDigit('4') catch { else => 0 } + ReadDigit('?') catch { else => 0 } + ReadDigit('9') catch { else => 0 }; ``` Each `catch` belongs to the `ReadDigit` just before it, so the sum is 4 + 0 + 9 = 13. ## The price The convenience has a price: the error is thrown away unseen. `'x'` and `' '` both became defaults, and nothing in the program can tell which went wrong or why. When the reason should change what happens next, give `catch` one arm per case instead, as [Catch](https://rux-lang.dev/docs/learn/catch) does. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Errors/CatchFallback){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // Often the reason for a failure does not matter, only that there is a value to carry on with. // `outcome catch { else => fallback }` says exactly that: the success if there is one, otherwise // the fallback. The single `else` arm takes every error alike, so nothing needs listing. // // It is the fallible twin of `option ?? fallback`. The fallback is only worked out when it is // needed, and it must have the success type — an `int` here. // // `catch` binds tightly to the call right before it, so several of them can sit in one // expression without parentheses. import Io::PrintLine; variant DigitError { Blank, NotADigit(char) } func ReadDigit(c: char) -> int ! DigitError { if c == ' ' { fail DigitError::Blank; } if c < '0' || c > '9' { fail DigitError::NotADigit(c); } return (c as int) - ('0' as int); } func Main() -> int { // A settings form where every field is one typed digit, each with a sensible default. let volume = ReadDigit('7') catch { else => 5 }; let brightness = ReadDigit('x') catch { else => 8 }; let contrast = ReadDigit(' ') catch { else => 5 }; PrintLine("volume {}, brightness {}, contrast {}", volume, brightness, contrast); // Adding up a code, where a digit that cannot be read counts as nothing. let total = ReadDigit('4') catch { else => 0 } + ReadDigit('?') catch { else => 0 } + ReadDigit('9') catch { else => 0 }; PrintLine("sum of 4?9 is {}", total); // The convenience has a price: the error is thrown away unseen. When the reason should // change what happens next, give `catch` one arm per case instead. return 0; } ``` ## Run it ```sh cd Examples/Errors/CatchFallback rux run ``` ```text volume 7, brightness 8, contrast 5 sum of 4?9 is 13 ``` ## Common mistakes ::mistake **Using ?? on a fallible.**:br`ReadDigit('7') ?? 5` is refused: ```text error: operator '??' cannot take 'int ! DigitError' ``` The help line names the two ways out: ```text recover the error with 'catch', or propagate it with '?' ``` :: ::mistake **A fallback of the wrong type.**:br`catch { else => 8.5 }` is an error: ```text error: 'catch' arm produces 'float64', but the recovered value has type 'int' ``` The fallback stands in for the success, so it must be an `int`. :: ## Try it yourself 1. Add up the digits `'7'`, `'x'` and `'7'` with a fallback of 0, then with a fallback of 5. Predict both sums. 2. Write `func Default() -> int` that prints `"(using the default)"` and returns 5, and use it as the fallback for `volume`. When does the line appear? 3. Rewrite `brightness` with one arm per case — `Blank` gives 8, `NotADigit(_)` gives 0. ## Learn more - [Catch](https://rux-lang.dev/docs/learn/catch) — one arm per error case - [Coalesce](https://rux-lang.dev/docs/learn/coalesce) — the same idea for optionals - [Propagate](https://rux-lang.dev/docs/learn/propagate) — when the caller should decide instead # Propagate ::note **You'll need**: [Outcome](https://rux-lang.dev/docs/learn/outcome), [Catch](https://rux-lang.dev/docs/learn/catch) :: Handling a fallible with `match` or `catch` is right when this function is the one that should decide what a failure means. Often it is not. The function is a step in the middle, and a failure should simply become the caller's problem. Postfix `?` does exactly that. On success, `step?` is the value inside. On failure, the enclosing function fails at once with that same error, and nothing after the `?` runs. ## The long way Written by hand, passing a failure on is the same few lines every time: match, keep the success, fail with the error unchanged. ```rux var high = 0; match ReadDigit(tens) { .Success(value) => high = value, .Failure(error) => fail error } ``` `TwoDigitsByHand` writes that block twice, once per digit. The two blocks are near-identical and say nothing new. ## The same with ? `?` is those lines written once. The success values are used straight away: ```rux func TwoDigits(tens: char, units: char) -> int ! DigitError { let high = ReadDigit(tens)?; let low = ReadDigit(units)?; return high * 10 + low; } ``` ```mermaid flowchart LR step["`ReadDigit(tens)?`"] --> q{"Success or failure?"} q -- "`.Success(value)`" --> go["the expression is `value`;
`TwoDigits` carries on"] q -- "`.Failure(error)`" --> out["`TwoDigits` fails at once
with the same error"] out --> caller["the caller's `match`
sees the original error"] ``` Both versions behave identically: `?` is shorthand, not a different rule. When both digits are wrong, as in `TwoDigits('x', '?')`, only the first one is reported — the first `?` leaves, and the second read never happens. ## The error travels intact Neither `TwoDigits` nor `?` looked at the error, yet the caller still learns which character was wrong: ```rux .Failure(DigitError::NotADigit(c)) => PrintLine("'{}' is not a digit", c) ``` `Show` matches the nested pattern `.Failure(DigitError::NotADigit(c))` directly, reaching through the failure channel into the variant case in one step. ## Two requirements `?` asks two things of the function it is used in: 1. **It must be fallible**, since that is where the failure goes. `Main` returns a plain `int`, so `ReadDigit('4')?` there is rejected. 2. **The error must fit its error type.** Here both are `DigitError`, so it passes through as is. A different error type needs [Error mapping](https://rux-lang.dev/docs/learn/error-mapping), or an [error sum](https://rux-lang.dev/docs/learn/error-sum) that includes it. | Tool | Who decides what a failure means | The function stays | | ---------------- | -------------------------------- | ---------------------------------- | | `match`, `catch` | this function | as fallible as you choose | | `?` | the caller | fallible, with the same error type | ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Errors/Propagate){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // Handling a fallible with `match` or `catch` is right when this function is the one that should // decide what a failure means. Often it is not: the function is a step in the middle, and a // failure should simply become the caller's problem. // // Written by hand that is the same few lines every time: match, keep the success, fail with the // error unchanged. Postfix `?` is those lines written once. On success, `step?` is the value // inside. On failure, the enclosing function fails at once with that same error, and nothing after // the `?` runs. import Io::PrintLine; variant DigitError { Blank, NotADigit(char) } // One small step that can fail. func ReadDigit(c: char) -> int ! DigitError { if c == ' ' { fail DigitError::Blank; } if c < '0' || c > '9' { fail DigitError::NotADigit(c); } return (c as int) - ('0' as int); } // The long way. Each failure is matched only to be handed straight back to the caller: two // near-identical blocks that say nothing new. func TwoDigitsByHand(tens: char, units: char) -> int ! DigitError { var high = 0; match ReadDigit(tens) { .Success(value) => high = value, .Failure(error) => fail error } var low = 0; match ReadDigit(units) { .Success(value) => low = value, .Failure(error) => fail error } return high * 10 + low; } // The same function with `?`. The success values are used straight away. func TwoDigits(tens: char, units: char) -> int ! DigitError { let high = ReadDigit(tens)?; let low = ReadDigit(units)?; return high * 10 + low; } func Show(outcome: int ! DigitError) { match outcome { .Success(value) => PrintLine("read {}", value), .Failure(DigitError::Blank) => PrintLine("a digit is missing"), .Failure(DigitError::NotADigit(c)) => PrintLine("'{}' is not a digit", c) } } func Main() -> int { Show(TwoDigits('4', '2')); Show(TwoDigits('4', 'x')); Show(TwoDigits('?', '2')); Show(TwoDigits(' ', '7')); // Both versions behave identically: `?` is shorthand, not a different rule. Show(TwoDigitsByHand('4', 'x')); // The error travels intact. Neither `TwoDigits` nor `?` looked at it, yet the caller still // learns which character was wrong. // // `?` has two requirements. The function using it must itself be fallible, since that is // where the failure goes. In `Main`, which returns a plain `int`, `ReadDigit('4')?` is // rejected: "'?' propagates native fallible 'int ! DigitError', but the enclosing function // returns 'int'". And the error must fit that function's error type. Here both are // `DigitError`, so it passes through as is. return 0; } ``` ## Run it ```sh cd Examples/Errors/Propagate rux run ``` ```text read 42 'x' is not a digit '?' is not a digit a digit is missing 'x' is not a digit ``` ## Common mistakes ::mistake **? in a function that cannot fail.**:br In `Main`, `ReadDigit('4')?` is an error: ```text error: '?' propagates native fallible 'int ! DigitError', but the enclosing function returns 'int' ``` Handle the failure with `match` or `catch` there — or make `Main` fallible, as [Fallible main](https://rux-lang.dev/docs/learn/fallible-main) shows. :: ::mistake **Forgetting the ?.**:br`let high = ReadDigit(tens);` makes `high` the whole fallible, and the next line fails: ```text error: operator '*' cannot combine left operand 'int ! DigitError' with right operand 'int' ``` :: ::mistake **Passing on an error of another type.**:br`?` never converts an error. In a function that fails with a `SettingError`, `?` on a `DigitError` is an error: ```text error: '?' propagates error type 'DigitError', but the enclosing function fails with 'SettingError' ``` [Error mapping](https://rux-lang.dev/docs/learn/error-mapping) is the fix. :: ## Try it yourself 1. Add `Show(TwoDigits(' ', 'x'));` and predict which of the two messages it prints. 2. Write `ThreeDigits(hundreds: char, tens: char, units: char) -> int ! DigitError` with three `?`. 3. Rewrite `ThreeDigits` to call `TwoDigits` for the last two digits. Does the `?` still need anything special? ## Learn more - [Optional propagate](https://rux-lang.dev/docs/learn/optional-propagate) — the same `?` for absence - [Error mapping](https://rux-lang.dev/docs/learn/error-mapping) — `? else` adds context on the way through - [Fallible main](https://rux-lang.dev/docs/learn/fallible-main) — `?` at the top level of a program - [Error variant](https://rux-lang.dev/docs/learn/error-variant) — one error type for a whole chain of steps # Error variant ::note **You'll need**: [Propagate](https://rux-lang.dev/docs/learn/propagate), [Variant match](https://rux-lang.dev/docs/learn/variant-match), [Struct pattern](https://rux-lang.dev/docs/learn/struct-pattern) :: An operation that can go wrong in several ways deserves an error type that lists those ways. A [variant](https://rux-lang.dev/docs/learn/variant) does that: one case per kind of failure, and each case carries only the details that make sense for it. The caller can then match on the case to decide what to do, and read the details to say precisely what went wrong — far more than a single error code could tell it. ## One case per way to fail A transfer between three bank accounts can fail in three ways: ```rux variant TransferError { SameAccount, UnknownAccount(int), ShortOfFunds { balance: int; requested: int; } } ``` | Case | Shape | Carries | | ---------------- | ------------------------- | ------------------------------------ | | `SameAccount` | bare | nothing — the case says it all | | `UnknownAccount` | one fact, in parentheses | the account number that was wrong | | `ShortOfFunds` | several facts, with names | the balance and the amount asked for | A case with several facts gives them names, like a small [struct](https://rux-lang.dev/docs/learn/struct), so nobody has to remember which number came first. ## Failing with each case Each `fail` builds the case that fits, with its details: ```rux if from == to { fail TransferError::SameAccount; } ``` ```rux if balances[source] < amount { fail TransferError::ShortOfFunds { balance: balances[source], requested: amount }; } ``` `UnknownAccount` comes from a helper, `Find`, which turns an account number into a position in the list of balances. It fails with the same error type, so `Transfer` passes its failures on with [`?`](https://rux-lang.dev/docs/learn/propagate), unchanged: ```rux let source = Find(from)?; let target = Find(to)?; ``` The checks run in order, and the first one that fails decides the error: ```mermaid flowchart TD start["`Transfer(from, to, amount)`"] --> same{"`from == to?`"} same -- "yes" --> e1["`SameAccount`"] same -- "no" --> find{"Do both accounts exist?
`Find(from)?` and `Find(to)?`"} find -- "no" --> e2["`UnknownAccount(number)`"] find -- "yes" --> funds{"Is there enough money?"} funds -- "no" --> e3["`ShortOfFunds { balance, requested }`"] funds -- "yes" --> done["Success: balances updated"] ``` ## Reading the details `Explain` gives one message per case, each built from the details that case carries. The patterns are the [struct patterns](https://rux-lang.dev/docs/learn/struct-pattern) you already know: ```rux match error { .SameAccount => PrintLine(" refused: an account cannot pay itself"), .UnknownAccount(number) => PrintLine(" refused: there is no account {}", number), .ShortOfFunds { balance, requested } => PrintLine( " refused: asked for {} but only {} is there", requested, balance) } ``` `.ShortOfFunds { balance, requested }` binds each field to a variable of the same name. A pattern written with field names may also leave fields out — `.ShortOfFunds { requested }` binds only the one it needs. Because the match must cover every case, adding a fourth way to fail later makes the compiler point at every `match` that does not handle it yet. That is the main payoff of a variant error: no new failure goes unexplained. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Errors/ErrorVariant){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // An operation that can go wrong in several ways deserves an error type that lists those ways. // A variant does that: one case per kind of failure, and each case carries only the details that // make sense for it. // // A case with nothing to add is bare. A case with one fact carries it in parentheses. A case with // several facts gives them names, like a small struct. The caller can then match on the case to // decide what to do, and read the details to say precisely what went wrong — far more than a // single error code could tell it. import Io::PrintLine; variant TransferError { SameAccount, UnknownAccount(int), ShortOfFunds { balance: int; requested: int; } } // Turns an account number into a position in the list of balances. func Find(number: int) -> int ! TransferError { if number < 1 || number > 3 { fail TransferError::UnknownAccount(number); } return number - 1; } func Transfer(balances: &var int[3], from: int, to: int, amount: int) -> ! TransferError { if from == to { fail TransferError::SameAccount; } // The same error type all the way through, so `?` passes each failure on unchanged. let source = Find(from)?; let target = Find(to)?; if balances[source] < amount { fail TransferError::ShortOfFunds { balance: balances[source], requested: amount }; } balances[source] -= amount; balances[target] += amount; } // One message per case, each built from the details that case carries. func Explain(error: TransferError) { match error { .SameAccount => PrintLine(" refused: an account cannot pay itself"), .UnknownAccount(number) => PrintLine(" refused: there is no account {}", number), .ShortOfFunds { balance, requested } => PrintLine( " refused: asked for {} but only {} is there", requested, balance) } } func Attempt(balances: &var int[3], from: int, to: int, amount: int) { PrintLine("move {} from account {} to account {}", amount, from, to); match Transfer(balances, from, to, amount) { .Success(()) => PrintLine(" done: balances {}, {}, {}", balances[0], balances[1], balances[2]), .Failure(error) => Explain(error) } } func Main() -> int { var balances: int[3] = [100, 50, 0]; Attempt(balances, 1, 3, 30); Attempt(balances, 2, 2, 10); Attempt(balances, 1, 7, 10); Attempt(balances, 3, 1, 45); return 0; } ``` ## Run it ```sh cd Examples/Errors/ErrorVariant rux run ``` ```text move 30 from account 1 to account 3 done: balances 70, 50, 30 move 10 from account 2 to account 2 refused: an account cannot pay itself move 10 from account 1 to account 7 refused: there is no account 7 move 45 from account 3 to account 1 refused: asked for 45 but only 30 is there ``` ## Common mistakes ::mistake **Forgetting a case.**:br Drop the `SameAccount` arm from `Explain` and the compiler says: ```text error: match on 'TransferError' is not exhaustive; missing TransferError::SameAccount ``` :: ::mistake **Giving a bare case a payload.**:br`fail TransferError::SameAccount(from);` is an error: ```text error: call to 'TransferError::SameAccount' expects 0 arguments, but 1 was provided ``` If the detail matters, declare the case with it. :: ## Try it yourself 1. Add a case `ZeroAmount` and refuse a transfer of 0 before any other check. Follow the compiler to every match that needs a new arm. 2. Make `ShortOfFunds` print how much is missing as well, using only the two fields it already carries. 3. Add `Attempt(balances, 2, 1, 50);` at the end and predict the balances it prints. ## Learn more - [Variant](https://rux-lang.dev/docs/learn/variant) and [Variant match](https://rux-lang.dev/docs/learn/variant-match) — the type and its patterns - [Struct pattern](https://rux-lang.dev/docs/learn/struct-pattern) — binding named fields - [Error mapping](https://rux-lang.dev/docs/learn/error-mapping) — turning a lower-level error into one of these cases - [Error sum](https://rux-lang.dev/docs/learn/error-sum) — the alternative when the errors are unrelated types # Error mapping ::note **You'll need**: [Fail](https://rux-lang.dev/docs/learn/fail), [Propagate](https://rux-lang.dev/docs/learn/propagate) :: A low-level function knows *what* went wrong but not *where*. `ParseNumber` can say "the character at position 2 is not a digit", but it has no idea that its text came from line 3 of a settings file. The function that does know is the one calling it. This lesson shows how that caller adds what it knows to the error as it passes through, with `? else (e => ...)`. ## Plain ? cannot add context Two error types meet here. `ParseNumber` fails with a `DigitError`, which knows a position; the settings reader fails with a `SettingError`, which needs a line and a column: ```rux struct DigitError { position: uint; } struct SettingError { line: uint; column: uint; } ``` Plain [`?`](https://rux-lang.dev/docs/learn/propagate) passes an error on unchanged, so it cannot add the line number — and it is rejected here anyway, because a `DigitError` is not a `SettingError`. The compiler's note is worth reading: `'?' moves an error into the outer failure only by identity, sum member injection, or subset widening; it never converts an error`. ## ? else maps the error The mapped form fixes both problems: ```rux let w = ParseNumber(width)? else (e => SettingError { line: 1, column: e.position + 1 }); let h = ParseNumber(height)? else (e => SettingError { line: 2, column: e.position + 1 }); ``` | Piece | Meaning | | ---------------------- | ------------------------------------------------------------------------------------ | | `ParseNumber(width)?` | on success, the number; the mapper never runs | | `else (e => ...)` | on failure, `e` is the whole original `DigitError` | | `SettingError { ... }` | the new error, built from `e` and anything else in scope; the function fails with it | ```mermaid flowchart LR invoke["`ParseNumber(width)`"] --> q{"Success or failure?"} q -- "success" --> n["the number;
the mapper never runs"] q -- "failure, as `e`" --> m["the mapper builds
`SettingError { line: 1, column: e.position + 1 }`"] m --> f["`WindowArea` fails
with the new error"] ``` ## The mapper uses what is in scope The mapper is a single expression, and it can read anything the function can. Here it adds the line number, which only `WindowArea` knows, and turns the 0-based position into the 1-based column a person would look for. In `"8O"` the letter O sits at position 1, so the message says column 2. The parentheses around `e => ...` hold exactly one name and one expression. The mapper must produce the enclosing function's error type — the compiler checks that, but not whether the arithmetic inside is right. ## Where to map Map an error where the context is. `ParseNumber` stays small and reusable because it knows nothing about files; `WindowArea` is the first function that knows about lines, so it is the one that maps. Its own caller then deals with `SettingError` alone and never needs to know that a `DigitError` existed. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Errors/ErrorMapping){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // A low-level function knows what went wrong but not where. `ParseNumber` below // can say "the character at position 2 is not a digit", but it has no idea that // its text came from line 3 of a settings file. The function that *does* know // is the one calling it. // // Plain `?` passes an error on unchanged, so it cannot add that context — and // it is rejected here anyway, because a `DigitError` is not a `SettingError`. // The mapped form fixes both: // // ParseNumber(text)? else (e => SettingError { ... }) // // On success the expression is the number and the mapper never runs. On // failure `e` is the whole original error, the mapper builds the new one from // `e` plus anything else in scope, and the function fails with it. import Io::PrintLine; struct DigitError { position: uint; } struct SettingError { line: uint; column: uint; } // Knows about characters, nothing about files or lines. func ParseNumber(text: char8[..]) -> int ! DigitError { var total = 0; for i in 0..text.length { let byte = text[i]; if byte < c8'0' || byte > c8'9' { fail DigitError { position: i }; } total = total * 10 + ((byte as int) - 48); } return total; } // Reads a window size from two settings lines. Each `? else` adds the line // number, which only this function knows, and turns the 0-based position into // the 1-based column a person would look for. func WindowArea(width: char8[..], height: char8[..]) -> int ! SettingError { let w = ParseNumber(width)? else (e => SettingError { line: 1, column: e.position + 1 }); let h = ParseNumber(height)? else (e => SettingError { line: 2, column: e.position + 1 }); return w * h; } func Show(width: char8[..], height: char8[..]) { match WindowArea(width, height) { .Success(area) => PrintLine("{} x {}: area {}", width, height, area), .Failure(e) => PrintLine("{} x {}: line {}, column {} is not a digit", width, height, e.line, e.column) } } func Main() -> int { Show("80", "24"); Show("8O", "24"); Show("80", "2-4"); return 0; } ``` ## Run it ```sh cd Examples/Errors/ErrorMapping rux run ``` ```text 80 x 24: area 1920 8O x 24: line 1, column 2 is not a digit 80 x 2-4: line 2, column 2 is not a digit ``` ## Common mistakes ::mistake **Plain ? across error types.**:br`let w = ParseNumber(width)?;` is an error: ```text error: '?' propagates error type 'DigitError', but the enclosing function fails with 'SettingError' ``` The help says: ```text map the error to 'SettingError' with '? else (e => ...)', or match the value ``` :: ::mistake **A mapper that builds the wrong type.**:br`ParseNumber(width)? else (e => 5)` is an error: ```text error: the mapped error has type 'int', but the enclosing function fails with 'SettingError' ``` :: ::mistake **Off by one in the mapper.**:br Write `column: e.position` and the program still compiles — it just reports column 1 for `"8O"`. The compiler checks the mapper's type, not its meaning. :: ## Try it yourself 1. Add a `found: char8` field to `SettingError` and fill it in the mapper with the bad character, `width[e.position]`. Print it in `Show`. 2. Call `Show("", "24")`. Predict the output before you run it — is an empty line an error? 3. Read a third setting, a depth on line 3, and print the volume instead of the area. ## Learn more - [Propagate](https://rux-lang.dev/docs/learn/propagate) — plain `?`, which passes an error on unchanged - [Error variant](https://rux-lang.dev/docs/learn/error-variant) — a richer target type for a mapper - [Error sum](https://rux-lang.dev/docs/learn/error-sum) — passing on two error types without mapping either # Error sum ::note **You'll need**: [Outcome](https://rux-lang.dev/docs/learn/outcome), [Propagate](https://rux-lang.dev/docs/learn/propagate) :: Some functions can fail in more than one unrelated way. Reading a percentage can find a character that is not a digit, or a perfectly good number that is bigger than 100. Those are two different error types, and the error channel can hold either one. ## Two errors in one channel The two errors are separate structs, each with its own details: ```rux struct DigitError { position: uint; } struct RangeError { value: int; limit: int; } ``` `ParsePercent` names both after the `!`: ```rux func ParsePercent(text: char8[..]) -> int ! (DigitError | RangeError) { ``` `A | B` is a *sum*: one value that is an `A` or a `B`, and knows which. Sums have a part of their own, [Sum types](https://rux-lang.dev/docs/learn/sum-types), straight after this one; here you need only what it means in an error channel. The order does not matter — `(RangeError | DigitError)` is the same type. The parentheses are for the reader: in a type, `|` binds tighter than `!`, so they could be left out, but with them nobody has to remember that. ## Widening needs no code The surprise is how little the function body has to do: ```rux let value = ParseNumber(text)?; if value > 100 { fail RangeError { value: value, limit: 100 }; } return value; ``` `ParseNumber` fails with a plain `DigitError`, yet `?` passes it on unchanged — a `DigitError` fits into the wider sum on its own. `fail RangeError { ... }` needs no wrapping either. This is called *widening*: a narrower error always fits into a sum that includes it. ```mermaid flowchart LR d["`ParseNumber` fails
with a `DigitError`"] -- "`?`" --> sum["`ParsePercent` fails with
`DigitError | RangeError`"] r["`fail RangeError { ... }`"] --> sum sum --> m{"The caller's `match`"} m -- "`e: DigitError`" --> a["`no digit at position …`"] m -- "`e: RangeError`" --> b["`… is over 100`"] ``` ## Telling the members apart The caller tells the members apart with a *typed pattern*. `e: DigitError` matches only that member and binds it as a plain `DigitError`, so its fields are right there: ```rux match ParsePercent(text) { .Success(percent) => PrintLine("{:5} -> {}%", text, percent), .Failure(e: DigitError) => PrintLine("{:5} -> no digit at position {}", text, e.position), .Failure(e: RangeError) => PrintLine("{:5} -> {} is over {}", text, e.value, e.limit) } ``` The match must cover every member of the sum, or the compiler names the missing one. ## A sum or a variant? [Error variant](https://rux-lang.dev/docs/learn/error-variant) solved a similar problem with one type and several cases. Both work; they suit different situations. | | Error sum `A | B` | Error variant | | -------------------------- | ------------------------------------------ | ------------------------------- | | The errors are | separate types that already exist | cases you declare together | | Passing one on with `?` | widens on its own | needs a mapping into a case | | Adding a new kind of error | changes every signature that lists the sum | one new case in one declaration | | Best for | combining errors from different places | a stable, named set of failures | ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Errors/ErrorSum){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // Some functions can fail in more than one unrelated way. Reading a percentage // can find a character that is not a digit, or a perfectly good number that // is bigger than 100. Those are two different error types, and the error // channel can hold either one: // // func ParsePercent(text: char8[..]) -> int ! (DigitError | RangeError) // // `A | B` is a sum: one value that is an `A` or a `B`, and knows which. The // order does not matter — `(RangeError | DigitError)` is the same type. // // The surprise is how little the function body has to do. A `DigitError` // fits into the wider sum on its own, so `ParseNumber(text)?` passes it on // unchanged and `fail RangeError { ... }` needs no wrapping either. This is // called widening: a narrower error always fits into a sum that includes it. import Io::PrintLine; struct DigitError { position: uint; } struct RangeError { value: int; limit: int; } func ParseNumber(text: char8[..]) -> int ! DigitError { var total = 0; for i in 0..text.length { let byte = text[i]; if byte < c8'0' || byte > c8'9' { fail DigitError { position: i }; } total = total * 10 + ((byte as int) - 48); } return total; } func ParsePercent(text: char8[..]) -> int ! (DigitError | RangeError) { // A `DigitError` widens into the sum as it passes through `?`. let value = ParseNumber(text)?; if value > 100 { fail RangeError { value: value, limit: 100 }; } return value; } // The caller tells the members apart with a typed pattern: `e: DigitError` // matches only that member and binds it as a plain `DigitError`. The match // must cover every member of the sum, or the compiler names the missing one. // Drop the `RangeError` arm and it says "match on 'int ! (DigitError | // RangeError)' is not exhaustive; missing .Failure(_: RangeError)". func Show(text: char8[..]) { match ParsePercent(text) { .Success(percent) => PrintLine("{:5} -> {}%", text, percent), .Failure(e: DigitError) => PrintLine("{:5} -> no digit at position {}", text, e.position), .Failure(e: RangeError) => PrintLine("{:5} -> {} is over {}", text, e.value, e.limit) } } func Main() -> int { Show("75"); Show("7%"); Show("250"); return 0; } ``` ## Run it ```sh cd Examples/Errors/ErrorSum rux run ``` ```text 75 -> 75% 7% -> no digit at position 1 250 -> 250 is over 100 ``` ## Common mistakes ::mistake **Leaving out a member.**:br Drop the `RangeError` arm and the compiler says: ```text error: match on 'int ! (DigitError | RangeError)' is not exhaustive; missing .Failure(_: RangeError) ``` :: ::mistake **Failing with a type that is not in the sum.**:br`fail 5;` in `ParsePercent` is an error: ```text error: 'fail' value must have type 'DigitError | RangeError', but found 'int' ``` Widening only accepts a member of the sum. :: ::mistake **An untyped failure arm first.**:br`.Failure(e) =>` matches every member, so a later `.Failure(e: RangeError)` arm is an error: ```text error: match arm is unreachable because earlier arms already match every value it matches ``` :: ## Try it yourself 1. Add `Show("100");` and `Show("101");` and predict both lines. 2. `Show("")` prints `0%`. Add an `EmptyError` struct, put it in the sum, and fail with it on empty text. What else does the compiler ask you to change? 3. Swap the order of the members in the signature to `(RangeError | DigitError)` and check that nothing else has to change. ## Learn more - [Sum types](https://rux-lang.dev/docs/learn/sum-types) — the next part, all about `A | B` - [Typed pattern](https://rux-lang.dev/docs/learn/typed-pattern) — `e: DigitError` in detail - [Sum widening](https://rux-lang.dev/docs/learn/sum-widening) — when a narrower type fits a wider sum - [Error variant](https://rux-lang.dev/docs/learn/error-variant) — the alternative with named cases # Fallible main ::note **You'll need**: [Unit fallible](https://rux-lang.dev/docs/learn/unit-fallible), [Propagate](https://rux-lang.dev/docs/learn/propagate) :: Every program so far ended with `return 0;` from `func Main() -> int`. That made [`?`](https://rux-lang.dev/docs/learn/propagate) useless at the top level: `Main` could not fail, so a failure had nowhere to go, and every step had to be matched by hand. `Main` may also be fallible. Then `?` works at the top level too, and a failure ends the program. ## Main may fail The installer in this lesson reserves disk space for two programs. `Reserve` fails with a `SpaceError` when there is not enough room, and `Main` declares the same error: ```rux func Main() -> ! SpaceError { var free = 100; PrintLine("Installing the editor (40 MB of {} MB free)", free); free = Reserve(40, free)?; ``` `Main` is now a [unit fallible](https://rux-lang.dev/docs/learn/unit-fallible), so it follows the same rules: falling off its end is success, and it has no `return 0;`. The second reservation asks for 90 MB with only 60 free, so its `?` ends the program — the last `PrintLine` never runs. ## How the program ends The operating system receives a number when a program ends, its *exit status*. 0 means success; anything else means something went wrong. | `Main` is declared | and ends by | Exit status | | ------------------------ | ---------------------- | ----------- | | `-> int` | `return n;` | `n` | | `-> ! E` | reaching its end | 0 | | `-> int ! E` | `return n;` | `n` | | `-> ! E` or `-> int ! E` | `fail` or a failed `?` | 1 | A failure still runs the program's ordinary cleanup on the way out, just as a `return` would — unlike a [panic](https://rux-lang.dev/docs/learn/panic), which stops at once. ## A failure prints nothing The surprise is what a failure does *not* do: it prints nothing. The `SpaceError` value is not shown anywhere, so a user only sees the program stop after the second line. The exit status is for whoever started the program — a script, a build tool or a shell. In PowerShell, `echo $LASTEXITCODE` shows it right after the program ends; in a POSIX shell such as bash, it is `echo $?`. That `1` is the last line of the output below. If a person should learn *why* the program stopped, print a message yourself before failing. A `catch` arm can do both — print, then `fail` with the same error: ```rux free = Reserve(90, free) catch { e => { PrintLine("Not enough space: {} MB needed, {} MB free", e.needed, e.free); fail e; } }; ``` The arm `e => ...` binds the whole error, and its block ends by leaving, so it never has to produce a value. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Errors/FallibleMain){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // Every program so far ended with `return 0;` from `func Main() -> int`. `Main` // may also be fallible: // // func Main() -> ! SpaceError // // Now `?` works at the top level too. Falling off the end of `Main` is // success, and the program exits with status 0. A failure — from `fail` or // from a `?` — ends the program with exit status 1. // // The surprise is what a failure does *not* do: it prints nothing. The error // value is not shown anywhere, so a user only sees the program stop. If they // should learn why, print a message yourself before failing. The exit status // is for whoever started the program: a script, a build tool or a shell. In // PowerShell, `echo $LASTEXITCODE` shows it right after the program ends. // // This program fails on purpose: the second install does not fit. import Io::PrintLine; struct SpaceError { needed: int; free: int; } func Reserve(needed: int, free: int) -> int ! SpaceError { if needed > free { fail SpaceError { needed: needed, free: free }; } return free - needed; } func Main() -> ! SpaceError { var free = 100; PrintLine("Installing the editor (40 MB of {} MB free)", free); free = Reserve(40, free)?; PrintLine("Installing the compiler (90 MB of {} MB free)", free); free = Reserve(90, free)?; // Never printed: the `?` above ended the program with status 1. PrintLine("Everything is installed, {} MB left", free); } ``` ## Run it ```sh cd Examples/Errors/FallibleMain rux run echo $? ``` The program fails on purpose, so it stops after the second line, and `echo $?` prints its exit status, 1. In PowerShell, use `echo $LASTEXITCODE` instead. ```text Installing the editor (40 MB of 100 MB free) Installing the compiler (90 MB of 60 MB free) 1 ``` ## Common mistakes ::mistake **Keeping return 0 in a fallible Main.**:br In `func Main() -> ! SpaceError`, `return 0;` is an error: ```text error: 'return' value must have type '! SpaceError', but found 'int' ``` Let `Main` reach its end — or declare `-> int ! SpaceError` if you want to choose the status yourself. :: ::mistake **Expecting the error to be shown.**:br A failed `Main` exits with status 1 and prints nothing about the error. Print what the user needs to know before the failure, as the `catch` above does. :: ## Try it yourself 1. Change the compiler's 90 MB to 50 and run again. What does `echo $LASTEXITCODE` show now? 2. Replace the second `?` with the `catch` above, so the user learns why the install stopped. 3. Declare `func Main() -> int ! SpaceError`, end it with `return 2;`, and check the exit status when everything fits. ## Learn more - [The Main entry point](https://rux-lang.dev/docs/lang/functions/main) in the Rux Reference - [Unit fallible](https://rux-lang.dev/docs/learn/unit-fallible) — the rules a `-> ! E` function follows - [Propagate](https://rux-lang.dev/docs/learn/propagate) — the `?` that `Main` can now use - [Panic](https://rux-lang.dev/docs/learn/panic) — stopping a program that has hit a bug # Absence to error ::note **You'll need**: [Coalesce](https://rux-lang.dev/docs/learn/coalesce), [Fail](https://rux-lang.dev/docs/learn/fail) :: An [optional](https://rux-lang.dev/docs/learn/optional) says "nothing here" and stops there. `PriceOf(7)` returns `none`, and `none` cannot say which code was missing or why that matters. When absence is a real problem for the caller, turn it into an error that does say so. ## ?? fail A small price list where an unknown code is simply absent: ```rux func PriceOf(code: int) -> int? { return match code { 1 => 250, 2 => 120, 3 => 75, else => none }; } ``` `Total` needs a price, and a missing one is a failure worth reporting: ```rux func Total(code: int, quantity: int) -> int ! UnknownProduct { let price = PriceOf(code) ?? fail UnknownProduct { code: code }; return price * quantity; } ``` This is the `??` from [Coalesce](https://rux-lang.dev/docs/learn/coalesce), with `fail` as its fallback — just as [Coalesce exit](https://rux-lang.dev/docs/learn/coalesce-exit) used `return`. When the price is present, `price` is that number. When it is absent, the function fails right there, and the error can carry whatever context is at hand — here, the code that was not found. ```mermaid flowchart LR look["`PriceOf(code)`"] --> q{"Present or `none`?"} q -- "present" --> price["`price` is the number;
`Total` carries on"] q -- "`none`" --> fail["`fail UnknownProduct { code }`"] fail --> caller["the caller learns
which code was missing"] ``` ## The error is built only when needed Like every `??` fallback, the right side runs only when it is needed. For a product that exists, the `UnknownProduct` value is never even built. ## Why not ? On an optional, [`?`](https://rux-lang.dev/docs/learn/optional-propagate) passes the absence on — but only as absence. It works in a function that returns an optional, and `Total` returns a fallible. `?` never invents an error for a missing value; `?? fail` is how you supply one yourself. | You write | When the price is missing, `Total`… | | --------------------------- | -------------------------------------------------------- | | `PriceOf(code) ?? 0` | carries on with 0, so the order costs nothing | | `PriceOf(code) ?? return …` | succeeds at once with the value given to `return` | | `PriceOf(code)?` | is rejected: `Total` returns a fallible, not an optional | | `PriceOf(code) ?? fail …` | fails, saying which code it was | ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Errors/AbsenceToError){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // An optional says "nothing here" and stops there. `PriceOf(7)` returns // `none`, and `none` cannot say which code was missing or why that matters. // When absence is a real problem for the caller, turn it into an error that // does say so: // // let price = PriceOf(code) ?? fail UnknownProduct { code: code }; // // This is the `??` from the optionals part with `fail` as its fallback. When // the price is present, `price` is that number. When it is absent, the // function fails right there, and the error can carry whatever context is at // hand — here, the code that was not found. // // Like every `??` fallback, the right side runs only when it is needed, so // the error is not even built for a product that exists. import Io::PrintLine; struct UnknownProduct { code: int; } // A small price list. An unknown code is simply absent. func PriceOf(code: int) -> int? { return match code { 1 => 250, 2 => 120, 3 => 75, else => none }; } func Total(code: int, quantity: int) -> int ! UnknownProduct { let price = PriceOf(code) ?? fail UnknownProduct { code: code }; return price * quantity; } func Order(code: int, quantity: int) { match Total(code, quantity) { .Success(total) => PrintLine("{} x product {}: {} cents", quantity, code, total), .Failure(e) => PrintLine("{} x product {}: no product has code {}", quantity, code, e.code) } } func Main() -> int { Order(1, 2); Order(3, 4); Order(7, 1); return 0; } ``` ## Run it ```sh cd Examples/Errors/AbsenceToError rux run ``` ```text 2 x product 1: 500 cents 4 x product 3: 300 cents 1 x product 7: no product has code 7 ``` ## Common mistakes ::mistake **Using ? to turn absence into an error.**:br`let price = PriceOf(code)?;` in `Total` is an error, with a note: ```text error: '?' propagates the absence of 'int?', but the enclosing function returns 'int ! UnknownProduct' '?' never invents an error for it ``` Write `?? fail` with the error you mean. :: ::mistake **?? fail in a function that cannot fail.**:br In `Main`, `PriceOf(1) ?? fail UnknownProduct { code: 1 }` is an error: ```text error: 'fail' needs an enclosing fallible function, but this function returns 'int' ``` :: ::mistake **Comparing without parentheses.**:br`==` binds tighter than `??`, so `PriceOf(1) ?? 0 == 250` means `PriceOf(1) ?? (0 == 250)` and fails with: ```text error: coalescing fallback has type 'bool8', but the optional payload is 'int' ``` Write `(PriceOf(1) ?? 0) == 250`. :: ## Try it yourself 1. Add product 4 at 990 cents and order three of them. 2. Refuse an order of zero items as well. One error struct no longer fits — try a variant with an `UnknownCode(int)` case and a `NoItems` case. 3. Change `Order(7, 1)` to use `PriceOf(7) ?? 0` directly in `Main` instead of `Total`. What does the customer pay for an unknown product? ## Learn more - [Coalesce](https://rux-lang.dev/docs/learn/coalesce) and [Coalesce exit](https://rux-lang.dev/docs/learn/coalesce-exit) — `??` with a value and with `return` - [Optional propagate](https://rux-lang.dev/docs/learn/optional-propagate) — `?` on an optional - [Fail](https://rux-lang.dev/docs/learn/fail) — the statement used as the fallback here # Nested fallible ::note **You'll need**: [Nested optional](https://rux-lang.dev/docs/learn/nested-optional), [Outcome](https://rux-lang.dev/docs/learn/outcome) :: Optionals and fallibles nest, and each level keeps its own meaning. You saw that with optionals in [Nested optional](https://rux-lang.dev/docs/learn/nested-optional); this lesson does the same with fallibles. Two shapes come up all the time, and both are about keeping two different answers apart. ## The next value, the end, or a failure `int? ! SensorError` is the shape of "read the next value". Three answers are possible: a value, no more values, or the read itself broke: ```rux func Reading(sensor: int, index: int) -> int? ! SensorError { ``` Running out is not an error, and a broken sensor is not "no more" — so both levels are needed. Patterns nest to reach each answer: ```rux match Reading(sensor, index) { .Success(value?) => Print(" {}", value), .Success(none) => { PrintLine(" (end)"); break; }, .Failure(e) => { PrintLine(" (sensor {} broke)", e.sensor); break; } } ``` | Pattern | Means | | ------------------ | -------------------------------------- | | `.Success(value?)` | the read worked and found a value | | `.Success(none)` | the read worked and found nothing more | | `.Failure(e)` | the read itself broke | Walking a folder in the `FileSystem` package has exactly this shape, as you will see in [Directory](https://rux-lang.dev/docs/learn/directory). ## An answer that can itself fail `(int ! RangeError) ! SensorError` is the shape of "ask for a result that can itself fail". The outer failure means the question never got an answer. A success holds the answer — and that answer may be a failure of its own: the sensor replied, and what it replied was "out of range". ```rux if sensor == 2 { return .Success(.Failure(RangeError { value: 999 })); } return .Success(.Success(21)); ``` The parentheses are required. A type holds at most one `!` without them, so `int ! RangeError ! SensorError` is refused, and the help line suggests the two groupings — `(T ! E) ! F` or `T ! (E ! F)` — which mean different things. ```mermaid flowchart LR test["`SelfTest(sensor)`"] --> outer{"Outer level:
did the sensor answer?"} outer -- "`.Failure(e)`" --> none["no answer
(a `SensorError`)"] outer -- "`.Success(answer)`" --> inner{"Inner level:
what did it answer?"} inner -- "`.Success(value)`" --> ok["a reading"] inner -- "`.Failure(e)`" --> range["out of range
(a `RangeError`)"] ``` ## Levels never merge An inner failure is ordinary data inside a success, so `?` or `catch` on the outer level never touches it. Here `catch` handles only the outer failure, and the inner one comes through intact: ```rux let inner = SelfTest(2) catch { else => .Success(0) }; match inner { .Success(v) => PrintLine("ok {}", v), .Failure(e) => PrintLine("inner failure {}", e.value) } ``` Sensor 2 did answer, so the `catch` has nothing to do, and the program prints `inner failure 999`. The `else` arm's `.Success(0)` would only stand in for an outer failure — and since it replaces an answer, it has to be one, an `int ! RangeError`. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Errors/NestedFallible){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // Native forms nest, and each level keeps its own meaning. Two shapes come up // all the time. // // `int? ! SensorError` — "read the next value". Three answers are possible: // a value, no more values (`none`), or the read itself broke (a failure). // Running out is not an error and a broken sensor is not "no more", so both // levels are needed. Walking a folder in the `FileSystem` package has exactly // this shape. // // `(int ! RangeError) ! SensorError` — "ask for a result that can itself // fail". The outer failure means the question never got an answer. A success // holds the answer, and that answer may be a failure of its own: the sensor // replied, and what it replied was "out of range". // // Levels never merge. An inner failure is ordinary data inside a success, so // `?` or `catch` on the outer level never touches it. Patterns nest to reach // every case: `.Success(value?)`, `.Success(none)`, `.Success(.Failure(e))`. import Io::{ Print, PrintLine }; struct SensorError { sensor: int; } struct RangeError { value: int; } // Sensor 1 logged three readings. Sensor 2 broke while reading its third. func Reading(sensor: int, index: int) -> int? ! SensorError { if sensor == 2 && index == 2 { fail SensorError { sensor: sensor }; } if index >= 3 { return none; } return 20 + index; } // Sensor 1 answers 21, sensor 2 answers with a reading it rejects, and // sensor 3 does not answer at all. func SelfTest(sensor: int) -> (int ! RangeError) ! SensorError { if sensor == 3 { fail SensorError { sensor: sensor }; } if sensor == 2 { return .Success(.Failure(RangeError { value: 999 })); } return .Success(.Success(21)); } func Main() -> int { for sensor in 1..=2 { Print("sensor {} log:", sensor); for index in 0..10 { match Reading(sensor, index) { .Success(value?) => Print(" {}", value), .Success(none) => { PrintLine(" (end)"); break; }, .Failure(e) => { PrintLine(" (sensor {} broke)", e.sensor); break; } } } } for sensor in 1..=3 { match SelfTest(sensor) { .Success(.Success(value)) => PrintLine("sensor {} test: reads {}", sensor, value), .Success(.Failure(e)) => PrintLine("sensor {} test: {} is out of range", sensor, e.value), .Failure(e) => PrintLine("sensor {} test: no answer", e.sensor) } } return 0; } ``` ## Run it ```sh cd Examples/Errors/NestedFallible rux run ``` ```text sensor 1 log: 20 21 22 (end) sensor 2 log: 20 21 (sensor 2 broke) sensor 1 test: reads 21 sensor 2 test: 999 is out of range sensor 3 test: no answer ``` ## Common mistakes ::mistake **Forgetting the end of the data.**:br Drop the `.Success(none)` arm and the compiler says: ```text error: match on 'int? ! SensorError' is not exhaustive; missing .Success(none) ``` :: ::mistake **Treating the outer success as the reading.**:br In `SelfTest`'s match, `.Success(value)` binds the inner `int ! RangeError`, not an `int`. `value + 1` there is an error: ```text error: operator '+' cannot combine left operand 'int ! RangeError' with right operand 'int' ``` Match one level deeper with `.Success(.Success(value))`. :: ::mistake **Leaving out the parentheses.**:br`int ! RangeError ! SensorError` is an error: ```text error: a type contains at most one unparenthesized '!' ``` Group the level you mean. :: ## Try it yourself 1. Extend the first loop to sensor 3 with `1..=3`. Predict its log line before you run. 2. Make sensor 1's self-test answer 150 and treat anything over 100 as out of range. 3. Write `func FirstReading(sensor: int) -> int? ! SensorError` that returns the reading at index 0 using `?` on the outer level. What type does `Reading(sensor, 0)?` have? ## Learn more - [Nested optional](https://rux-lang.dev/docs/learn/nested-optional) — the same idea with `T??` - [Outcome](https://rux-lang.dev/docs/learn/outcome) — `.Success` and `.Failure` as patterns and constructors - [Iterator](https://rux-lang.dev/docs/learn/iterator) — `T?` as "the next item, or the end" - [Directory](https://rux-lang.dev/docs/learn/directory) — a real `T? ! E` from the `FileSystem` package # Panic ::note **You'll need**: [Match expression](https://rux-lang.dev/docs/learn/match-expression), [Range pattern](https://rux-lang.dev/docs/learn/range-pattern), [Fallible](https://rux-lang.dev/docs/learn/fallible) :: A fallible `T ! E` is for failures a caller can do something about: a bad number typed by a user, a file that is missing. Some situations are not like that. They cannot happen unless the program itself is wrong, and no caller could sensibly recover. For those there is `Core::Panic(message)`. ## Failures and bugs The question to ask is: *could this happen in a program with no bugs?* | | A fallible `T ! E` | `Panic` | | ----------- | ----------------------------------------------------- | --------------------------- | | Is for | something the world can do: bad input, a missing file | something only a bug can do | | The caller | must handle it, and can recover | never sees it | | The program | carries on | stops at once | | Cleanup | runs, as on any `return` | does not run | A month number of 13 typed by a user is a failure: tell them and ask again. A month number of 13 computed by `% 12 + 1` is a bug: the arithmetic is wrong, and nothing the caller could do would fix it. ## What Panic does `Panic` prints its message and where it was called, on the error stream, then stops the program at once. Nothing unwinds: no cleanup runs, no caller gets a chance to catch it, and the program exits with a failure status. That is on purpose — once something "impossible" has happened, the program's assumptions are broken, and running more of its code would only spread the damage. This program never panics, but change the month calculation to `start + offset as uint` and the third month is 13. The output then ends like this, and nothing after it runs: ```text month 11: 30 days month 12: 31 days month 13 does not exist Panic: a month is always 1 to 12 at BadMonth (Src/Main.rux:30:5) ``` Rux panics the same way on its own when an array index is out of range: the program stops with `Panic: index out of range` and the place of the bad subscript. ## Panic never returns Because `Panic` never returns, it may stand where a value is expected. Every arm of `DaysIn`'s match must produce an `int`, and the `else` arm produces none — it never finishes: ```rux return match month { 2 => 28, 4 => 30, 6 => 30, 9 => 30, 11 => 30, 1..=12 => 31, else => BadMonth(month) }; ``` The `1..=12` [range pattern](https://rux-lang.dev/docs/learn/range-pattern) gives every other real month 31 days, so the `else` arm is reached only by a month that does not exist. ## #NoReturn for your own functions A function of your own can promise the same with the `#NoReturn()` attribute. `BadMonth` uses that to print the offending value, which a plain `Panic` message cannot include, before it panics: ```rux #NoReturn() func BadMonth(month: uint) { PrintLine("month {} does not exist", month); Panic("a month is always 1 to 12"); } ``` Without the attribute, `BadMonth` looks like an ordinary function that returns nothing, and the `else` arm no longer produces an `int`. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Errors/Panic){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // A fallible `T ! E` is for failures a caller can do something about: a bad // number typed by a user, a file that is missing. Some situations are not like // that. They cannot happen unless the program itself is wrong, and no caller // could sensibly recover. For those there is `Core::Panic(message)`. // // `Panic` prints its message and where it was called, then stops the program // at once. Nothing unwinds: no cleanup runs, no caller gets a chance to catch // it, and the program exits with a failure status. That is on purpose — once // something "impossible" has happened, the program's assumptions are broken, // and running more of its code would only spread the damage. // // `Panic` never returns, so it may stand where a value is expected, like the // `else` arm below. A function of your own can promise the same with the // `#NoReturn()` attribute. `BadMonth` uses that to print the offending value, // which a plain `Panic` message cannot include, before it panics. // // This program never panics: `% 12 + 1` keeps every month between 1 and 12. // If `BadMonth` were reached, the output would end like this, and nothing // after it would run: // // month 13 does not exist // Panic: a month is always 1 to 12 // at BadMonth (Src/Main.rux:30:5) import Core::Panic; import Io::PrintLine; #NoReturn() func BadMonth(month: uint) { PrintLine("month {} does not exist", month); Panic("a month is always 1 to 12"); } func DaysIn(month: uint) -> int { return match month { 2 => 28, 4 => 30, 6 => 30, 9 => 30, 11 => 30, 1..=12 => 31, else => BadMonth(month) }; } func Main() -> int { // A loan that starts in November, counted month by month. let start: uint = 11; var total = 0; for offset in 0..4 { let month = (start - 1 + offset as uint) % 12 + 1; let days = DaysIn(month); total += days; PrintLine("month {:2}: {} days", month, days); } PrintLine("total: {} days", total); return 0; } ``` Besides `Io`, its `Rux.toml` lists `Core` under `[Dependencies]`. ## Run it ```sh cd Examples/Errors/Panic rux run ``` ```text month 11: 30 days month 12: 31 days month 1: 31 days month 2: 28 days total: 120 days ``` ## Common mistakes ::mistake **Forgetting #NoReturn.**:br Remove the attribute and `DaysIn` stops compiling: ```text error: match arm type mismatch: expected 'int', found '()' ``` The compiler no longer knows that `BadMonth` never comes back. :: ::mistake **Panicking on bad input.**:br Input from a user, a file or the network can be wrong in a working program. Report that with a fallible so the caller can recover; keep `Panic` for the cases only a bug can reach. :: ::mistake **Expecting cleanup to run.**:br A panic stops the program at once. A `defer` that would run on a `return` or a failed `?` does not run on a panic. :: ## Try it yourself 1. Change the month calculation to `start + offset as uint` and run the program. Compare the output with the listing above. 2. Make `DaysIn` panic for month 0 with a message of its own, before the `else` arm. 3. Write a `#NoReturn()` function `Unreachable(where: char8[..])` that prints `where` and panics, and use it in another `match`. ## Learn more - [Panic](https://rux-lang.dev/docs/api/core/diagnostics#panic) in the API reference - [Fatal errors](https://rux-lang.dev/docs/lang/errors/panics) and [NoReturn](https://rux-lang.dev/docs/lang/attributes/noreturn) in the Rux Reference - [Assert](https://rux-lang.dev/docs/learn/assert) — a panic with a condition attached - [Fallible](https://rux-lang.dev/docs/learn/fallible) — for failures a caller can handle # Assert ::note **You'll need**: [Panic](https://rux-lang.dev/docs/learn/panic), [Slice](https://rux-lang.dev/docs/learn/slice) :: An *assertion* states something the program relies on, and checks it while the program runs. It is a [panic](https://rux-lang.dev/docs/learn/panic) with a condition attached: when the condition holds, nothing happens; when it does not, the program stops. Assertions are for the same kind of problem as `Panic` — a bug, not bad input. They make an assumption visible in the code, and make sure that if it is ever wrong, the program says so at once instead of carrying on with nonsense. ## Assert The median of a list is its middle score, and an empty list has no middle: ```rux Assert(scores.length > 0, "a median needs at least one score"); ``` Call `Median` with an empty slice and the program stops exactly like a `Panic`, reporting the message and where the assertion is: ```text Assertion failed: a median needs at least one score at Median (Src/Main.rux:43:5) ``` Write the message as what was *expected*, since the failing value is not printed. "a median needs at least one score" tells the reader the rule that was broken; "empty list" would only describe the symptom. ## DebugAssert `Core` has two assertions, and the difference is the build: ```rux DebugAssert(InOrder(scores), "the scores are sorted"); ``` | | `Assert` | `DebugAssert` | | ----------------------------------- | ------------------------------------------------ | ----------------------------------------------------------------------- | | Debug build (`rux run`) | checked | checked | | Release build (`rux run --release`) | checked | removed — the condition is not evaluated | | Use it for | a promise that must hold in the program you ship | a check worth making while developing, too slow to pay for when shipped | `InOrder` is a whole pass over the scores. That is worth doing while developing, but it would turn a cheap lookup into a slow one on every call in a shipped program — so it sits in a `DebugAssert`. ## Removed means not evaluated `InOrder` prints a line so you can see the difference. Run the program both ways and the line appears only in the debug build — in a release build the call never happens at all. That has two consequences. An expensive check costs nothing when shipped. And a condition with a side effect loses that effect: anything a `DebugAssert`'s condition *does* is gone from the release build. It also means a release build no longer catches the mistake the check was there for. Give `Median` the unsorted scores `[3, 8, 5, 13, 21]`, and the debug build stops with `Assertion failed: the scores are sorted`, while the release build quietly prints `median: 5`. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Errors/Assert){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // An assertion states something the program relies on, and checks it while // the program runs: // // Assert(scores.length > 0, "a median needs at least one score"); // // When the condition holds, nothing happens. When it does not, the program // stops exactly like a `Panic`, reporting the message and where it was: // // Assertion failed: a median needs at least one score // at Median (Src/Main.rux:43:5) // // Write the message as what was expected, since the failing value is not // printed. // // `Core` has two of them, and the difference is the build: // // - `Assert` is checked in every build. Use it for a promise that must hold // in the program you ship. // - `DebugAssert` is checked in a debug build (`rux run`) and removed from a // release build (`rux run --release`). Removed means its condition is not // even evaluated, so an expensive check costs nothing when shipped — and a // condition with a side effect loses that effect. // // `InOrder` below prints a line so you can see that difference: run the // program both ways and the line appears only in the debug build. import Core::{ Assert, DebugAssert }; import Io::PrintLine; // A whole pass over the scores: worth checking while developing, too slow to // pay for on every call in a shipped program. func InOrder(scores: int[..]) -> bool { PrintLine("(checking that the scores are in order)"); for i in 1..scores.length { if scores[i - 1] > scores[i] { return false; } } return true; } // The middle score of a sorted list. func Median(scores: int[..]) -> int { Assert(scores.length > 0, "a median needs at least one score"); DebugAssert(InOrder(scores), "the scores are sorted"); return scores[scores.length / 2]; } func Main() -> int { let scores = [3, 5, 8, 13, 21]; PrintLine("median: {}", Median(scores)); return 0; } ``` Besides `Io`, its `Rux.toml` lists `Core` under `[Dependencies]`. ## Run it ```sh cd Examples/Errors/Assert rux run ``` ```text (checking that the scores are in order) median: 8 ``` A release build drops the `DebugAssert`, so its check never runs: ```sh rux run --release ``` ```text median: 8 ``` ## Common mistakes ::mistake **Work inside a DebugAssert.**:br A condition such as `DebugAssert(Load(settings), "...")` does its loading in a debug build and not at all in a release build. Do the work first, store the result, and assert on the stored value. :: ::mistake **A condition that is not a bool.**:br`Assert(scores.length, "...")` is an error: ```text error: argument 1 to 'Assert' has type 'uint64', but parameter 'condition' requires 'bool8' ``` Write the comparison out: `scores.length > 0`. :: ::mistake **Asserting on user input.**:br Like `Panic`, an assertion is for bugs. Input that can be wrong in a working program deserves a fallible and a helpful message, not a stopped program. :: ## Try it yourself 1. Call `Median(scores[0..0])` — an empty slice of the scores — and read the assertion message. 2. Change the scores to `[3, 8, 5, 13, 21]` and run with `rux run` and `rux run --release`. Compare the two. 3. Add an `Assert` that every score is between 0 and 100, and decide whether it should be an `Assert` or a `DebugAssert`. ## Learn more - [Assert](https://rux-lang.dev/docs/api/core/diagnostics#assert) and [#build](https://rux-lang.dev/docs/api/core/build#build-constant) in the API reference - [Build mode](https://rux-lang.dev/docs/learn/build-mode) — debug and release builds, and how a program can tell them apart - [rux run](https://rux-lang.dev/docs/cli/run) — the `--release` flag - [Panic](https://rux-lang.dev/docs/learn/panic) — the same stop, without a condition # Part 10: Sum types A setting in a configuration file is a number, a switch or a word. A token from a tokenizer is a number, a name or an operator. Rux writes "one of these types" directly in the type: `int32 | bool | char8[..]`. The value always knows which member it holds, and the compiler will not let you treat it as any one of them until you have asked. This part shows how to build such a value, how to ask, and how sums of different sizes fit together. ## What you will learn - What `A | B` means, and why it is a *set* of types: order and duplicates make no difference, and `int32 | int32` is plain `int32`. - How a value goes into a sum, and when a literal is ambiguous. - Matching a sum by the type it holds with a typed pattern, `n: int32 =>`, and covering every member. - Handling several members in one arm with a subset pattern, `box: Square | Rectangle =>`, and passing the smaller sum on. - Asking which member is active with `is`, which answers with a `bool` and never unpacks anything. - Widening: a smaller sum fits wherever a larger one is expected, but never the other way round. ## Into a sum and back out ```mermaid flowchart LR m["A member value
`Square { side: 2.0 }`"] -- "goes in" --> s(["`Circle | Square | Rectangle`"]) small["A smaller sum
`Square | Rectangle`"] -- "widening" --> s s --> t["typed pattern
`s: Square =>`"] s --> sub["subset pattern
`box: Square | Rectangle =>`"] s --> is["`is`
`shape is Circle`"] t --> t2["one member,
as its own type"] sub --> sub2["a smaller sum"] is --> is2["a `bool`, nothing unpacked"] ``` | You want to… | Use | Lesson | | ---------------------------------------- | ----------------------------------------- | ---------------------------------------------------------------- | | use the value inside | `match` with `n: int32 =>` | [Typed pattern](https://rux-lang.dev/docs/learn/typed-pattern) | | handle several members alike | `match` with `box: Square | Rectangle =>` | [Subset pattern](https://rux-lang.dev/docs/learn/subset-pattern) | | only know which member it is | `value is T`, `value is (A | B)` | [The is operator](https://rux-lang.dev/docs/learn/is) | | pass a smaller sum to a larger parameter | nothing — it widens by itself | [Sum widening](https://rux-lang.dev/docs/learn/sum-widening) | ## Lessons | | Lesson | What you will learn | | ---- | ---------------------------------------------------------------- | ---------------------------------------------------------- | | 10.1 | [Sum type](https://rux-lang.dev/docs/learn/sum-type) | a value that can be an `int32` or a `bool`: `int32 | bool` | | 10.2 | [Typed pattern](https://rux-lang.dev/docs/learn/typed-pattern) | match a sum by the type it holds | | 10.3 | [Subset pattern](https://rux-lang.dev/docs/learn/subset-pattern) | match several members of a sum in one arm | | 10.4 | [The is operator](https://rux-lang.dev/docs/learn/is) | ask which type a sum holds with `is` | | 10.5 | [Sum widening](https://rux-lang.dev/docs/learn/sum-widening) | pass a smaller sum where a larger one is expected | ## Before you start Finish Parts 1–9 first. This part leans on [Type alias](https://rux-lang.dev/docs/learn/type-alias), [Variant](https://rux-lang.dev/docs/learn/variant) and [Variant match](https://rux-lang.dev/docs/learn/variant-match) from Part 6 — a sum is matched much as a variant is — and on [Error sum](https://rux-lang.dev/docs/learn/error-sum) from Part 9, where you first wrote `A | B` as a function's error type. Each lesson's package is in the Examples repository's `SumTypes/` folder: ```sh cd Examples/SumTypes/SumType rux run ``` ## After this part [Part 11: Ownership](https://rux-lang.dev/docs/learn/ownership) turns from what a value *is* to who *owns* it — copies, moves, destructors and `defer`. Sums come back in [Part 13: Generics](https://rux-lang.dev/docs/learn/generics), where [Generic sum](https://rux-lang.dev/docs/learn/generic-sum) builds `T | U` from type parameters and the "a sum is a set" rule decides what `T | U` becomes when `T` and `U` are the same type. The next checkpoint projects, [Circle](https://rux-lang.dev/docs/learn/circle) and [Quadratic](https://rux-lang.dev/docs/learn/quadratic), come after Part 16. For the rules behind this part, see [`match`](https://rux-lang.dev/docs/lang/patterns/match), [Type tests](https://rux-lang.dev/docs/lang/sums/type-tests) and [Type aliases](https://rux-lang.dev/docs/lang/types/aliases) in the Rux Reference. # Sum type ::note **You'll need**: [Type alias](https://rux-lang.dev/docs/learn/type-alias), [Variant](https://rux-lang.dev/docs/learn/variant), [Error sum](https://rux-lang.dev/docs/learn/error-sum) :: A *sum type* holds one value whose type is one of a short list. `int32 | bool` reads "an `int32` or a `bool`": a variable of that type can hold `8080` now and `true` later, and it always knows which of the two it is holding. You have met the idea twice already. A [variant](https://rux-lang.dev/docs/learn/variant) holds one of several cases, and an [error sum](https://rux-lang.dev/docs/learn/error-sum) let a function fail in two unrelated ways. A sum type is the general form: any types at all, joined with `|`. This lesson builds sums, stores them and compares them. Getting a member back out takes a pattern, and that is the [next lesson](https://rux-lang.dev/docs/learn/typed-pattern). ## A value of one of several types A setting in a configuration file might be a number, a switch or a word. A [type alias](https://rux-lang.dev/docs/learn/type-alias) gives that sum a short name — it is still exactly `int32 | bool | char8[..]`, just easier to write: ```rux type Setting = int32 | bool | char8[..]; ``` A value of any member type goes straight into the sum, with nothing to wrap it in: ```rux let port: Setting = 8080; let verbose: Setting = true; let name: Setting = "server"; ``` The value picks the member. `8080` is an integer, and `Setting` has exactly one integer member, so `port` holds an `int32`. `true` can only be the `bool`, and `"server"` only the text. ```mermaid flowchart LR v["A value meets
a sum type"] --> q{"Is its type
a member?"} q -- "yes" --> ok["That member
becomes active"] q -- "an unsuffixed literal" --> lit{"How many members
of its kind?"} lit -- "exactly one" --> ok lit -- "several" --> amb["`error: integer literal`
`is ambiguous`"] q -- "no" --> err["`error: cannot assign`
`'float64' to …`"] ``` ## Switching members A `var` sum can change its member, not only its value. Each assignment replaces both the value and the record of which member is active: ```rux var limit: int32 | bool = 100; limit = false; limit = 250; ``` `limit` starts as the number 100, becomes the switch `false`, and ends as the number 250. A plain `int32` variable could never hold `false`, and a `bool` could never hold 250; the sum can hold either. ## A set of types A variant names its cases. A sum names only types, so its list is a **set**: the order the types are written in does not matter, and a type written twice counts once. These are three spellings of one type: ```rux let reordered: bool | int32 = limit; let repeated: int32 | bool | int32 = reordered; ``` No conversion happens on either line, because there is nothing to convert — `limit`, `reordered` and `repeated` all have the same type. The compiler even writes every sum in its own sorted order in error messages, so `int32 | bool` appears there as `bool8 | int32` (`bool8` is `bool`'s full name). The same rule makes a sum of one type just that type. `int32 | int32` collapses to `int32`, so it takes part in arithmetic like any other integer: ```rux let single: int32 | int32 = 20; PrintLine("single + 1 {}", single + 1); ``` | Written | Is the type | | ---------------------- | -------------- | | `int32 | bool` | `int32 | bool` | | `bool | int32` | the same type | | `int32 | bool | int32` | the same type | | `int32 | int32` | plain `int32` | That collapse looks like a curiosity now. It matters in [Generic sum](https://rux-lang.dev/docs/learn/generic-sum), where `T | U` is written before anyone knows whether `T` and `U` are the same type. ## Comparing sums Two sums are equal when the same member is active and the values agree: ```rux let off: int32 | bool = false; let zero: int32 | bool = 0; PrintLine("limit == 250 {}", limit == 250); PrintLine("repeated == limit {}", repeated == limit); PrintLine("off == zero {}", off == zero); ``` `off == zero` is `false`. A switch and a number are never equal, whatever their bits look like — `false` and `0` may well be the same byte in memory, but the sum remembers that one is a `bool` and the other an `int32`. ## Sum or variant? Both hold one of several things. The difference is what the alternatives are called: | | Variant | Sum | | -------------------- | ------------------------------- | -------------------------------- | | Declared as | `variant Reading { … }` | `int32 | bool`, no declaration | | Alternatives are | named cases, such as `.Exact` | types, such as `int32` | | Two of the same type | allowed, as two different cases | impossible — duplicates collapse | | Matched with | `.Exact(value) =>` | `value: int32 =>` | Reach for a variant when the cases *mean* different things even if they carry the same type — a temperature in Celsius and one in Fahrenheit are both `float64`. Reach for a sum when the types themselves are the difference, as with a setting that is a number, a switch or a word. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/SumTypes/SumType){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // A sum type holds one value whose type is one of a short list. `int32 | bool` is "an int32 or // a bool": a variable of that type can hold 8080 now and `true` later, and it always knows which // of the two it is holding. // // You have met this shape before. A variant also holds one of several things, but it names its // cases. A sum names only types, so its list is a *set* of types: the order they are written in // does not matter, and a type written twice counts once. `int32 | bool`, `bool | int32` and // `int32 | bool | int32` are three spellings of one type. // // Getting a member back out takes a pattern, and that is the next lesson. Here a sum is only // built, stored, reassigned and compared. import Io::PrintLine; // A setting in a configuration file is a number, a switch or a word. A type alias gives the sum // a short name; it is still exactly `int32 | bool | char8[..]`. type Setting = int32 | bool | char8[..]; func Main() -> int { // A value of any member type goes straight into the sum. The value picks the member: 8080 // is an integer, and the sum has exactly one integer member to put it in. let port: Setting = 8080; let verbose: Setting = true; let name: Setting = "server"; // A `var` sum can switch members. Each assignment replaces both the value and the record of // which member is active. var limit: int32 | bool = 100; limit = false; limit = 250; // Order and duplicates do not make a new type, so these copies need no conversion at all. let reordered: bool | int32 = limit; let repeated: int32 | bool | int32 = reordered; // Two sums are equal when the same member is active and the values agree. A number and a // switch are never equal, whatever their bits look like. let off: int32 | bool = false; let zero: int32 | bool = 0; PrintLine("limit == 250 {}", limit == 250); PrintLine("repeated == limit {}", repeated == limit); PrintLine("off == zero {}", off == zero); // A sum of one type is just that type: `int32 | int32` collapses to `int32`, so it takes // part in arithmetic like any other integer. let single: int32 | int32 = 20; PrintLine("single + 1 {}", single + 1); // The other settings are stored and ready, but printing one needs its member first. // `PrintLine("{}", port)` is rejected: a sum is not a number, even when it holds one. return 0; } ``` ## Run it ```sh cd Examples/SumTypes/SumType rux run ``` ```text limit == 250 true repeated == limit true off == zero false single + 1 21 ``` ## Common mistakes ::mistake **Using a sum as if it were its member.**:br A sum is not a number, even while it holds one. `PrintLine("{}", port)` fails with: ```text error: no matching overload for 'PrintLine' with argument types (char8[..], bool8 | char8[..] | int32) ``` With `let x: int32 | bool = 3;` the sum `x + 1` fails with: ```text error: operator '+' cannot combine left operand 'bool8 | int32' with right operand 'int' ``` Take the member out with a [typed pattern](https://rux-lang.dev/docs/learn/typed-pattern) first. :: ::mistake **A literal that fits more than one member.**:br`let s: int32 | int64 = 5;` fails with: ```text error: integer literal is ambiguous for 'int32 | int64', which has several integer members; add a suffix or a cast ``` The compiler will not guess which integer you meant. Write `5i64`, or `5 as int32`. :: ::mistake **A value whose type is not a member.**:br`let s: int32 | bool = 2.5;` fails with: ```text error: cannot assign 'float64' to 'bool8 | int32' ``` A sum holds its members and nothing else — no conversion is tried. :: ::mistake **Comparing a sum with a plain value.**:br`limit == false` fails with: ```text error: operator '==' cannot compare 'bool8 | int32' with 'bool8' ``` The compiler's note explains why: a comparison never injects, widens, or wraps an operand. Give the value the sum's type first, as the program does with `let off: int32 | bool = false;`, and compare two sums. :: ## Try it yourself 1. Add `float64` to `Setting` and store `let ratio: Setting = 0.75;`. Why is `0.75` not ambiguous, when an integer literal would be for `int32 | int64`? 2. Declare `let wide: int32 | int64 = 5;`, read the error, then fix it with a suffix. 3. Declare `let alsoOff: bool | int32 = false;` and print `off == alsoOff`. The two types are spelled differently — can they be compared? 4. Try `PrintLine("{}", port);` and read which parameter type the sum fails to satisfy. ## Learn more - [Typed pattern](https://rux-lang.dev/docs/learn/typed-pattern) — getting a member back out of a sum - [Variant](https://rux-lang.dev/docs/learn/variant) and [Error sum](https://rux-lang.dev/docs/learn/error-sum) — the two forms you met before this one - [Type aliases](https://rux-lang.dev/docs/lang/types/aliases) in the Rux Reference # Typed pattern ::note **You'll need**: [Sum type](https://rux-lang.dev/docs/learn/sum-type), [Variant match](https://rux-lang.dev/docs/learn/variant-match), [Match expression](https://rux-lang.dev/docs/learn/match-expression) :: A sum knows which member it holds, and a *typed pattern* asks it. The arm `n: int32 =>` matches only when the active member is `int32`, and binds that value to `n` **as an `int32`** — so inside the arm it is an ordinary number again. It prints, it adds, it compares. In the [last lesson](https://rux-lang.dev/docs/learn/sum-type) a sum could be built, stored and compared, but not printed or used in arithmetic. This lesson is the way back out. ## One arm per member A [variant match](https://rux-lang.dev/docs/learn/variant-match) arm names a case: `.Exact(value) =>`. A sum has no case names, so its arm names a **type** instead — the binding, a colon, the member type: ```rux type Setting = int32 | bool | char8[..]; func Show(key: char8[..], value: Setting) { match value { seconds: int32 => PrintLine("{:8} = {} ms", key, seconds * 1000), flag: bool => PrintLine("{:8} = {}", key, flag ? "on" : "off"), word: char8[..] => PrintLine("{:8} = \"{}\"", key, word) } } ``` Each binding has its member's own type. `seconds` is an `int32`, so `seconds * 1000` is integer arithmetic. `flag` is a `bool`, so it can drive the [ternary](https://rux-lang.dev/docs/learn/ternary). `word` is a text slice, ready for a placeholder. ```mermaid flowchart LR v["`value: Setting`"] --> q{"Which member
is active?"} q -- "`int32`" --> a1["`seconds: int32 =>`
`seconds * 1000`"] q -- "`bool`" --> a2["`flag: bool =>`
on or off"] q -- "`char8[..]`" --> a3["`word: char8[..] =>`
print the word"] ``` Exactly one arm runs, the one whose type is the active member. The order of the arms does not change which one that is — a member can only ever match its own arm. ## A match that produces a value As an expression, a match on a sum produces one value from whichever arm ran, just as a [match expression](https://rux-lang.dev/docs/learn/match-expression) on a number does: ```rux func Weight(value: Setting) -> int32 { return match value { n: int32 => n, flag: bool => flag ? 1 : 0, _: char8[..] => -1 }; } ``` All three arms produce an `int32`, so the whole `match` is an `int32`, whichever member came in. ## Matching without a binding The text arm in `Weight` needs no value from its member — only the fact that the setting is text. `_: char8[..]` matches the type without naming it. Use it whenever an arm would otherwise bind a name it never reads. | Pattern | Matches when the active member is | Binds | | -------------- | --------------------------------- | --------------- | | `n: int32` | `int32` | `n`, an `int32` | | `_: char8[..]` | `char8[..]` | nothing | | `else` | anything earlier arms left | nothing | ## Every member must be covered A match on a sum must handle every member, just as a variant match handles every case. Leave out an arm and the compiler names the pattern you still need. Without the `int32` arm in `Show`: ```text error: match on 'bool8 | char8[..] | int32' is not exhaustive; missing _: int32 ``` The compiler spells the sum in its own sorted order, and `bool` by its full name `bool8`, so the members may not appear in the order you wrote them. When several members are handled alike, an `else` arm covers whatever the earlier arms left: ```rux match value { n: int32 => PrintLine("number {}", n), else => PrintLine("something else") } ``` That works, but it gives something up: add a fourth member to `Setting` later and this match quietly sends it to `else`. With one arm per member, the compiler stops you and points at every match that needs the new arm. The [next lesson](https://rux-lang.dev/docs/learn/subset-pattern) shows a middle way — one arm for a chosen group of members. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/SumTypes/TypedPattern){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // A sum knows which member it holds, and a typed pattern asks it. The arm `n: int32 =>` matches // only when the active member is `int32`, and binds that value to `n` *as an int32*, so inside // the arm it is an ordinary number again: it prints, it adds, it compares. // // A variant arm names a case, `.Exact(value) =>`. A sum has no case names, so its arm names a // type instead: the binding, a colon, the member type. `_: char8[..] =>` matches the member // without binding it, for when only the fact matters. // // The match must cover every member, just as a variant match covers every case. Leave out the // `int32` arm below and the compiler names the pattern you still need: // error: match on 'bool8 | char8[..] | int32' is not exhaustive; missing _: int32 // (The compiler spells the sum in its own sorted order, and `bool` by its full name `bool8`.) import Io::PrintLine; type Setting = int32 | bool | char8[..]; // One arm per member. Each binding has the member's own type, so `seconds * 1000` is integer // arithmetic and `word` is a text slice ready for a placeholder. func Show(key: char8[..], value: Setting) { match value { seconds: int32 => PrintLine("{:8} = {} ms", key, seconds * 1000), flag: bool => PrintLine("{:8} = {}", key, flag ? "on" : "off"), word: char8[..] => PrintLine("{:8} = \"{}\"", key, word) } } // As an expression, a match on a sum produces one value from whichever arm ran. Here the text // arm needs no value from its member, so `_` matches the type without naming it. func Weight(value: Setting) -> int32 { return match value { n: int32 => n, flag: bool => flag ? 1 : 0, _: char8[..] => -1 }; } func Main() -> int { let timeout: Setting = 30; let verbose: Setting = true; let mode: Setting = "fast"; Show("timeout", timeout); Show("verbose", verbose); Show("mode", mode); PrintLine("weights {} {} {}", Weight(timeout), Weight(verbose), Weight(mode)); return 0; } ``` ## Run it ```sh cd Examples/SumTypes/TypedPattern rux run ``` ```text timeout = 30000 ms verbose = on mode = "fast" weights 30 1 -1 ``` ## Common mistakes ::mistake **Leaving out a member.**:br A match on a sum must be exhaustive. Drop the `int32` arm from `Show` and it fails with: ```text error: match on 'bool8 | char8[..] | int32' is not exhaustive; missing _: int32 ``` :: ::mistake **Naming a type that is not a member.**:br`n: int64 =>` on a `Setting` fails with: ```text error: type 'int64' is not a member or subset of sum 'bool8 | char8[..] | int32' ``` The pattern must name the member exactly — an `int32` member is not matched by a wider integer type. :: ::mistake **Writing only the type.**:br An arm `int32 => "number"` fails with: ```text error: pattern 'int32' cannot bind a new variable because 'int32' already names a type ``` A bare name in a pattern is a new binding, and a type name cannot be one. Write `_: int32 =>`, or `n: int32 =>` if you need the value. :: ## Try it yourself 1. Add `float64` to `Setting` and run the program. Read the error, then add a `float64` arm to both `Show` and `Weight`. 2. Write `func Kind(value: Setting) -> char8[..]` that returns `"number"`, `"switch"` or `"text"`. Which patterns need no binding at all? 3. Rewrite `Show` with one `int32` arm and an `else` arm. Then add a fourth member to `Setting` and compare: which version of `Show` makes the compiler complain? ## Learn more - [Subset pattern](https://rux-lang.dev/docs/learn/subset-pattern) — one arm for several members - [Variant match](https://rux-lang.dev/docs/learn/variant-match) — the same idea for named cases - [`match`](https://rux-lang.dev/docs/lang/patterns/match) in the Rux Reference # Subset pattern ::note **You'll need**: [Typed pattern](https://rux-lang.dev/docs/learn/typed-pattern), [Struct](https://rux-lang.dev/docs/learn/struct) :: A typed pattern can name more than one member. The arm `box: Square | Rectangle =>` matches when the active member is either of the two, and `box` is then a **smaller sum**: still one of several types, but only the ones the arm let through. That is useful when some members are handled the same way. A circle has no corners, while a square and a rectangle both have four — so counting corners needs two arms, not three. And when the shared members still need work of their own, the smaller sum can be handed on whole to a function that takes exactly those members. ## The shapes Each shape is a [struct](https://rux-lang.dev/docs/learn/struct) of its own, and `Shape` is the sum of all three: ```rux struct Circle { radius: float64; } struct Square { side: float64; } struct Rectangle { width: float64; height: float64; } type Shape = Circle | Square | Rectangle; ``` ## Several members in one arm Write the members after the colon, joined by `|` just as in the type itself: ```rux func Corners(shape: Shape) -> int32 { return match shape { _: Circle => 0, _: Square | Rectangle => 4 }; } ``` A subset needs no binding either: `_: Square | Rectangle` only asks the question. The match is still exhaustive — between them, the two arms cover all three members. ## The binding is a smaller sum With a name instead of `_`, the arm binds what it matched. Here `box` has the type `Square | Rectangle`: ```rux func Describe(shape: Shape) { match shape { c: Circle => PrintLine("circle, radius {}, {} corners", c.radius, Corners(shape)), box: Square | Rectangle => PrintLine("box, area {}, {} corners", BoxArea(box), Corners(shape)) } } ``` `box` is not a square, and it is not a rectangle — it is whichever of the two `shape` held, and it remembers which. That is exactly what `BoxArea` takes, so `box` is passed on whole: ```rux func BoxArea(box: Square | Rectangle) -> float64 { return match box { s: Square => s.side * s.side, r: Rectangle => r.width * r.height }; } ``` `BoxArea` only ever sees boxes, so it matches two members and no more. It never has to say what to do with a circle, because a circle cannot reach it. ```mermaid flowchart LR s["`shape: Shape`"] --> d{"`Describe`"} d -- "`c: Circle`" --> c["radius, 0 corners"] d -- "`box: Square | Rectangle`" --> b{"`BoxArea(box)`"} b -- "`s: Square`" --> sq["`side * side`"] b -- "`r: Rectangle`" --> re["`width * height`"] ``` | Pattern | Matches when the active member is | The binding's type | | ------------------------- | --------------------------------- | -------------------- | | `c: Circle` | `Circle` | `Circle` | | `box: Square | Rectangle` | `Square` or `Rectangle` | `Square | Rectangle` | | `_: Square | Rectangle` | `Square` or `Rectangle` | nothing is bound | ## The first matching arm wins Arms are tried from the top, and the first one whose types include the active member runs. Two subsets may share a member — with `round: Circle | Square =>` above `box: Square | Rectangle =>`, a square goes to the first arm and a rectangle to the second. What the compiler refuses is an arm that can *never* run. Once `box: Square | Rectangle` has taken every square, a later `s: Square =>` would be dead code, and it is an error rather than a silent leftover. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/SumTypes/SubsetPattern){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // A typed pattern can name more than one member. The arm `box: Square | Rectangle =>` matches // when the active member is either of the two, and `box` is then a *smaller sum*: it is still // one of several types, but only the ones the arm let through. // // That is useful when some members are handled the same way. A circle has no corners and a // square and a rectangle both have four, so the corner count needs two arms, not three. And when // the shared members need their own work, the smaller sum can be handed on whole to a function // that takes exactly those members, and matched again there. // // An arm after a subset may not repeat a member the subset already took. Add `s: Square =>` // after the `box` arm in `Describe` and the compiler refuses the arm that can never run: // error: match arm is unreachable because earlier arms already match every value it matches import Io::PrintLine; struct Circle { radius: float64; } struct Square { side: float64; } struct Rectangle { width: float64; height: float64; } type Shape = Circle | Square | Rectangle; // A subset needs no binding either: `_: Square | Rectangle` only asks the question. func Corners(shape: Shape) -> int32 { return match shape { _: Circle => 0, _: Square | Rectangle => 4 }; } // This function only ever sees boxes, so it matches two members and no more. func BoxArea(box: Square | Rectangle) -> float64 { return match box { s: Square => s.side * s.side, r: Rectangle => r.width * r.height }; } func Describe(shape: Shape) { match shape { c: Circle => PrintLine("circle, radius {}, {} corners", c.radius, Corners(shape)), box: Square | Rectangle => PrintLine("box, area {}, {} corners", BoxArea(box), Corners(shape)) } } func Main() -> int { let wheel: Shape = Circle { radius: 1.5 }; let tile: Shape = Square { side: 2.0 }; let door: Shape = Rectangle { width: 1.0, height: 2.5 }; Describe(wheel); Describe(tile); Describe(door); return 0; } ``` ## Run it ```sh cd Examples/SumTypes/SubsetPattern rux run ``` ```text circle, radius 1.5, 0 corners box, area 4.0, 4 corners box, area 2.5, 4 corners ``` ## Common mistakes ::mistake **An arm that an earlier subset already covers.**:br Add `s: Square =>` after the `box` arm in `Describe` and it fails with: ```text error: match arm is unreachable because earlier arms already match every value it matches ``` Every square has already gone to `box`. Either delete the arm, or move it above the subset so squares are handled on their own first. :: ::mistake **Reading a field through a smaller sum.**:br Inside the `box` arm, `box.side` fails with: ```text error: type 'Rectangle | Square' has no field 'side' ``` A rectangle has no `side`, and `box` might be one. Match `box` again, as `BoxArea` does, to reach the fields of each member. :: ## Try it yourself 1. Add `struct Triangle { base: float64; height: float64; }` to `Shape`. Which matches does the compiler now reject, and what does each one need? 2. Write `func IsRound(shape: Shape) -> bool` with exactly two arms. 3. Move `s: Square =>` above the `box` arm in `Describe`, so squares print differently from rectangles. Which members can still reach `box` now? ## Learn more - [The is operator](https://rux-lang.dev/docs/learn/is) — ask which member a sum holds without unpacking it - [Sum widening](https://rux-lang.dev/docs/learn/sum-widening) — passing a smaller sum where a larger one is expected - [`match`](https://rux-lang.dev/docs/lang/patterns/match) in the Rux Reference # The is operator ::note **You'll need**: [Subset pattern](https://rux-lang.dev/docs/learn/subset-pattern), [For](https://rux-lang.dev/docs/learn/for), [Array](https://rux-lang.dev/docs/learn/array) :: Sometimes a program only needs to know *which* member a sum holds, not what is inside it. Is this token a number? Is it an operator? `value is T` answers with a plain `bool`: `true` when the active member is `T`. A [typed pattern](https://rux-lang.dev/docs/learn/typed-pattern) can answer the same question, but it takes a whole `match` with an arm for every member. `is` is the one-line version for when a yes or no is all you want. ## The tokens A tokenizer turns the text `price + 2 - discount + 1` into pieces, and each piece is one of four types: ```rux struct Number { value: int32; } struct Name { text: char8[..]; } struct Plus {} struct Minus {} type Token = Number | Name | Plus | Minus; ``` `Plus` and `Minus` carry no fields at all — for them, the type *is* the whole message. The [array](https://rux-lang.dev/docs/learn/array) is annotated `Token[7]`, which makes every element a `Token`, so one array holds all four member types side by side: ```rux let tokens: Token[7] = [ Name { text: "price" }, Plus {}, Number { value: 2 }, Minus {}, Name { text: "discount" }, Plus {}, Number { value: 1 } ]; ``` ## Asking which member Inside the [loop](https://rux-lang.dev/docs/learn/for), `is` sorts the tokens without unpacking any of them: ```rux for token in tokens { if token is Number { numbers++; } if token is (Plus | Minus) { operators++; } } ``` `token is Number` is `true` for the two numbers. Put a smaller sum in parentheses, `token is (Plus | Minus)`, and the test is `true` when the active member is any one of them — the three operators here. It is the `is` form of a [subset pattern](https://rux-lang.dev/docs/learn/subset-pattern). The parentheses are required. Without them, `token is Plus | Minus` is refused, and the compiler's help shows the grouped form to write instead. ## An ordinary bool The result is a `bool` like any other, so it can be stored, printed or combined with `&&` and `||`: ```rux let startsWithName = tokens[0] is Name; PrintLine("starts with a name: {}", startsWithName); PrintLine("ends with a number: {}", tokens[6] is Number); ``` ## What is does not do `is` only asks. Two things follow from that. **It does not narrow.** Inside `if token is Number { … }`, `token` is still the whole `Token`, not a `Number`. Reading `token.value` there is rejected, because a `Name`, a `Plus` or a `Minus` has no `value`. To use what is inside, bind it with a typed pattern in a `match`. **It does not quietly answer `false`.** A test that could never be true is a mistake, and the compiler says so. `token is bool` is refused because `bool` is not a member of `Token`. On a value that is not a sum at all, `is` compares exact types, and a mismatch is an error too. ```mermaid flowchart LR q{"Do you need the
value inside?"} -- "no — only which member" --> is["`value is T`
`value is (A | B)`"] q -- "yes" --> m["`match` with a typed pattern
`n: Number => n.value`"] ``` | You want | Write | You get | | ------------------------------- | -------------------------------- | --------------- | | to know the member | `token is Number` | a `bool` | | to know if it is one of several | `token is (Plus | Minus)` | a `bool` | | the value inside | `match token { n: Number => … }` | `n`, a `Number` | ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/SumTypes/Is){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // Sometimes a program only needs to know *which* member a sum holds, not what is inside it. // `value is T` answers that with a plain `bool`: true when the active member is `T`. Put a smaller // sum in parentheses, `value is (Plus | Minus)`, and it is true when the active member is any one // of them. The parentheses are required: `token is Plus | Minus` is refused with // error: a sum type after 'is' must be grouped // help: write 'value is (Plus | Minus)' // // Two things `is` does not do: // // - It does not narrow. Inside `if token is Number { ... }`, `token` is still the whole sum, so // `token.value` is rejected: // error: type 'Minus | Name | Number | Plus' has no field 'value' // To use what is inside, bind it with a typed pattern in a `match`. // // - It does not quietly answer `false`. A test that could never be true is a mistake, and the // compiler says so. `token is bool` is refused because `bool` is not one of the members: // error: type 'bool8' is not a member or subset of sum 'Minus | Name | Number | Plus' // On a value that is not a sum at all, `is` compares exact types, and a mismatch is an error // too. The counter `numbers` is an `int`, so `numbers is bool` gives // error: 'is bool8' can never be true for a value of type 'int' import Io::PrintLine; // The pieces of the expression `price + 2 - discount + 1`, as a tokenizer might hand them over. struct Number { value: int32; } struct Name { text: char8[..]; } struct Plus {} struct Minus {} type Token = Number | Name | Plus | Minus; func Main() -> int { // The annotation makes every element a `Token`, so one array holds all four member types. let tokens: Token[7] = [ Name { text: "price" }, Plus {}, Number { value: 2 }, Minus {}, Name { text: "discount" }, Plus {}, Number { value: 1 } ]; var numbers = 0; var operators = 0; for token in tokens { // `is` only asks; the token is untouched and keeps its type. if token is Number { numbers++; } if token is (Plus | Minus) { operators++; } } PrintLine("{} numbers, {} operators", numbers, operators); // The result is an ordinary boolean, so it can be stored and printed like one. let startsWithName = tokens[0] is Name; PrintLine("starts with a name: {}", startsWithName); PrintLine("ends with a number: {}", tokens[6] is Number); return 0; } ``` ## Run it ```sh cd Examples/SumTypes/Is rux run ``` ```text 2 numbers, 3 operators starts with a name: true ends with a number: true ``` ## Common mistakes ::mistake **A sum after `is` without parentheses.**:br`token is Plus | Minus` fails with: ```text error: a sum type after 'is' must be grouped ``` The help says: ```text write 'value is (Plus | Minus)' ``` :: ::mistake **Expecting `is` to narrow.**:br`if token is Number { PrintLine("{}", token.value); }` fails with: ```text error: type 'Minus | Name | Number | Plus' has no field 'value' ``` After the test `token` is still the whole sum. Use `match token { n: Number => …, else => {} }` to get at the number. :: ::mistake **Testing a type that is not a member.**:br`token is bool` fails with: ```text error: type 'bool8' is not a member or subset of sum 'Minus | Name | Number | Plus' ``` A test that can never be true is an error, not a constant `false`. :: ::mistake **Testing a value that is not a sum.**:br The counter `numbers` is an `int`, so `numbers is bool` fails with: ```text error: 'is bool8' can never be true for a value of type 'int' ``` On an ordinary value, `is` compares exact types. :: ## Try it yourself 1. Count the `Name` tokens as well, and print all three counts. 2. Write `func IsOperator(token: Token) -> bool` with `is`, and use it in the loop. 3. Add up the values of all the `Number` tokens. Why does this one need a `match` with an `else => {}` arm rather than `is`? ## Learn more - [Typed pattern](https://rux-lang.dev/docs/learn/typed-pattern) and [Subset pattern](https://rux-lang.dev/docs/learn/subset-pattern) — the patterns `is` mirrors - [Sum widening](https://rux-lang.dev/docs/learn/sum-widening) — the next lesson - [Type tests](https://rux-lang.dev/docs/lang/sums/type-tests) in the Rux Reference # Sum widening ::note **You'll need**: [Subset pattern](https://rux-lang.dev/docs/learn/subset-pattern), [The is operator](https://rux-lang.dev/docs/learn/is) :: A smaller sum fits wherever a larger one is expected. A value of `Square | Rectangle` is always one of those two, and both are members of `Circle | Square | Rectangle` — so the compiler accepts it there without a word. This is *widening*: the set of possible members grows, while the value itself, and which member is active, stays exactly as it was. You have already seen widening once, in [Error sum](https://rux-lang.dev/docs/learn/error-sum), where a `DigitError` fitted into a function that fails with `DigitError | RangeError`. This lesson shows the same step with a whole sum on the narrow side. ## An honest return type `Box` builds a square when the sides are equal and a rectangle otherwise. It can never produce a circle, so its return type says exactly that: ```rux func Box(width: float64, height: float64) -> Square | Rectangle { if width == height { return Square { side: width }; } return Rectangle { width: width, height: height }; } ``` Each `return` puts a single struct into the two-member sum — the step you met in [Sum type](https://rux-lang.dev/docs/learn/sum-type), a value going into a sum that has its type as a member. Returning `Shape` would also compile, but it would throw information away: every caller would then have to be ready for a circle that never comes. ## One value, two functions `Area` works only on boxes, and `Describe` on any shape: ```rux func Area(box: Square | Rectangle) -> float64 { return match box { s: Square => s.side * s.side, r: Rectangle => r.width * r.height }; } ``` The same two values serve both — as they are for `Area`, widened for `Describe`: ```rux let tile = Box(2.0, 2.0); let door = Box(1.0, 2.5); PrintLine("areas {} and {}", Area(tile), Area(door)); Describe(tile); Describe(door); ``` `Describe(tile)` passes a `Square | Rectangle` to a `Shape` parameter. Nothing about the value changes: `tile` was a square, and inside `Describe` it is still a square, matched by the `s: Square` arm. ## Where widening happens Widening happens in the same places a value is handed on — on assignment, on a call, and on `return`: ```rux let anything: Shape = tile; Describe(anything); Describe(Circle { radius: 0.5 }); ``` `anything` holds the square from `tile`, now with room for a circle too. The last line is the single-member step again: a `Circle` going straight into `Shape`. | From | To | Accepted? | | -------------------- | -------------------- | ------------------------- | | `Circle` | `Shape` | yes — a member goes in | | `Square | Rectangle` | `Shape` | yes — widening | | `Shape` | `Square | Rectangle` | no — it might be a circle | ## Only one way ```mermaid flowchart LR sq["`Square`"] -- "member goes in" --> box["`Square | Rectangle`"] box -- "widening" --> shape["`Circle | Square | Rectangle`"] shape -. "refused — it might be a circle;
use a subset pattern" .-> box ``` A `Shape` might be a circle, and `Square | Rectangle` has no room for one, so the compiler refuses to narrow it — even when you know, this time, that it holds a square. Getting the smaller sum back out of the larger one takes a [subset pattern](https://rux-lang.dev/docs/learn/subset-pattern): `box: Square | Rectangle =>` is exactly the arm that proves the circle is not there. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/SumTypes/SumWidening){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // A smaller sum fits wherever a larger one is expected. A value of `Square | Rectangle` is // always one of those two, and both are members of `Circle | Square | Rectangle`, so the // compiler accepts it there without a word. This is *widening*: the set of possible members // grows, while the value itself, and which member is active, stays exactly as it was. // // It is the same step a single member takes when it goes into a sum, `let s: Shape = tile;`, // just with more than one member at a time. It happens on assignment, on a call and on `return`. // // It only goes one way. A `Shape` might be a circle, which `Square | Rectangle` has no room for, // so passing a `Shape` to `Area` below is refused: // error: argument 1 to 'Area' has type 'Circle | Rectangle | Square', but parameter 'box' // requires 'Rectangle | Square' // Getting the smaller sum back out of the larger one takes a subset pattern. import Io::PrintLine; struct Circle { radius: float64; } struct Square { side: float64; } struct Rectangle { width: float64; height: float64; } type Shape = Circle | Square | Rectangle; // Equal sides make a square, anything else a rectangle, so the honest result type is the // two-member sum, not the whole `Shape`. func Box(width: float64, height: float64) -> Square | Rectangle { if width == height { return Square { side: width }; } return Rectangle { width: width, height: height }; } func Area(box: Square | Rectangle) -> float64 { return match box { s: Square => s.side * s.side, r: Rectangle => r.width * r.height }; } func Describe(shape: Shape) { match shape { c: Circle => PrintLine("circle radius {}", c.radius), s: Square => PrintLine("square side {}", s.side), r: Rectangle => PrintLine("rectangle {} by {}", r.width, r.height) } } func Main() -> int { let tile = Box(2.0, 2.0); let door = Box(1.0, 2.5); // The same two values serve both functions: as they are for `Area`, widened for `Describe`. PrintLine("areas {} and {}", Area(tile), Area(door)); Describe(tile); Describe(door); // Widening on assignment: the square stays a square inside the larger sum. let anything: Shape = tile; Describe(anything); Describe(Circle { radius: 0.5 }); return 0; } ``` ## Run it ```sh cd Examples/SumTypes/SumWidening rux run ``` ```text areas 4.0 and 2.5 square side 2.0 rectangle 1.0 by 2.5 square side 2.0 circle radius 0.5 ``` ## Common mistakes ::mistake **Passing the larger sum where the smaller one is expected.**:br`Area(anything)` with `anything: Shape` fails with: ```text error: argument 1 to 'Area' has type 'Circle | Rectangle | Square', but parameter 'box' requires 'Rectangle | Square' ``` Match `anything` with a `box: Square | Rectangle` arm and pass `box` instead. :: ::mistake **Narrowing on assignment.**:br`let b: Square | Rectangle = anything;` fails the same way: ```text error: cannot assign 'Circle | Rectangle | Square' to 'Rectangle | Square' ``` Knowing that `anything` holds a square right now is not enough — the type says it might not. :: ::mistake **Returning a wider type than the function produces.**:br Not an error, but a cost: had `Box` returned `Shape`, `Area(tile)` would be refused, because `tile` would then be a `Shape`. Give a function the narrowest return type that is true, and let widening do the rest at the call site. :: ## Try it yourself 1. Change `Box`'s return type to `Shape` and run the program. Which line is now rejected, and why? 2. After `let anything: Shape = tile;`, print the area of `anything` using a `match` with a subset arm and a `Circle` arm. 3. Write `func Wheel(radius: float64) -> Circle` and pass its result to `Describe`. Is that widening, or a member going into a sum? ## Learn more - [Subset pattern](https://rux-lang.dev/docs/learn/subset-pattern) — the way back from a larger sum to a smaller one - [Error sum](https://rux-lang.dev/docs/learn/error-sum) — widening in a function's error channel - [Generic sum](https://rux-lang.dev/docs/learn/generic-sum) — sums built from type parameters, in the Generics part # Part 11: Ownership Every value in a Rux program has exactly one owner — a variable, a parameter, a field — and the owner decides when the value's life ends. Most of the time you never think about it: numbers and small structs are copied freely, and nothing needs cleaning up. This part is about the values where it matters — a hotel key that must be handed back once, a valve that must be closed on every path, a sheet whose copies must each be shredded — and about the rules the compiler checks so that cleanup happens exactly once, never twice and never not at all. ## What you will learn - Why a `&var` borrow is exclusive, and why a borrow ends at its last use. - What a copy is, and where one happens: binding, passing, returning and assigning. - Handing a value on with `<-` in a binding, an argument and a return, and what happens to the old name. - Writing a destructor, `func ~T(self: &var T)`, and when the compiler runs it — newest value first. - Prohibiting copies with a bodyless `func =`, or writing your own copy with a body. - Why one field cannot be moved out of a struct, and how a moving pattern takes it apart instead. - Registering cleanup with `defer`, its reverse order, and how it meets `return`. - Declaring a `var` without a value, and the compiler's check that every path assigns it. ## The life of a value ```mermaid flowchart LR b(["Begins
`let`, `var`, a constructor
11.10"]) --> h{"Handed on?"} h -- "`=` copy
11.2, 11.6" --> two["two values,
each with its own end"] h -- "`<-` move
11.3, 11.5, 11.7" --> one["one value,
a new owner"] h -- "`&` or `&var` borrow
11.1" --> same["one value,
the same owner"] two --> e(["Ends
scope, replacement, return
`~T` runs: 11.4"]) one --> e same --> e w["`defer`: cleanup for a piece
of work, 11.8, 11.9"] -.-> e ``` | A type that… | Write in `extend T` | Lesson | | ------------------------------- | --------------------------------------- | ------------------------------------------------------------- | | needs nothing special | nothing — copies field by field | [Copy](https://rux-lang.dev/docs/learn/copy) | | must clean up when a value ends | `func ~T(self: &var T) { … }` | [Destructor](https://rux-lang.dev/docs/learn/destructor) | | must never exist twice | `func =(self: &var T, other: &T);` | [Non-copyable types](https://rux-lang.dev/docs/learn/no-copy) | | needs real work to duplicate | `func =(self: &var T, other: &T) { … }` | [Custom copy](https://rux-lang.dev/docs/learn/custom-copy) | ## Lessons | | Lesson | What you will learn | | ----- | ---------------------------------------------------------------- | --------------------------------------------------------------------------- | | 11.1 | [Exclusivity](https://rux-lang.dev/docs/learn/exclusivity) | one writer at a time: the rule that keeps borrows safe | | 11.2 | [Copy](https://rux-lang.dev/docs/learn/copy) | assignment copies a value, and the copies are independent | | 11.3 | [Move](https://rux-lang.dev/docs/learn/move) | hand a value over with `<-` instead of copying it | | 11.4 | [Destructor](https://rux-lang.dev/docs/learn/destructor) | run cleanup when a value goes out of scope with `~T` | | 11.5 | [Non-copyable types](https://rux-lang.dev/docs/learn/no-copy) | forbid copying a type that owns a resource | | 11.6 | [Custom copy](https://rux-lang.dev/docs/learn/custom-copy) | write your own copy for a type that needs real work to duplicate | | 11.7 | [Partial move](https://rux-lang.dev/docs/learn/partial-move) | move one field out of a struct, and what is cleaned up after | | 11.8 | [Defer](https://rux-lang.dev/docs/learn/defer) | schedule cleanup at the point you start the work, so it cannot be forgotten | | 11.9 | [Defer return](https://rux-lang.dev/docs/learn/defer-return) | what a deferred action sees when the function returns a value | | 11.10 | [Initialization](https://rux-lang.dev/docs/learn/initialization) | a variable must be assigned before it is read | ## Before you start Finish Parts 1–10 first. This part leans most on [Part 6: Types](https://rux-lang.dev/docs/learn/types) — [Reference](https://rux-lang.dev/docs/learn/reference), [Mutable reference](https://rux-lang.dev/docs/learn/mutable-reference), [Method](https://rux-lang.dev/docs/learn/method) and [Constructor](https://rux-lang.dev/docs/learn/constructor) — and on [Destructure](https://rux-lang.dev/docs/learn/destructure) and [Struct pattern](https://rux-lang.dev/docs/learn/struct-pattern), which [Partial move](https://rux-lang.dev/docs/learn/partial-move) turns into a way of taking values apart. Each lesson's package is in the Examples repository's `Ownership/` folder: ```sh cd Examples/Ownership/Exclusivity rux run ``` ## After this part [Part 12: Interfaces](https://rux-lang.dev/docs/learn/interfaces) describes behaviour that many types share — and lets a type declare its own `==` and other operators the way this part declared its own `=`. Ownership comes back in [Part 15: Memory](https://rux-lang.dev/docs/learn/memory), where a [Box](https://rux-lang.dev/docs/learn/box) owns a block of memory and gives it back in its destructor, exactly as the keys and sheets here gave back their rooms and paper. The next checkpoint projects, [Circle](https://rux-lang.dev/docs/learn/circle) and [Quadratic](https://rux-lang.dev/docs/learn/quadratic), come after Part 16. For related rules, see [Mutability of structs](https://rux-lang.dev/docs/lang/bindings/overview#mutability), [`var`](https://rux-lang.dev/docs/lang/bindings/overview#var) and [Methods](https://rux-lang.dev/docs/lang/structs/methods) in the Rux Reference. # Exclusivity ::note **You'll need**: [Mutable reference](https://rux-lang.dev/docs/learn/mutable-reference), [Reference](https://rux-lang.dev/docs/learn/reference) :: This part is about *ownership*: which name a value belongs to, who may change it, and when it is cleaned up. It starts with a rule you have already bumped into. A `&var` borrow is **exclusive** — while it is alive, it is the only way to reach the value. No second `&var` borrow, and no reading the value by its own name either. Read-only `&` borrows have no such limit, because any number of readers can look at a value without harming it. "While it is alive" is shorter than it looks. A borrow ends at its **last use**, not at the end of the block it was made in, so a borrow that has finished its work is no obstacle. ## Two accounts, two borrows `Merge` moves everything from one account into another. It takes both as `&var`, because it changes both: ```rux func Merge(into: &var Account, from: &var Account) { into.balance += from.balance; from.balance = 0; } ``` Called with two different accounts, the two borrows do not overlap, and all is well: ```rux var alice = Account { owner: "Alice", balance: 100 }; var bob = Account { owner: "Bob", balance: 20 }; Merge(alice, bob); ``` Alice ends with 120 and Bob with 0. ## Why the rule exists `Merge` is written for two *different* accounts. Follow what it would do if `into` and `from` were the same one, with a balance of 100: 1. `into.balance += from.balance` — the balance becomes 200. 2. `from.balance = 0` — but `from` is `into`, so the balance becomes 0. Merging an account with itself would wipe out the money. Nothing in `Merge` is wrong; it simply assumes its two parameters are two things. Exclusivity makes that assumption safe, by making the bad call impossible to write: ```rux Merge(alice, alice); ``` ```text error: call arguments create overlapping exclusive borrows of 'alice' note: an earlier argument borrows the same storage at 40:11 help: split the accesses into non-overlapping calls ``` ## Readers may share Read-only borrows may overlap freely. `Richer` takes two `&Account` and changes neither, so the same account twice is fine: ```rux func Richer(left: &Account, right: &Account) -> char8[..] { let owner = left.balance >= right.balance ? left.owner : right.owner; return owner; } ``` ```rux PrintLine("richer of Alice and Alice: {}", Richer(alice, alice)); ``` | While this is alive… | Another `&` borrow | Another `&var` borrow | Reading by name | Writing by name | | -------------------- | ------------------ | --------------------- | --------------- | --------------- | | a `&` borrow | yes | no | yes | no | | a `&var` borrow | no | no | no | no | ## A borrow ends at its last use A borrow does not have to be a parameter. Here `wallet` is a local `&var` borrow of `alice`: ```rux let wallet: &var Account = alice; wallet.balance -= 30; wallet.balance -= 20; PrintLine("after spending: Alice {}", alice.balance); ``` The second `wallet` line is its last use, and from there on `alice` is free again, so reading it by name on the next line is accepted. ```mermaid flowchart LR b["`let wallet: &var Account = alice`"] --> u1["`wallet.balance -= 30`"] u1 --> u2["`wallet.balance -= 20`
last use — the borrow ends"] u2 --> r["`alice.balance`
free again"] u1 -. "reading `alice` here
is refused" .-> x["`error: cannot read 'alice.balance'`
`while 'wallet' holds an exclusive borrow`"] ``` Move that `PrintLine` above the second `wallet` line and `wallet` is still alive when `alice` is read. The compiler refuses, and its help names both ways out: read through `wallet`, or wait until its last use. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Ownership/Exclusivity){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // A `&var` borrow is exclusive. While it is alive, it is the only way to reach the value: no // second `&var` borrow, and no reading the value by its own name either. Read-only `&` borrows // have no such limit, because any number of readers can look at a value without harming it. // // "While it is alive" is shorter than it looks. A borrow ends at its last use, not at the end of // the block it was made in, so a borrow that has finished its work is no obstacle. // // The rule exists for functions like `Merge` below. It takes two accounts and is written for two // different ones. Handed the same account twice, it would add the balance to itself and then wipe // it out. Exclusivity makes that call impossible to write. import Io::PrintLine; struct Account { owner: char8[..]; balance: int32; } // Moves everything from one account into another. func Merge(into: &var Account, from: &var Account) { into.balance += from.balance; from.balance = 0; } // Two read-only borrows of the same account are fine: neither can change it. func Richer(left: &Account, right: &Account) -> char8[..] { let owner = left.balance >= right.balance ? left.owner : right.owner; return owner; } func Main() -> int { var alice = Account { owner: "Alice", balance: 100 }; var bob = Account { owner: "Bob", balance: 20 }; // Two different accounts: two exclusive borrows that do not overlap. Merge(alice, bob); PrintLine("after merge: Alice {}, Bob {}", alice.balance, bob.balance); // The same account twice is refused: // // Merge(alice, alice); // // error: call arguments create overlapping exclusive borrows of 'alice' // note: an earlier argument borrows the same storage at 40:11 // help: split the accesses into non-overlapping calls // Shared borrows may overlap freely. PrintLine("richer of Alice and Alice: {}", Richer(alice, alice)); // A local `&var` borrow. Its last use is the second line below, and from there on `alice` // is free again, so reading it by name is accepted. let wallet: &var Account = alice; wallet.balance -= 30; wallet.balance -= 20; PrintLine("after spending: Alice {}", alice.balance); // Move that `PrintLine` above the second `wallet` line and `wallet` is still alive when // `alice` is read: // // error: cannot read 'alice.balance' while 'wallet' holds an exclusive borrow // note: exclusive borrow begins at 51:32 // help: read through 'wallet' or wait until its last use return 0; } ``` ## Run it ```sh cd Examples/Ownership/Exclusivity rux run ``` ```text after merge: Alice 120, Bob 0 richer of Alice and Alice: Alice after spending: Alice 70 ``` ## Common mistakes ::mistake **Passing one value to two `&var` parameters.**:br`Merge(alice, alice)` fails with: ```text error: call arguments create overlapping exclusive borrows of 'alice' ``` Each `&var` argument must be a different value. :: ::mistake **Reading a value while a `&var` borrow of it is still in use.**:br With a later `wallet` line still to come, reading `alice.balance` fails with: ```text error: cannot read 'alice.balance' while 'wallet' holds an exclusive borrow ``` Read through `wallet` instead, or move the read after `wallet`'s last use. :: ::mistake **Borrowing for writing while a reader is still in use.**:br`let view: &Account = alice;` followed by `let wallet: &var Account = alice;`, with `view` used again later, fails with: ```text error: cannot borrow exclusively 'alice' while it is immutably borrowed ``` A reader expects the value not to change under it, so a writer has to wait until the reader is done. :: ## Try it yourself 1. Add a third account, `carol`, and merge both others into her with two calls to `Merge`. 2. Move the `PrintLine` with `alice.balance` above the second `wallet` line and read the error. Then change it to print `wallet.balance` instead — is that accepted? 3. Make two local `&var` borrows of `alice`, one after the other, where the first is finished before the second begins. Does the compiler allow it? ## Learn more - [Mutable reference](https://rux-lang.dev/docs/learn/mutable-reference) and [Reference](https://rux-lang.dev/docs/learn/reference) — the two kinds of borrow - [Copy](https://rux-lang.dev/docs/learn/copy) — the next lesson: what happens when a value is not borrowed at all - [Mutability of structs](https://rux-lang.dev/docs/lang/bindings/overview#mutability) in the Rux Reference # Copy ::note **You'll need**: [Struct](https://rux-lang.dev/docs/learn/struct), [Array](https://rux-lang.dev/docs/learn/array), [Function](https://rux-lang.dev/docs/learn/function) :: Every time a value is used **by value** — bound to a new name, passed to a parameter that is not a reference, returned, or assigned over another value — what arrives is a *copy*. From that moment the two are separate: changing one never shows up in the other. That is the opposite of the [Reference](https://rux-lang.dev/docs/learn/reference) lessons, where a borrow shares one value instead of making a second. Most of the time a copy is exactly what you want, and you have been relying on it since Part 1 without a name for it. This lesson gives it the name, because the rest of the part is about values for which a plain copy is *not* right. ## Nothing to write A struct needs no extra code to be copyable. The compiler copies a struct by copying each field, and an array by copying each element, as long as every part can itself be copied: ```rux struct Point { x: int32; y: int32; } ``` `Point` is two `int32`s, and an `int32` copies, so a `Point` copies. ## Binding a new name `end` starts as a copy of `start`, then goes its own way: ```rux let start = Point { x: 1, y: 2 }; var end = start; end.y = 99; ``` `end` is now `(1, 99)`, and `start` is still `(1, 2)`. There are two points in memory, not one point with two names. ## Passing and returning A parameter that is not a reference receives its own copy. A parameter cannot be changed, so `Nudged` copies it once more into a `var`, changes that, and returns it: ```rux func Nudged(point: Point) -> Point { var result = point; result.x += 10; return result; } ``` ```rux let nudged = Nudged(start); ``` `nudged` is `(11, 2)`. The caller's `start` is never touched — the function only ever saw copies of it. ## Arrays copy too An array is a value, so assigning it copies the whole array, element by element: ```rux let scores = [3, 5, 8]; var adjusted = scores; adjusted[0] = 100; ``` `scores[0]` is still 3. If you come from a language where an array variable is a pointer to shared storage, this is the place to slow down: in Rux, `adjusted` is a second array. ## Assigning over a value Assigning to an existing variable copies again and replaces what was there: ```rux end = start; ``` `end` was `(1, 99)`; now it is a fresh copy of `start`, `(1, 2)`. ## Copy or borrow? ```mermaid flowchart LR subgraph copy["By value: `let end = start`"] s1["`start` `(1, 2)`"] e1["`end` `(1, 2)`
a second `Point`"] s1 -- "copied into" --> e1 end subgraph borrow["By reference: `let view: &Point = start`"] s2["`start` `(1, 2)`"] v2["`view`"] -- "refers to" --> s2 end ``` | Written | What arrives | A change through it reaches the original? | | --------------------------- | ------------------- | ----------------------------------------- | | `var end = start;` | a copy | no | | `func F(point: Point)` | a copy | no — and the parameter is read-only | | `func F(point: &Point)` | a borrow, to read | it cannot change anything | | `func F(point: &var Point)` | a borrow, to change | yes | A copy is cheap for small values like a `Point`, and it is always *safe*: nothing you do to a copy can surprise the code holding the original. The [next lesson](https://rux-lang.dev/docs/learn/move) covers the other way to hand a value on — moving it, so that only one remains. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Ownership/Copy){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // Every time a value is used by value — bound to a new name, passed to a parameter that is not a // reference, returned, or assigned over another value — what arrives is a copy. From that moment // the two are separate: changing one never shows up in the other. // // Nothing has to be written to make a struct copyable. The compiler copies a struct by copying // each field, and an array by copying each element, as long as every part can itself be copied. // The Reference lessons were the opposite case: a borrow shares one value instead of making a // second one. import Io::PrintLine; struct Point { x: int32; y: int32; } // `point` is this function's own copy. A parameter cannot be changed, so it is copied once more // into a `var`, which is changed and returned. The caller's point is never touched. func Nudged(point: Point) -> Point { var result = point; result.x += 10; return result; } func Main() -> int { // Binding: `end` starts as a copy of `start`, then goes its own way. let start = Point { x: 1, y: 2 }; var end = start; end.y = 99; PrintLine("start ({}, {}) end ({}, {})", start.x, start.y, end.x, end.y); // Passing and returning: the function worked on a copy. let nudged = Nudged(start); PrintLine("start ({}, {}) nudged ({}, {})", start.x, start.y, nudged.x, nudged.y); // An array is a value too, so the whole array is copied, element by element. let scores = [3, 5, 8]; var adjusted = scores; adjusted[0] = 100; PrintLine("scores[0] {} adjusted[0] {}", scores[0], adjusted[0]); // Assigning over an existing value copies again and replaces what was there. end = start; PrintLine("end ({}, {}) after end = start", end.x, end.y); return 0; } ``` ## Run it ```sh cd Examples/Ownership/Copy rux run ``` ```text start (1, 2) end (1, 99) start (1, 2) nudged (11, 2) scores[0] 3 adjusted[0] 100 end (1, 2) after end = start ``` ## Common mistakes ::mistake **Expecting a change to reach the original.**:br There is no error to warn you here, which is what makes it a mistake. `var end = start; end.y = 99;` changes `end` only. If the caller's value must change, the function needs a `&var` parameter, as in [Mutable reference](https://rux-lang.dev/docs/learn/mutable-reference). :: ::mistake **Changing a by-value parameter.**:br`func Nudged(point: Point) -> Point { point.x += 10; return point; }` fails with: ```text error: cannot modify parameter 'point' ``` The compiler's help names both fixes: take `point` as `&var Point` to change the caller's value, or move it into a `var` local — or, as `Nudged` does, copy it into one. :: ::mistake **Changing a `let` copy.**:br`let end = start; end.y = 99;` fails with: ```text error: cannot modify immutable variable 'end' ``` The copy is a new variable with its own mutability, and a `let` never changes. Declare it with `var`. :: ## Try it yourself 1. Write `func Nudge(point: &var Point)` that adds 10 to `x`, call it on a `var` point, and compare the result with `Nudged`. 2. Make an array of two `Point`s, copy it into a `var`, and change `x` of the copy's first point. Print the first point of both arrays. 3. Change the body of `Nudged` to `point.x += 10; return point;` and read the compiler's help. ## Learn more - [Move](https://rux-lang.dev/docs/learn/move) — handing a value on without copying it - [Reference](https://rux-lang.dev/docs/learn/reference) and [Mutable reference](https://rux-lang.dev/docs/learn/mutable-reference) — sharing one value instead of copying it - [Struct](https://rux-lang.dev/docs/learn/struct) and [Array](https://rux-lang.dev/docs/learn/array) — the values copied in this lesson # Move ::note **You'll need**: [Copy](https://rux-lang.dev/docs/learn/copy) :: A [copy](https://rux-lang.dev/docs/learn/copy) leaves two values behind. A *move* leaves one: the value is handed to its new owner, and the old name is finished. Rux writes a move as `<-`, the arrow pointing the way the value goes. A relay baton is the picture to keep in mind. One runner holds it at a time, and once it has been handed on, the runner who passed it no longer has it. The compiler enforces exactly that: any later use of a moved-from name is an error. For a `Baton` holding one number, the point of a move is not speed. It is what is left afterwards — and in the lessons after this one, that becomes the difference between a value cleaned up once and a value cleaned up twice. ## Three places to move A move works in the same three places a copy happens. Only the arrow changes: | Where | Copy | Move | | ----------- | -------------------- | --------------------- | | A binding | `let taken = value;` | `let taken <- value;` | | An argument | `Run(value)` | `Run(<-value)` | | A return | `return value;` | `return <-value;` | ## A binding ```rux let baton = Baton { laps: 0 }; let first <- baton; ``` `first` now holds the baton. `baton` still exists as a name in the source, but it no longer holds anything, and the compiler will not let you read it: ```text error: value 'baton' is used after it was moved note: 'baton' was moved at 31:15 help: clone 'baton' before moving it if both uses are required ``` ## An argument and a return `Run` takes the baton, runs one lap with it, and hands it back: ```rux func Run(baton: Baton, runner: char8[..]) -> Baton { var held <- baton; held.laps += 1; PrintLine("{} runs lap {}", runner, held.laps); return <-held; } ``` A parameter cannot be changed, so `var held <- baton` moves it into a mutable local: still one baton, just under a new name. `return <-held` hands it on to the caller. The caller passes the baton along the line of runners: ```rux let second = Run(<-first, "Ana"); let third = Run(<-second, "Ben"); let last = Run(<-third, "Cleo"); ``` Each `<-` gives up a name: after the first line, `first` is finished, after the second, `second`, and so on. One baton runs three laps, and `last.laps` is 3. ## Fresh values need no arrow What a call *returns* is a fresh value that nobody else holds, so `=` simply takes it — there is no old name to give up, and nothing to copy from. `let second = Run(…)` above is already a move in all but spelling. The same is true of any value made on the spot: ```rux let spare = Run(Baton { laps: 0 }, "Dev"); ``` The arrow is for a value that has a name. It is there so that a reader can see, at a glance, which names stop working on that line. ## Copy, move or borrow You now have three ways to hand a value to someone else: ```mermaid flowchart LR a(["`a`: a value
with a name"]) a -- "`let b = a`
copy" --> c["two values
`a` and `b` both usable,
each changes alone"] a -- "`let b <- a`
move" --> m["one value, now `b`'s
`a` is finished"] a -- "`let b: &T = a`
borrow" --> r["one value, still `a`'s
`b` refers to it"] ``` | | Copy `=` | Move `<-` | Borrow `&` / `&var` | | ----------------- | ------------------ | -------------- | -------------------- | | Values afterwards | two | one | one | | The old name | still usable | finished | still the owner | | The new name | owns its own value | owns the value | owns nothing; refers | ## Moves on some paths The compiler tracks moves through loops and branches. A move inside a loop is checked against the next pass too — the first pass would take the baton, and the second would find nothing left to take: ```rux for lap in 0..3 { let runner <- first; } ``` ```text error: value 'first' may have been moved on some control-flow paths ``` The same error appears when a move happens inside an `if` and the name is used after it: on the path where the `if` ran, the value is gone. A moved-from `var` is not ruined for good. Assigning it a new value with `=` gives it something to hold again, and from then on it can be read as before. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Ownership/Move){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // A copy leaves two values behind. A move leaves one: the value is handed to its new owner and // the old name is finished. Rux writes a move as `<-`, the arrow pointing the way the value goes, // and it works in the same three places a copy happens. // // let taken <- value; a binding // Run(<-value) an argument // return <-value; a return // // A relay baton is the picture to keep in mind. One runner holds it at a time, and once it has // been handed on, the runner who passed it no longer has it. The compiler enforces exactly that: // any later use of a moved-from name is an error. import Io::PrintLine; struct Baton { laps: int32; } // Takes the baton, runs one lap with it, and hands it back. A parameter cannot be changed, so // `var held <- baton` moves it into a mutable local: still one baton, just under a new name. func Run(baton: Baton, runner: char8[..]) -> Baton { var held <- baton; held.laps += 1; PrintLine("{} runs lap {}", runner, held.laps); return <-held; } func Main() -> int { let baton = Baton { laps: 0 }; // A binding takes the baton over. let first <- baton; // From here on, `baton` cannot be used: // // PrintLine("{}", baton.laps); // // error: value 'baton' is used after it was moved // note: 'baton' was moved at 31:15 // help: clone 'baton' before moving it if both uses are required // // A move inside a loop is checked against the next pass too. The first pass would take the // baton, and the second would find nothing left to take: // // for lap in 0..3 { // let runner <- first; // } // // error: value 'first' may have been moved on some control-flow paths // Arguments and returns. What a call returns is a fresh value that nobody else holds, so it // needs no arrow: `=` simply takes it. let second = Run(<-first, "Ana"); let third = Run(<-second, "Ben"); let last = Run(<-third, "Cleo"); PrintLine("laps run: {}", last.laps); // The same is true of any value made on the spot. There is no old name to give up. let spare = Run(Baton { laps: 0 }, "Dev"); PrintLine("spare laps: {}", spare.laps); return 0; } ``` ## Run it ```sh cd Examples/Ownership/Move rux run ``` ```text Ana runs lap 1 Ben runs lap 2 Cleo runs lap 3 laps run: 3 Dev runs lap 1 spare laps: 1 ``` ## Common mistakes ::mistake **Using a name after moving from it.**:br After `let first <- baton;`, `PrintLine("{}", baton.laps)` fails with: ```text error: value 'baton' is used after it was moved ``` The note points at the line of the move. If both names really need a value, copy with `=` instead of moving. :: ::mistake **Moving inside a loop.**:br`let runner <- first;` in a loop body fails with: ```text error: value 'first' may have been moved on some control-flow paths ``` The second pass would have nothing to take. Move before the loop, or give each pass a value of its own. :: ::mistake **Moving inside a branch, then using the name.**:br`if ready { let first <- baton; }` followed by `baton.laps` fails the same way: ```text error: value 'baton' may have been moved on some control-flow paths ``` The compiler does not know whether the `if` ran, so it assumes the worst. :: ## Try it yourself 1. Add a fourth runner, Dana, to the relay, and print the laps run. 2. Uncomment the `PrintLine` after `let first <- baton;` and read the error and its note. 3. Change `Run(<-first, "Ana")` to `Run(first, "Ana")`. The program still compiles — why? Print `first.laps` at the end: which baton does `first` still hold? 4. Declare `var baton`, move it into `first`, then assign it a new `Baton { laps: 7 }` and print both. ## Learn more - [Copy](https://rux-lang.dev/docs/learn/copy) — the other way a value is handed on - [Destructor](https://rux-lang.dev/docs/learn/destructor) — the next lesson, where a move decides who cleans up - [Non-copyable types](https://rux-lang.dev/docs/learn/no-copy) — values that can only be moved # Destructor ::note **You'll need**: [Move](https://rux-lang.dev/docs/learn/move), [Method](https://rux-lang.dev/docs/learn/method) :: A *destructor* is code that runs when a value's life ends. Nobody calls it. The compiler does, exactly once for every value that is still alive when its life ends — when its scope closes, when a function returns, or when `=` replaces it with a new value. In real code a destructor gives back what the value was holding: a file, a network connection, a block of memory. Because the compiler calls it, it cannot be forgotten, and it cannot be called twice. Here the destructor only prints, so that you can watch exactly when it runs. ## Writing a destructor A destructor is written inside `extend`, named after the type with a leading `~`, and borrows the dying value mutably: ```rux struct Guest { name: char8[..]; } extend Guest { func ~Guest(self: &var Guest) { PrintLine(" {} leaves", self.name); } } ``` It takes no other parameters and returns nothing. The signature is fixed: `func ~T(self: &var T)`, with the type's own name. ## When a scope ends The guest in `Visit` lives only as long as the call: ```rux func Visit(name: char8[..]) { let guest = Guest { name: name }; PrintLine(" {} visits", guest.name); } ``` ```text a short visit: Ada visits Ada leaves back in Main ``` "Ada leaves" is printed by the destructor as `Visit` returns, before `Main` carries on. The same happens at the end of every block that owns a value — including each pass of a loop body. ## When a value is replaced Replacing a value ends the old one's life first: ```rux var seat = Guest { name: "Bob" }; seat = Guest { name: "Cy" }; ``` Bob leaves at the `=`. Cy now holds the seat and will leave later. Replacing one field of a struct works the same way: the old field value is destroyed, the rest of the struct is untouched. ## When a value is moved After a [move](https://rux-lang.dev/docs/learn/move), only the new owner is destroyed: ```rux let host = Guest { name: "Dee" }; let moved <- host; ``` `host` gave its value away, so there is nothing left in `host` to destroy. Dee leaves once, at the end of `Main`, as `moved`. ## Newest first Values that end together are destroyed in reverse order of creation — newest first. At the end of `Main`, `seat` (holding Cy) was created before `moved` (holding Dee), so Dee leaves first: ```mermaid flowchart LR subgraph made["Created, in order"] direction LR c1["`seat` — Cy"] --> c2["`moved` — Dee"] end subgraph gone["Destroyed at the end of `Main`"] direction LR d1["Dee leaves"] --> d2["Cy leaves"] end made -- "reversed" --> gone ``` The order is not arbitrary. A value made later may depend on one made earlier — a reader that uses an open file, say — so it has to go first, while the thing it depends on is still there. | What happens | Destructor runs | | ---------------------------- | ------------------------------------------------ | | The owning scope ends | yes, newest value first | | `=` replaces the value | yes, on the old value, at the assignment | | The value is moved with `<-` | not here — the new owner destroys it later | | The value is copied | the copy is a second value, destroyed on its own | ## Why this program never copies a guest A [copy](https://rux-lang.dev/docs/learn/copy) of a guest would be a second guest, and it would leave too. With `let twin = host;`, the program would print "Dee leaves" twice for one person. For a guest that only prints, that is odd; for a value that frees memory or closes a file, it would free or close the same thing twice. The [next lesson](https://rux-lang.dev/docs/learn/no-copy) shows how a type turns copying off. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Ownership/Destructor){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // A destructor is code that runs when a value's life ends. It is written inside `extend`, named // after the type with a leading `~`, and borrows the dying value mutably: // // func ~Guest(self: &var Guest) { ... } // // Nobody calls it. The compiler does, exactly once for every value that is still alive when its // life ends: when its scope closes, when a function returns, or when `=` replaces it with a new // value, whether it is a whole variable or one field of a struct. A value that was moved away is // not destroyed where it was, because its new owner will destroy it later. Values that end // together are destroyed in reverse order of creation, newest first. // // Here the destructor only prints, so its timing can be watched. In real code it gives back what // the value was holding: a file, a connection, a block of memory. Notice that this program never // copies a guest: a copy would be a second guest that leaves too. The NoCopy lesson deals with it. import Io::PrintLine; struct Guest { name: char8[..]; } extend Guest { func ~Guest(self: &var Guest) { PrintLine(" {} leaves", self.name); } } // The guest lives only as long as this call. func Visit(name: char8[..]) { let guest = Guest { name: name }; PrintLine(" {} visits", guest.name); } func Main() -> int { PrintLine("a short visit:"); Visit("Ada"); PrintLine(" back in Main"); // Replacing a value ends the old one's life first. PrintLine("swapping the seat:"); var seat = Guest { name: "Bob" }; seat = Guest { name: "Cy" }; // After a move only the new owner is destroyed, so Dee leaves once, at the end. PrintLine("moving:"); let host = Guest { name: "Dee" }; let moved <- host; // `moved` was created after `seat`, so it is destroyed before it. PrintLine("end of Main:"); return 0; } ``` ## Run it ```sh cd Examples/Ownership/Destructor rux run ``` ```text a short visit: Ada visits Ada leaves back in Main swapping the seat: Bob leaves moving: end of Main: Dee leaves Cy leaves ``` ## Common mistakes ::mistake **The wrong signature.**:br`func ~Guest(self: &Guest)` fails with: ```text error: destructor for type 'Guest' must have signature 'func ~Guest(self: &var Guest)' ``` The value is dying, and the destructor may need to change it on the way out — closing a handle, clearing a pointer — so it borrows it mutably. :: ::mistake **The wrong name.**:br`func ~Visitor(self: &var Guest)` inside `extend Guest` fails with: ```text error: destructor '~Visitor' must be named '~Guest' for type 'Guest' ``` :: ::mistake **Calling a destructor yourself.**:br`seat.~Guest();` does not even parse: ```text error: expected a field name or tuple index after '.' before '~' ``` Destruction is the compiler's job. To end a value early, replace it with `=` or move it into a function that lets it go. :: ::mistake **Copying a value that has a destructor.**:br`let twin = host;` compiles, and both `twin` and `host` are destroyed — the destructor runs twice for what you meant as one guest. For a type that holds a resource, prohibit copying, as in [Non-copyable types](https://rux-lang.dev/docs/learn/no-copy). :: ## Try it yourself 1. Create a guest inside a `for` loop over `0..3` and print the pass number. When does each guest leave? 2. Add `let twin = host;` before the move and count how many times Dee leaves. 3. Declare `struct Table { number: int32; guest: Guest; }`, make a `var` table, and assign a new guest to its `guest` field. Who leaves, and when? ## Learn more - [Move](https://rux-lang.dev/docs/learn/move) — why a moved-from value is not destroyed - [Non-copyable types](https://rux-lang.dev/docs/learn/no-copy) — one value, one destructor call - [Defer](https://rux-lang.dev/docs/learn/defer) — cleanup that belongs to a piece of work rather than a value - [Methods](https://rux-lang.dev/docs/lang/structs/methods) in the Rux Reference # Non-copyable types ::note **You'll need**: [Destructor](https://rux-lang.dev/docs/learn/destructor), [Move](https://rux-lang.dev/docs/learn/move) :: A hotel key stands for a room. If keys could be copied, two of them would each be handed back at checkout — the [destructor](https://rux-lang.dev/docs/learn/destructor) would run twice for one room. For a type like this, the compiler's automatic [copy](https://rux-lang.dev/docs/learn/copy) is wrong, and Rux lets the type turn it off. Once copying is off, the only way to hand a key on is to [move](https://rux-lang.dev/docs/learn/move) it. One key, one owner, one destructor call — and the compiler checks all three. ## Turning copying off The copy operator is `=`. Declaring it inside `extend` **with no body** says "this type has no copy": ```rux struct RoomKey { room: int32; } extend RoomKey { // No body: copying is prohibited. func =(self: &var RoomKey, other: &RoomKey); func ~RoomKey(self: &var RoomKey) { PrintLine(" key {} handed back", self.room); } } ``` The signature is the one a real copy would have — `self` is the new value to fill in, `other` the value being copied — but with a `;` where the body would be. The [Custom copy](https://rux-lang.dev/docs/learn/custom-copy) lesson gives it a body. ## Moving instead From then on every use that would copy a key is an error, and the diagnostic shows the move to write instead: ```rux let spare = key; ``` ```text error: move-only value 'key' requires an explicit '<-' in initialization note: plain by-value use copies its source, but 'RoomKey' prohibits copying help: write 'let destination <- key' to transfer ownership ``` With the arrow, the key changes hands and `key` is finished: ```rux let friend <- key; PrintLine(" friend holds key {}", friend.room); ``` Passing by value is a copy too, so an argument needs the arrow as well. `CheckOut` takes ownership of the key, so the key's life ends when the function returns: ```rux func CheckOut(key: RoomKey) { PrintLine(" checking out of room {}", key.room); } ``` ```rux CheckOut(<-friend); PrintLine(" done"); ``` That is why the output shows "key 12 handed back" between "checking out of room 12" and "done": the destructor runs as `CheckOut` returns, not at the end of `Main`. ## Fresh keys and borrowed keys Two things still work without an arrow. A value made on the spot has no old owner, so `CheckIn` returns its new key with a plain `return`: ```rux func CheckIn(room: int32) -> RoomKey { PrintLine(" key {} issued", room); return RoomKey { room: room }; } ``` And a borrow is not a copy. A function that only needs to look at a key takes `&RoomKey`, and the caller keeps the key. ```mermaid flowchart LR k(["`key: RoomKey`
no copy"]) -- "`let spare = key`" --> x["`error: requires`
`an explicit '<-'`"] k -- "`let friend <- key`" --> f["`friend` owns the key
`key` is finished"] k -- "`Peek(key)` with `key: &RoomKey`" --> b["borrowed for the call
`key` still owns it"] ``` ## Everywhere a copy would happen Every by-value use of a named key needs the arrow. The compiler names the place in each error: | Where | Refused | Written with a move | | -------------- | ---------------------- | ------------------------ | | A binding | `let spare = key;` | `let spare <- key;` | | An argument | `CheckOut(key)` | `CheckOut(<-key)` | | A return | `return key;` | `return <-key;` | | A struct field | `Booking { key: key }` | `Booking { key: <-key }` | | An assignment | `key = other;` | `key <- other;` | The prohibition also spreads outwards. A struct with a `RoomKey` field cannot be copied either — copying it would copy the key — so the compiler treats the whole struct as move-only. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Ownership/NoCopy){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // A hotel key stands for a room. If keys could be copied, two of them would each be handed back // at checkout: the destructor would run twice for one room. For a type like this the compiler's // automatic copy is wrong, and Rux lets the type turn it off. // // The copy operator is `=`. Declaring it with no body says "this type has no copy": // // func =(self: &var RoomKey, other: &RoomKey); // // From then on every use that would copy a key is an error, and the only way to hand one on is // to move it with `<-`. One key, one owner, one destructor call. import Io::PrintLine; struct RoomKey { room: int32; } extend RoomKey { // No body: copying is prohibited. func =(self: &var RoomKey, other: &RoomKey); func ~RoomKey(self: &var RoomKey) { PrintLine(" key {} handed back", self.room); } } func CheckIn(room: int32) -> RoomKey { PrintLine(" key {} issued", room); return RoomKey { room: room }; } // Takes ownership of the key, so the key's life ends when this function returns. func CheckOut(key: RoomKey) { PrintLine(" checking out of room {}", key.room); } func Main() -> int { PrintLine("check in:"); let key = CheckIn(12); // A copy is refused, and the diagnostic shows the move to write instead: // // let spare = key; // // error: move-only value 'key' requires an explicit '<-' in initialization // note: plain by-value use copies its source, but 'RoomKey' prohibits copying // help: write 'let destination <- key' to transfer ownership PrintLine("give the key to a friend:"); let friend <- key; PrintLine(" friend holds key {}", friend.room); // Passing by value is a copy too, so the argument needs the arrow as well. Without it: // error: move-only value 'friend' requires an explicit '<-' in argument PrintLine("check out:"); CheckOut(<-friend); PrintLine(" done"); return 0; } ``` ## Run it ```sh cd Examples/Ownership/NoCopy rux run ``` ```text check in: key 12 issued give the key to a friend: friend holds key 12 check out: checking out of room 12 key 12 handed back done ``` ## Common mistakes ::mistake **Binding or passing a key without the arrow.**:br`let spare = key;` and `CheckOut(friend)` fail with: ```text error: move-only value 'key' requires an explicit '<-' in initialization error: move-only value 'friend' requires an explicit '<-' in argument ``` Both notes say the same thing: plain by-value use copies its source, and this type prohibits copying. :: ::mistake **Returning a named key with a plain `return`.**:br A function that builds a key in a local and ends with `return key;` fails with: ```text error: move-only value 'key' requires an explicit '<-' in return ``` Write `return <-key;`. Only a value made on the spot, like `return RoomKey { room: room };`, needs no arrow. :: ::mistake **Replacing a key with `=`.**:br With two `var` keys, `key = other;` fails with: ```text error: copying type 'RoomKey' is prohibited ``` Assignment copies too. Write `key <- other;`, which hands back the old key first and then moves `other` in. :: ## Try it yourself 1. Write `func Peek(key: &RoomKey)` that prints the room number, and call it twice on `key` before giving it to the friend. Why does `Peek` need no arrow? 2. Write `func Spare(room: int32) -> RoomKey` that stores a new key in a `let` before returning it. Which `return` does it need? 3. Make two `var` keys and replace the first with `key <- other;`. When is each key handed back? 4. Declare `struct Booking { guest: char8[..]; key: RoomKey; }`, build one, and try to copy it with `=`. What does the error say about `Booking`? ## Learn more - [Move](https://rux-lang.dev/docs/learn/move) — the arrow in all three places - [Custom copy](https://rux-lang.dev/docs/learn/custom-copy) — giving `=` a body instead - [Partial move](https://rux-lang.dev/docs/learn/partial-move) — taking a struct of move-only fields apart # Custom copy ::note **You'll need**: [Non-copyable types](https://rux-lang.dev/docs/learn/no-copy), [Destructor](https://rux-lang.dev/docs/learn/destructor) :: Between "the compiler copies each field" and "no copies at all" there is a third choice: write the copy yourself. Give `=` a body, and every copy of the type runs it. In real code the body does what a field-by-field copy cannot — typically duplicating something the value owns, so the copy gets its own instead of sharing. A buffer that owns a block of memory, for example, would allocate a fresh block and copy the bytes into it. Here each copy of a sheet of paper is a *photocopy*, and remembers how many generations it is from the original. ## Three ways to copy | In `extend T` | What a copy does | Lesson | | --------------------------------------- | ----------------------------- | ------------------------------------------------------------- | | nothing | copies each field | [Copy](https://rux-lang.dev/docs/learn/copy) | | `func =(self: &var T, other: &T);` | nothing — copying is an error | [Non-copyable types](https://rux-lang.dev/docs/learn/no-copy) | | `func =(self: &var T, other: &T) { … }` | runs your body | this lesson | ## Writing the copy ```rux struct Sheet { text: char8[..]; generation: int32; } extend Sheet { func =(self: &var Sheet, other: &Sheet) { self.text = other.text; self.generation = other.generation + 1; PrintLine(" photocopy: generation {} -> {}", other.generation, self.generation); } func ~Sheet(self: &var Sheet) { PrintLine(" shredding generation {}", self.generation); } } ``` `other` is the value being copied, borrowed read-only so the copy cannot change or consume it. `self` is the new value to fill in. Once you write the body, the field-by-field copy is gone: every field you want in the copy, you set yourself. Leave out `self.text = other.text;` and every photocopy comes out with empty text. The destructor is there to show that every copy is a value of its own, with its own end. ## Every copy runs it A binding copies: ```rux let original = Sheet { text: "Minutes", generation: 1 }; let copy = original; ``` `copy` is generation 2. `original` is untouched, still generation 1. Passing by value copies too. `Show` takes its sheet by value, so the caller's sheet is photocopied into the parameter, and the photocopy is shredded when `Show` returns: ```rux func Show(sheet: Sheet) { PrintLine(" showing '{}', generation {}", sheet.text, sheet.generation); } ``` ```text passing by value: photocopy: generation 2 -> 3 showing 'Minutes', generation 3 shredding generation 3 ``` ## Assigning over a live value Assignment over a value that already exists does two things, in a fixed order — it makes the new copy first, then ends the old value's life: ```rux var board = Sheet { text: "Agenda", generation: 1 }; board = copy; ``` ```mermaid flowchart LR c["`copy`
generation 2"] -- "first, `=` runs:
a photocopy" --> n["new sheet
generation 3"] b["`board`
generation 1"] -- "then the old value ends" --> s["shredding
generation 1"] n -- "finally the new one
is installed" --> b2["`board`
generation 3"] ``` The output shows the order: the photocopy line comes before the shredding line. ## Only a copy runs `=` `=` runs when an existing value is copied — one that keeps its value afterwards. A sheet made on the spot is not a copy of anything, so it moves straight in with no photocopy. That is why `var board = Sheet { … };` prints nothing, and why `board = Sheet { … };` would print only the shredding of the old sheet. A value handed over with `<-` is not copied either. | Written | Runs `=`? | | -------------------------- | --------------------- | | `let copy = original;` | yes | | `Show(copy)` | yes | | `board = copy;` | yes | | `var board = Sheet { … };` | no — made on the spot | | `Show(<-copy)` | no — moved | At the end of `Main`, three sheets are still alive — `original`, `copy` and `board` — and each is shredded once, newest first: generation 3, then 2, then 1. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Ownership/CustomCopy){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // Between "the compiler copies each field" and "no copies at all" there is a third choice: write // the copy yourself. Give `=` a body and every copy of the type runs it. `other` is the value // being copied, borrowed read-only so the copy cannot change or consume it, and `self` is the // new value to fill in. // // In real code the body does what a field-by-field copy cannot, typically duplicating something // the value owns so the copy gets its own instead of sharing. Here each copy of a sheet is a // photocopy and remembers how many generations it is from the original. The destructor shows // that every copy is a value of its own, with its own end. import Io::PrintLine; struct Sheet { text: char8[..]; generation: int32; } extend Sheet { func =(self: &var Sheet, other: &Sheet) { self.text = other.text; self.generation = other.generation + 1; PrintLine(" photocopy: generation {} -> {}", other.generation, self.generation); } func ~Sheet(self: &var Sheet) { PrintLine(" shredding generation {}", self.generation); } } // Taken by value, so the caller's sheet is copied into `sheet` by the custom copy. func Show(sheet: Sheet) { PrintLine(" showing '{}', generation {}", sheet.text, sheet.generation); } func Main() -> int { PrintLine("binding:"); let original = Sheet { text: "Minutes", generation: 1 }; let copy = original; PrintLine(" original {}, copy {}", original.generation, copy.generation); PrintLine("passing by value:"); Show(copy); // Assigning over a live value makes the new copy first, then ends the old value's life. // Only a copy of an existing value runs `=`. A sheet made on the spot is not a copy of // anything, so it moves straight in with no photocopy, here and in `board = Sheet { ... };`. PrintLine("assigning:"); var board = Sheet { text: "Agenda", generation: 1 }; board = copy; PrintLine(" board now holds '{}', generation {}", board.text, board.generation); PrintLine("end of Main:"); return 0; } ``` ## Run it ```sh cd Examples/Ownership/CustomCopy rux run ``` ```text binding: photocopy: generation 1 -> 2 original 1, copy 2 passing by value: photocopy: generation 2 -> 3 showing 'Minutes', generation 3 shredding generation 3 assigning: photocopy: generation 2 -> 3 shredding generation 1 board now holds 'Minutes', generation 3 end of Main: shredding generation 3 shredding generation 2 shredding generation 1 ``` ## Common mistakes ::mistake **Taking `other` by value.**:br`func =(self: &var Sheet, other: Sheet)` fails with: ```text error: copy special operation for type 'Sheet' must have signature 'func =(self: &var Sheet, other: &Source)' ``` Taking `other` by value would itself need a copy — the very operation being defined. :: ::mistake **Changing the original while copying it.**:br`other.generation = 0;` inside the body fails with: ```text error: cannot modify data through immutable reference '&Sheet' ``` A copy must leave its source exactly as it was. :: ::mistake **Expecting `=` to run for every assignment.**:br`board = Sheet { text: "Notes", generation: 5 };` runs no photocopy: the new sheet is made on the spot and moves straight in. Only the old board is shredded. If your body counts or logs copies, values built in place will not show up in the count. :: ## Try it yourself 1. Add `let third = copy;` after the binding. Predict every photocopy and shredding line before you run it. 2. Change `Show(copy)` to `Show(<-copy)`. The photocopy line disappears — and a later line no longer compiles. Which one, and why? 3. Remove `self.text = other.text;` from the body and run the program. What does each photocopy say it is showing? ## Learn more - [Copy](https://rux-lang.dev/docs/learn/copy) — the copy the compiler writes for you - [Non-copyable types](https://rux-lang.dev/docs/learn/no-copy) — the bodyless `=` - [Destructor](https://rux-lang.dev/docs/learn/destructor) — the other end of every copy's life # Partial move ::note **You'll need**: [Non-copyable types](https://rux-lang.dev/docs/learn/no-copy), [Destructure](https://rux-lang.dev/docs/learn/destructure), [Struct pattern](https://rux-lang.dev/docs/learn/struct-pattern) :: A parcel is wrapping paper around a gift. It is tempting to move just the gift out and leave the rest where it is — but Rux refuses: a field cannot be moved out of a value on its own. What works instead is taking the **whole** value apart, so that every field gets exactly one new owner. This lesson brings together three things from earlier: [move-only types](https://rux-lang.dev/docs/learn/no-copy), [destructors](https://rux-lang.dev/docs/learn/destructor), and the [struct pattern](https://rux-lang.dev/docs/learn/struct-pattern) you used to [destructure](https://rux-lang.dev/docs/learn/destructure) values in `let`. ## The parcel `Item` is move-only and announces its own destruction. `Parcel` holds two of them and has no destructor of its own: ```rux struct Item { name: char8[..]; } extend Item { func =(self: &var Item, other: &Item); func ~Item(self: &var Item) { PrintLine(" {} destroyed", self.name); } } // No destructor of its own, so a moving pattern may take it apart. struct Parcel { wrapping: Item; gift: Item; } ``` Because both fields are move-only, `Parcel` is move-only too: copying a parcel would copy the items inside it. ## One field on its own is refused The obvious way to get the gift out does not compile: ```rux return <-parcel.gift; ``` ```text error: cannot move field 'gift' out of droppable value 'parcel' note: partial moves would leave the aggregate with only some fields initialized help: move the complete aggregate or borrow or clone the component explicitly ``` Half a parcel would be a value that is partly alive. When `parcel`'s scope ended, the compiler could no longer say what to destroy: the wrapping, yes, but not the gift, which has moved on. Rather than track a value that is part here and part gone, Rux keeps the rule simple — a value is moved whole or not at all. ## Taking the whole value apart A struct pattern with `<-` moves the parcel into the pattern, and every field gets exactly one owner again: ```rux func Unwrap(parcel: Parcel) -> Item { let Parcel { wrapping: _, gift: gift } <- parcel; PrintLine(" unwrapped the {}", gift.name); return <-gift; } ``` - A field bound to a name belongs to that binding. `gift` is a local `Item` now, and `return <-gift` hands it to the caller. - A field bound to `_`, or left out of the pattern, belongs to nobody, so it is destroyed on the spot. That is why the output reads "paper destroyed" *before* "unwrapped the book": the wrapping is gone by the time the `let` finishes. ```mermaid flowchart LR p(["`parcel: Parcel`"]) -- "`let Parcel { … } <- parcel`" --> pat{"each field
gets one owner"} pat -- "`wrapping: _`" --> w["no owner —
destroyed at the `let`"] pat -- "`gift: gift`" --> g["owned by `gift`"] g -- "`return <-gift`" --> c["the caller's `gift`
destroyed at the end of `Main`"] ``` ## Only a struct that is just its fields A struct can be taken apart only when it has no destructor of its own. Give `Parcel` a `~Parcel`, and that destructor needs the whole parcel to run on — so the same pattern is refused: ```text error: cannot split 'Parcel' with a moving pattern, because it declares destructor '~Parcel' note: '~Parcel' runs on the whole value, so no part of it can be taken out on its own help: bind the whole value and read its fields, or match a value that stays with its owner ``` | You want | Write | Allowed when | | ------------------------------ | --------------------------------------------------- | ------------------------------ | | one field, moved out | `<-parcel.gift` | never | | every field, each to one owner | `let Parcel { wrapping: _, gift: gift } <- parcel;` | the struct has no destructor | | to look at a field | `parcel.gift.name` | always — reading moves nothing | ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Ownership/PartialMove){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // A parcel is wrapping paper around a gift. It is tempting to move just the gift out and leave the // rest where it is, but Rux refuses: a field cannot be moved out of a value on its own. // // return <-parcel.gift; // // error: cannot move field 'gift' out of droppable value 'parcel' // note: partial moves would leave the aggregate with only some fields initialized // help: move the complete aggregate or borrow or clone the component explicitly // // Half a parcel would be a value that is partly alive, and the compiler could no longer say what // to destroy when its scope ends. // // What works is taking the whole value apart. A struct pattern with `<-` moves the parcel into // the pattern, and every field gets exactly one owner again: a field bound to a name belongs to // that binding, and a field bound to `_`, or left out of the pattern, belongs to nobody and is // destroyed on the spot. So the gift moves on and the wrapping is gone before the next line runs. // // Only a struct that is nothing more than its fields can be taken apart. Give `Parcel` its own // destructor and that destructor needs the whole parcel, so the same pattern is refused: // // error: cannot split 'Parcel' with a moving pattern, because it declares destructor '~Parcel' // note: '~Parcel' runs on the whole value, so no part of it can be taken out on its own // help: bind the whole value and read its fields, or match a value that stays with its owner import Io::PrintLine; struct Item { name: char8[..]; } extend Item { func =(self: &var Item, other: &Item); func ~Item(self: &var Item) { PrintLine(" {} destroyed", self.name); } } // No destructor of its own, so a moving pattern may take it apart. struct Parcel { wrapping: Item; gift: Item; } // The gift moves out to the caller. The wrapping is bound to `_`, so it is destroyed at the `let`. func Unwrap(parcel: Parcel) -> Item { let Parcel { wrapping: _, gift: gift } <- parcel; PrintLine(" unwrapped the {}", gift.name); return <-gift; } func Main() -> int { PrintLine("unwrapping:"); let gift = Unwrap(Parcel { wrapping: Item { name: "paper" }, gift: Item { name: "book" } }); PrintLine(" reading the {}", gift.name); PrintLine("end of Main:"); return 0; } ``` ## Run it ```sh cd Examples/Ownership/PartialMove rux run ``` ```text unwrapping: paper destroyed unwrapped the book reading the book end of Main: book destroyed ``` ## Common mistakes ::mistake **Moving a single field.**:br`return <-parcel.gift;` fails with: ```text error: cannot move field 'gift' out of droppable value 'parcel' ``` Take the parcel apart with a moving pattern instead, or read the field without moving it. :: ::mistake **Destructuring with `=` instead of `<-`.**:br`let Parcel { wrapping: _, gift: gift } = parcel;` fails with: ```text error: move-only value 'parcel' requires an explicit '<-' in initialization ``` A destructuring `let` owns what it takes apart, and a move-only parcel can only be handed over with the arrow. :: ::mistake **Splitting a struct that has its own destructor.**:br With `~Parcel` declared, the pattern fails with: ```text error: cannot split 'Parcel' with a moving pattern, because it declares destructor '~Parcel' ``` Bind the parcel whole and read its fields, or drop the destructor if the struct does not really need one. :: ## Try it yourself 1. Leave `wrapping` out of the pattern altogether: `let Parcel { gift: gift } <- parcel;`. Is the paper still destroyed at the `let`? 2. In `Main`, build a parcel and take it apart into two bindings, `wrapping: w, gift: g`. At the end of `Main`, which item is destroyed first? 3. Add `func ~Parcel(self: &var Parcel)` that prints "parcel opened", and read the error. Then change `Unwrap` so it only prints `parcel.gift.name` and returns nothing. ## Learn more - [Struct pattern](https://rux-lang.dev/docs/learn/struct-pattern) and [Destructure](https://rux-lang.dev/docs/learn/destructure) — the patterns used here - [Non-copyable types](https://rux-lang.dev/docs/learn/no-copy) — why `Item` and `Parcel` can only be moved - [Initialization](https://rux-lang.dev/docs/learn/initialization) — the same "whole value" rule when a variable starts empty # Defer ::note **You'll need**: [Method](https://rux-lang.dev/docs/learn/method), [Return](https://rux-lang.dev/docs/learn/return) :: Some work has to be undone however a function ends. A valve that is opened must be closed — on the normal path, and on every early `return` as well. Writing the close before each exit is easy to get wrong, and the mistake is silent: the program runs, and the valve stays open. `defer` registers a statement now and runs it when the enclosing scope ends, by whichever way it ends. So the cleanup is written **once**, on the line right after the work it undoes, where a reader can check that the two match. ## Cleanup next to the work A `Valve` can be opened and closed; each method prints, so you can see the order: ```rux struct Valve { name: char8[..]; } extend Valve { func Open(self: &Valve) { PrintLine(" open {}", self.name); } func Close(self: &Valve) { PrintLine(" close {}", self.name); } } ``` `Fill` opens two valves, and pairs each `Open` with a deferred `Close` on the very next line: ```rux let supply = Valve { name: "supply" }; supply.Open(); defer supply.Close(); let drain = Valve { name: "drain" }; drain.Open(); defer drain.Close(); ``` Nothing is closed yet. `defer` only remembers the statement; it runs later, when `Fill` ends. ## Every way out `Fill` has two exits — an early `return false` for too much water, and the normal `return true`: ```rux if litres > 100 { PrintLine(" {} litres is too much, stopping", litres); return false; } PrintLine(" filling {} litres", litres); return true; ``` Neither `return` mentions a valve, yet both valves are closed on both paths. Add a third exit next year, and it will close them too — the cleanup belongs to the scope, not to any one `return`. ## Last registered, first run Several defers run in **reverse** order: the last one registered runs first. The drain was opened last, so it is closed first: ```text fill 40: open supply open drain filling 40 litres close drain close supply ``` That is the order cleanup usually needs, because what was set up last tends to depend on what came before it. Values with [destructors](https://rux-lang.dev/docs/learn/destructor) follow the same rule, and when a scope has both, the deferred statements run first, newest first, and then the values are destroyed, newest first: ```mermaid flowchart LR subgraph reg["Registered while the scope runs"] direction TB r1["1. `let ada = Guest`"] --> r2["2. `defer` lights off"] r2 --> r3["3. `let bob = Guest`"] r3 --> r4["4. `defer` music off"] end subgraph run["At the end of the scope"] direction TB e1["music off"] --> e2["lights off"] e2 --> e3["Bob leaves"] e3 --> e4["Ada leaves"] end reg -- "defers in reverse,
then destructors in reverse" --> run ``` Here `Guest` is the type from [Destructor](https://rux-lang.dev/docs/learn/destructor), whose destructor prints "… leaves". ## A defer is registered when it is reached `defer` is a statement like any other, and it counts only once execution reaches it. A `return` that comes before a `defer` line leaves without running it — which is exactly right, because the work it would undo has not been done yet either. Put a `return` between opening the supply and opening the drain, and only the supply is closed on that path. A `defer` belongs to the scope it is written in. Inside a loop body, it runs at the end of every pass, not once after the loop. ## Defer or destructor? | | Destructor `~T` | `defer` | | ---------- | -------------------------- | --------------------------------- | | Belongs to | a type — every value of it | one piece of work in one function | | Written | once, in `extend T` | at the place the work starts | | Runs | when a value's life ends | when the enclosing scope ends | A destructor cleans up after a value. `defer` is for cleanup that belongs to a piece of work rather than to any one value's life — the valves here are ordinary values with no destructor, and opening one is something `Fill` does, not something every `Valve` needs undone. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Ownership/Defer){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // Some work has to be undone however a function ends: a valve that is opened must be closed, on // the normal path and on every early `return` as well. Writing the close before each exit is easy // to get wrong, and the mistake is silent. // // `defer` registers a statement now and runs it when the enclosing scope ends, by whichever way // it ends. So the cleanup is written once, on the line right after the work it undoes, where a // reader can check that the two match. // // Several defers run in reverse order: the last one registered runs first. That is the order // cleanup usually needs, because what was set up last tends to depend on what came before it. // // A destructor cleans up after a value. `defer` is for cleanup that belongs to a piece of work // rather than to any one value's life. import Io::PrintLine; struct Valve { name: char8[..]; } extend Valve { func Open(self: &Valve) { PrintLine(" open {}", self.name); } func Close(self: &Valve) { PrintLine(" close {}", self.name); } } func Fill(litres: int32) -> bool { let supply = Valve { name: "supply" }; supply.Open(); defer supply.Close(); let drain = Valve { name: "drain" }; drain.Open(); defer drain.Close(); // An early exit. Both valves are still closed, drain first. if litres > 100 { PrintLine(" {} litres is too much, stopping", litres); return false; } PrintLine(" filling {} litres", litres); return true; } func Main() -> int { PrintLine("fill 40:"); let first = Fill(40); PrintLine(" filled: {}", first); PrintLine("fill 500:"); let second = Fill(500); PrintLine(" filled: {}", second); return 0; } ``` ## Run it ```sh cd Examples/Ownership/Defer rux run ``` ```text fill 40: open supply open drain filling 40 litres close drain close supply filled: true fill 500: open supply open drain 500 litres is too much, stopping close drain close supply filled: false ``` ## Common mistakes ::mistake **Deferring a block.**:br`defer { PrintLine("a"); PrintLine("b"); }` does not parse: ```text error: expected an expression before '{' ``` A `defer` takes one statement. Write two defers — remembering they run in reverse — or put the steps in a method and defer the call. :: ::mistake **Registering the cleanup too late.**:br A `defer` written at the end of a function, or after an early `return`, does not run on the paths that leave before it. There is no error for this; it is the very mistake `defer` exists to prevent. Write it on the line right after the work it undoes. :: ::mistake **Expecting defers to run in the order written.**:br They run newest first. If the drain must close before the supply, register the supply's cleanup first — which is what opening them in that order already does. :: ## Try it yourself 1. Add a third valve, `vent`, opened after the drain. Predict the order of the three closes on both paths, then run it. 2. Add an early `return false` for `litres <= 0` between opening the supply and opening the drain. Which valves are closed when you call `Fill(0)`? 3. Write a `for` loop over `0..3` whose body defers a `PrintLine` of the pass number. Does each line print at the end of its own pass, or all after the loop? ## Learn more - [Defer return](https://rux-lang.dev/docs/learn/defer-return) — what a deferred statement sees when a function returns a value - [Destructor](https://rux-lang.dev/docs/learn/destructor) — cleanup that belongs to a value - [Return](https://rux-lang.dev/docs/learn/return) — the early exits `defer` has to cover # Defer return ::note **You'll need**: [Defer](https://rux-lang.dev/docs/learn/defer), [Mutating method](https://rux-lang.dev/docs/learn/mutating-method) :: `return` and [`defer`](https://rux-lang.dev/docs/learn/defer) meet at the end of a function, and the order between them is fixed. `return value;` works out its value first and **keeps** it; only then do the deferred statements run. Whatever they change afterwards, the caller still receives the kept value. That sounds like a detail, but it makes a useful pattern possible: "hand out the current value, then move on" becomes a two-line function, with no temporary variable to hold the old value. ## The order at the end of a function `Countdown` registers two deferred statements and then returns its local: ```rux func Countdown() -> int32 { var remaining: int32 = 3; defer PrintLine(" deferred code sees remaining = {}", remaining); defer remaining = 0; return remaining; } ``` Step by step, as the function ends: ```mermaid flowchart LR r["`return remaining`
works out `3`
and keeps it"] --> d1["`defer remaining = 0`
(registered last, runs first)"] d1 --> d2["`defer PrintLine(…)`
prints `remaining = 0`"] d2 --> c["the caller
receives `3`"] ``` ```text countdown: deferred code sees remaining = 0 returned 3 ``` Two things are worth noticing in that output. The `PrintLine` shows 0, not 3. A deferred statement is evaluated **when it runs**, not when it is registered — so it reads `remaining` after the reset has happened. And the reset *did* happen: the local really is 0. It simply makes no difference to the caller, who gets the 3 that `return` had already kept. ## Hand out, then advance A ticket dispenser shows a number. Taking a ticket gives you that number, and the display moves on to the next: ```rux struct Dispenser { next: int32; } extend Dispenser { // Returns the current ticket, then advances the dispenser. func Take(self: &var Dispenser) -> int32 { defer self.next += 1; return self.next; } } ``` `return self.next` keeps the current number; the deferred `self.next += 1` then advances the dispenser. Without `defer`, the same method needs a temporary: ```rux let ticket = self.next; self.next += 1; return ticket; ``` Both are correct. The `defer` version says what the method is for in its last line — return the current ticket — and puts the bookkeeping on the line before it. ```rux var dispenser = Dispenser { next: 1 }; let first = dispenser.Take(); let second = dispenser.Take(); ``` `first` is 1, `second` is 2, and the dispenser now shows 3. The method changes `self`, so it takes `&var Dispenser`, as in [Mutating method](https://rux-lang.dev/docs/learn/mutating-method). | Statement | When it is evaluated | What the caller sees | | ----------------------- | ------------------------------ | ---------------------------- | | `return self.next;` | first — its value is kept | the kept value | | `defer self.next += 1;` | after the return value is kept | the change, on its next call | ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Ownership/DeferReturn){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // `return` and `defer` meet at the end of a function, and the order between them is fixed: // `return value;` works out its value first and keeps it, and only then do the deferred // statements run. Whatever they change afterwards, the caller still receives the kept value. // // That makes "hand out the current value, then move on" a two-line function. A ticket dispenser // returns the number it is showing and advances to the next one, without a temporary variable to // hold the old number. import Io::PrintLine; // Both deferred statements run after the return value is kept. In reverse order, so the reset // runs first and the `PrintLine` then shows that the local really changed. The caller gets 3. func Countdown() -> int32 { var remaining: int32 = 3; defer PrintLine(" deferred code sees remaining = {}", remaining); defer remaining = 0; return remaining; } struct Dispenser { next: int32; } extend Dispenser { // Returns the current ticket, then advances the dispenser. func Take(self: &var Dispenser) -> int32 { defer self.next += 1; return self.next; } } func Main() -> int { PrintLine("countdown:"); let result = Countdown(); PrintLine(" returned {}", result); PrintLine("tickets:"); var dispenser = Dispenser { next: 1 }; let first = dispenser.Take(); let second = dispenser.Take(); PrintLine(" took {} and {}, now showing {}", first, second, dispenser.next); return 0; } ``` ## Run it ```sh cd Examples/Ownership/DeferReturn rux run ``` ```text countdown: deferred code sees remaining = 0 returned 3 tickets: took 1 and 2, now showing 3 ``` ## Common mistakes ::mistake **Expecting a deferred change to reach the caller.**:br`defer remaining = 0;` does reset the local, but `Countdown()` still returns 3. The return value was kept before any deferred statement ran. If the caller must see the change, make it before the `return`. :: ::mistake **Expecting a deferred statement to remember old values.**:br`defer PrintLine("{}", remaining);` does not capture `remaining` at the `defer` line. It reads the variable when it runs, at the end of the function, after everything else has changed it. :: ::mistake **Advancing through a read-only receiver.**:br With `func Take(self: &Dispenser)`, the deferred `self.next += 1;` fails with: ```text error: cannot modify data through immutable reference '&Dispenser' ``` Deferred code is checked like any other code in the function: changing `self` needs `&var`. :: ## Try it yourself 1. Swap the two `defer` lines in `Countdown`. What does the deferred `PrintLine` show now, and does the returned value change? 2. Add a method `Peek(self: &Dispenser) -> int32` that returns the next ticket without taking it, and print it between the two `Take` calls. 3. Write `func Next(counter: &var int32) -> int32` that returns the counter's current value and then adds 1 to it, using `defer`. Call it twice on a `var` that starts at 5. ## Learn more - [Defer](https://rux-lang.dev/docs/learn/defer) — registering cleanup, and the reverse order - [Mutating method](https://rux-lang.dev/docs/learn/mutating-method) — `self: &var T` - [Return](https://rux-lang.dev/docs/learn/return) — returning a value from a function # Initialization ::note **You'll need**: [Else if](https://rux-lang.dev/docs/learn/else-if), [Constructor](https://rux-lang.dev/docs/learn/constructor) :: A `var` may be declared before its value is known, and given one later. Until then it holds nothing, and the compiler tracks it: every path that reaches a read must have assigned it first. A read that some path can reach without an assignment is rejected at compile time — so a Rux program never sees leftover garbage from an unassigned variable. This is the last lesson of the part, and it closes the circle on ownership. A value's life ends with its destructor; this lesson is about how it begins, and why the compiler must always know whether a variable holds a value at all. ## Declare now, assign later Sometimes the value depends on a decision that has not been made yet. `grade` is declared with a type and no value, and each branch of an [`else if`](https://rux-lang.dev/docs/learn/else-if) chain assigns it: ```rux func Grade(score: int32) -> char8[..] { var grade: char8[..]; if score >= 90 { grade = "excellent"; } else if score >= 50 { grade = "pass"; } else { grade = "retry"; } return grade; } ``` The compiler follows every path from the declaration to the `return`, and on each one `grade` has been assigned. The read is accepted. ```mermaid flowchart LR d["`var grade: char8[..]`
holds nothing"] --> q{"`score`?"} q -- "`>= 90`" --> a1["`grade = excellent`"] q -- "`>= 50`" --> a2["`grade = pass`"] q -- "`else`" --> a3["`grade = retry`"] a1 --> r["`return grade`
assigned on every path"] a2 --> r a3 --> r q -. "without the final `else`" .-> x["`error: value 'grade' may be`
`uninitialized on some`
`control-flow paths`"] ``` Delete the final `else`, and a score below 50 reaches the `return` with nothing assigned. The compiler refuses the program and points at where that path starts. ## Reading too early The simplest case is a read straight after the declaration: ```rux var total: int32; PrintLine("{}", total); ``` ```text error: variable 'total' is used before it is initialized note: 'total' was declared without an initializer at 47:5 help: assign a value to 'total' before this use ``` Many languages would print whatever happened to be in that memory, or a silent zero. Rux makes you say what the value is. ## A let needs its value now A `let` has no such freedom. It can never be assigned later, so it needs its value where it is declared: `let total: int32;` on its own is rejected with `error: immutable variable requires an initializer`. ## One field at a time A plain struct of numbers may be filled in one field at a time, and it counts as assigned once every field has been written. The compiler tracks the fields individually: after `var p: Point; p.x = 1;`, reading `p.x` is fine, but reading `p.y` is refused, with a note that only `p.x` has been written. A type that needs destroying is different. When a struct holds a `Guest` — the type with a destructor from the [Destructor](https://rux-lang.dev/docs/learn/destructor) lesson — a guest written into one field of an empty struct would belong to no whole value, and nothing would ever destroy it. So such a variable must get its value whole: ```rux var table: Table; table.guest = Guest { name: "Gus" }; ``` ```text error: cannot write field 'guest' of 'table', which holds no value help: initialize 'table' whole, as in 'table = Table { ... }' ``` It is the same rule as in [Partial move](https://rux-lang.dev/docs/learn/partial-move), seen from the other end: a value with a destructor is alive whole, or not at all. ## A constructor runs for you There is one exception to "holds nothing". When the type has a [constructor](https://rux-lang.dev/docs/learn/constructor) that takes no arguments, `var value: T;` calls it, and the variable starts out initialized: ```rux extend Tally { func Tally() -> Tally { PrintLine(" Tally() starts the count at zero"); return Tally { count: 0 }; } } ``` ```rux var tally: Tally; tally.count += 1; ``` `tally.count += 1` reads the count before changing it, and that read is fine — the constructor has already run, as the output shows. | Declaration | Starts as | | ---------------------------------- | ---------------------------------- | | `var grade: char8[..];` | nothing — assign before reading | | `var tally: Tally;` with `Tally()` | whatever `Tally()` returns | | `let total: int32;` | an error — a `let` needs its value | ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Ownership/Initialization){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // A `var` may be declared before its value is known, and given one later. Until then it holds // nothing, and the compiler tracks it: every path that reaches a read must have assigned it // first. A read that some path can reach without an assignment is rejected at compile time, so // a Rux program never sees leftover garbage from an unassigned variable. // // A `let` has no such freedom. It cannot be assigned later, so it needs its value where it is // declared. // // One exception to "holds nothing": when the type has a constructor taking no arguments, // `var value: T;` calls it, and the variable starts out initialized. import Io::PrintLine; // Every branch assigns `grade`, so the read in `return` is accepted. Delete the final `else` and // one path reaches the read with nothing assigned: // // error: value 'grade' may be uninitialized on some control-flow paths // note: one unavailable path for 'grade' originates at 20:5 // help: initialize or preserve 'grade' on every path before this use func Grade(score: int32) -> char8[..] { var grade: char8[..]; if score >= 90 { grade = "excellent"; } else if score >= 50 { grade = "pass"; } else { grade = "retry"; } return grade; } struct Tally { count: int32; } extend Tally { func Tally() -> Tally { PrintLine(" Tally() starts the count at zero"); return Tally { count: 0 }; } } func Main() -> int { PrintLine("grades: {}, {}, {}", Grade(95), Grade(72), Grade(31)); // Declared without a value and read straight away: // // var total: int32; // PrintLine("{}", total); // // error: variable 'total' is used before it is initialized // note: 'total' was declared without an initializer at 47:5 // help: assign a value to 'total' before this use // When the type needs destroying, a variable without a value must also get its value whole. // Here `Table` is a struct holding a `Guest`, the type with a destructor from the Destructor // lesson. A guest written into one field would belong to no whole table, and nothing would // ever destroy it: // // var table: Table; // table.guest = Guest { name: "Gus" }; // // error: cannot write field 'guest' of 'table', which holds no value // help: initialize 'table' whole, as in 'table = Table { ... }' // `Tally` has a constructor without arguments, so this declaration runs it. PrintLine("tally:"); var tally: Tally; tally.count += 1; PrintLine(" count {}", tally.count); return 0; } ``` ## Run it ```sh cd Examples/Ownership/Initialization rux run ``` ```text grades: excellent, pass, retry tally: Tally() starts the count at zero count 1 ``` ## Common mistakes ::mistake **A path that never assigns.**:br Without the final `else` in `Grade`, `return grade;` fails with: ```text error: value 'grade' may be uninitialized on some control-flow paths ``` Every branch that can reach the read must assign — add the missing `else`, or give the variable a sensible starting value. :: ::mistake **Reading before the first assignment.**:br`var total: int32; PrintLine("{}", total);` fails with: ```text error: variable 'total' is used before it is initialized ``` There is no hidden zero. If zero is what you mean, write `var total: int32 = 0;`. :: ::mistake **A `let` without a value.**:br`let total: int32;` fails with: ```text error: immutable variable requires an initializer ``` Declare it with `var` if it must be assigned later, or give it its value on the spot. :: ::mistake **Filling a destroyable struct one field at a time.**:br`var table: Table; table.guest = Guest { name: "Gus" };` fails with: ```text error: cannot write field 'guest' of 'table', which holds no value ``` Assign the whole struct: `table = Table { guest: Guest { name: "Gus" } };`. :: ## Try it yourself 1. Delete the final `else` in `Grade` and read the error and its note. 2. Declare `struct Point { x: int32; y: int32; }`, then `var p: Point; p.x = 1;`, and print `p.y`. Then assign `p.y` too and print both. 3. Remove the `Tally()` constructor. Which lines in `Main` are now rejected, and what would you write instead? ## Learn more - [Constructor](https://rux-lang.dev/docs/learn/constructor) — the function `var value: T;` calls - [Mutable](https://rux-lang.dev/docs/learn/mutable) — `var` and `let` - [`var`](https://rux-lang.dev/docs/lang/bindings/overview#var) and [`let`](https://rux-lang.dev/docs/lang/bindings/overview#let) in the Rux Reference # Part 12: Interfaces A circle and a rectangle both have an area; a price and a temperature can both be printed; a version number and a score can both be put in order. An **interface** names a piece of behaviour like that, and any type can promise to provide it. This part shows how to declare and keep such a promise, how code written against the promise works for every type that keeps it, and how your own types join in with the language's own machinery: `{}` placeholders, `==` and `<`, square brackets and `for` loops. ## What you will learn - Declaring an `interface` and implementing it with `extend Type : Interface`. - Interface values: one variable, array or loop holding many types, with dynamic dispatch choosing the method. - Interface parameters, `&I` and `&var I`, and requirements that write with `self: &var Self`. - The standard interfaces `Display`, `Equatable` and `Comparable`, and the `Ordering` a comparison answers with. - Comparing structs, tuples, arrays and variants with `==`, field by field, for free. - Declaring operators such as `+`, `==`, `<` and `[]` for your own types, and the four comparisons derived from two. - Making a type walkable by `for` with `Next`, and a collection with `Iterate`. ## How a type joins in ```mermaid flowchart LR t(["Your type"]) --> own["`interface` + `extend T : I`
a promise the compiler checks
(12.1)"] own --> dyn["interface values and parameters
one call, many types
(12.2–12.3)"] t --> std["standard interfaces
printed with `{}`, `Equals`, `Compare`
(12.4–12.6)"] t --> ops["operator functions
`==`, `+`, `<`, `[]`
(12.7–12.10)"] t --> loops["`Next` and `Iterate`
walked by `for`
(12.11–12.12)"] ``` ## Lessons | | Lesson | What you will learn | | ----- | -------------------------------------------------------------------------- | ---------------------------------------------------------------- | | 12.1 | [Interface](https://rux-lang.dev/docs/learn/interface) | declare an interface and implement it for your own types | | 12.2 | [Interface value](https://rux-lang.dev/docs/learn/interface-value) | hold any implementing type in one interface value | | 12.3 | [Interface parameter](https://rux-lang.dev/docs/learn/interface-parameter) | write a function that accepts any type implementing an interface | | 12.4 | [Display](https://rux-lang.dev/docs/learn/display) | make your own type printable with `{}` | | 12.5 | [Equatable](https://rux-lang.dev/docs/learn/equatable) | define what it means for two of your values to be equal | | 12.6 | [Comparable](https://rux-lang.dev/docs/learn/comparable) | define an order for your own type | | 12.7 | [Structural equality](https://rux-lang.dev/docs/learn/structural-equality) | compare whole structs and tuples with `==` | | 12.8 | [Operator overload](https://rux-lang.dev/docs/learn/operator-overload) | define `==`, `+` and the other operators for your own type | | 12.9 | [Derived operator](https://rux-lang.dev/docs/learn/derived-operator) | define one operator and get its partners for free | | 12.10 | [Indexer](https://rux-lang.dev/docs/learn/indexer) | let your own type be indexed with `[]` | | 12.11 | [Iterator](https://rux-lang.dev/docs/learn/iterator) | implement `Next` so a type of your own can be used with `for` | | 12.12 | [Iterable](https://rux-lang.dev/docs/learn/iterable) | let a container hand out an iterator for `for` | ## Before you start Finish [Part 11: Ownership](https://rux-lang.dev/docs/learn/ownership) — an interface value is a [copy](https://rux-lang.dev/docs/learn/copy) of what it holds. The lessons also lean on [Method](https://rux-lang.dev/docs/learn/method), [Extension](https://rux-lang.dev/docs/learn/extension) and [Mutable reference](https://rux-lang.dev/docs/learn/mutable-reference) from Part 6, on optionals from [Part 8](https://rux-lang.dev/docs/learn/optionals) for iterators, and on [Propagate](https://rux-lang.dev/docs/learn/propagate) from Part 9 for `Display`. Each lesson's package is in the Examples repository's `Interfaces/` folder: ```sh cd Examples/Interfaces/Interface rux run ``` ## After this part [Part 13: Generics](https://rux-lang.dev/docs/learn/generics) writes one function or type for many types at once, and interfaces come straight back as its *bounds*: `` accepts any type that keeps the `Display` promise, checked when the program is compiled rather than dispatched while it runs. After [Part 16: Numbers](https://rux-lang.dev/docs/learn/numbers) you are ready for the next checkpoint projects, [Circle](https://rux-lang.dev/docs/learn/circle) and [Quadratic](https://rux-lang.dev/docs/learn/quadratic). For the rules behind this part, see [Interfaces](https://rux-lang.dev/docs/lang/interfaces/overview), [Methods](https://rux-lang.dev/docs/lang/structs/methods) and [Comparison operators](https://rux-lang.dev/docs/lang/expressions/comparison) in the Rux Reference. # Interface ::note **You'll need**: [Method](https://rux-lang.dev/docs/learn/method), [Extension](https://rux-lang.dev/docs/learn/extension) :: Different types often answer the same question in their own way. A circle and a rectangle both have an area, but each works it out differently. An **interface** gives that shared question a name: it lists the functions a type must provide, and a type that *implements* the interface promises to provide every one of them. This lesson is about making that promise and having the compiler hold you to it. The next two lessons show what other code can do with a type once it has made one. ## Declaring an interface ```rux interface Shape { func Area() -> float64; func Name() -> char8[..]; } ``` An interface lists function headers — names, parameters and result types — and ends each one with `;` where a body would go. It has no fields and no code of its own. It only names what must exist. The requirements carry no `self`. The interface says what each implementation must be able to answer; each implementation supplies its own receiver. ## Keeping the promise A type makes the promise in an `extend` block, the same block you met in [Extension](https://rux-lang.dev/docs/learn/extension), with `: Shape` after the type name: ```rux extend Circle : Shape { func Area(self: &Circle) -> float64 { return 3.14 * self.radius * self.radius; } func Name(self: &Circle) -> char8[..] { return "circle"; } } ``` Inside, each requirement is written as an ordinary [method](https://rux-lang.dev/docs/learn/method), now with `self: &Circle` as its first parameter. `Rectangle` keeps the same promise with its own formula. The two halves divide the work like this: | Written | Who writes it | What it says | | ----------------------------- | ---------------------- | ----------------------------------- | | `interface Shape { … }` | the interface | which functions must exist | | `extend Circle : Shape { … }` | each implementing type | how this type provides each of them | The compiler checks the promise word for word. Delete `Name` from the `Circle` block and the program is refused: `error: implementation of interface 'Shape' for type 'Circle' is missing method 'Name'`. Methods that keep a promise are called like any other method: ```rux PrintLine("a {} with area {}", wheel.Name(), wheel.Area()); PrintLine("a {} with area {}", door.Name(), door.Area()); ``` ## More than the promise An implementation may add methods beyond the promised ones: ```rux // An implementation may add methods beyond the promised ones. This one belongs to // Rectangle alone; Shape knows nothing about it. func IsSquare(self: &Rectangle) -> bool { return self.width == self.height; } ``` `door.IsSquare()` works because `door` is a `Rectangle`. `Shape` knows nothing about `IsSquare`, which will matter in the next lesson, where a value is known only as "some `Shape`". ## Any type can make the promise The implementing type does not have to be a struct you wrote. A primitive type such as `int32` can implement `Shape` just as well: ```rux extend int32 : Shape { func Area(self: &int32) -> float64 { return 0.0; } func Name(self: &int32) -> char8[..] { return "number"; } } ``` After this, `let n: int32 = 4;` answers `n.Name()` with `number`. An interface describes behaviour, not a family of related types: anything that can answer the questions may join. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Interfaces/Interface){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // An interface is a promise a type can make: a list of functions it will provide. The interface // has no fields and no code of its own. It only names what must exist. // // A type makes the promise with `extend Type : Interface { ... }`, and the compiler holds it to // it: leave a function out and the `extend` is rejected. Copy each signature exactly as well — a // different parameter or result type breaks the promise, though the compiler does not catch that // yet. That checked promise is this lesson. The next two show what other code can do with a // type once it has made one. // // Any type can make the promise, including one you did not write: `extend int32 : Shape` would be // just as valid as the two below. import Io::PrintLine; // The requirements. They carry no `self`: the interface says what each implementation must be // able to answer, and each implementation supplies its own receiver. interface Shape { func Area() -> float64; func Name() -> char8[..]; } struct Circle { radius: float64; } struct Rectangle { width: float64; height: float64; } // `: Shape` after the type name is the promise. Inside, each requirement is written as an // ordinary method, now with `self` as its first parameter. extend Circle : Shape { func Area(self: &Circle) -> float64 { return 3.14 * self.radius * self.radius; } func Name(self: &Circle) -> char8[..] { return "circle"; } } extend Rectangle : Shape { func Area(self: &Rectangle) -> float64 { return self.width * self.height; } func Name(self: &Rectangle) -> char8[..] { return "rectangle"; } // An implementation may add methods beyond the promised ones. This one belongs to // Rectangle alone; Shape knows nothing about it. func IsSquare(self: &Rectangle) -> bool { return self.width == self.height; } } func Main() -> int { let wheel = Circle { radius: 2.0 }; let door = Rectangle { width: 0.9, height: 2.0 }; // Methods that keep a promise are called like any other method. PrintLine("a {} with area {}", wheel.Name(), wheel.Area()); PrintLine("a {} with area {}", door.Name(), door.Area()); PrintLine("is the door square? {}", door.IsSquare()); // Delete `Name` from the Circle block and the compiler refuses the program: "implementation // of interface 'Shape' for type 'Circle' is missing method 'Name'". return 0; } ``` ## Run it ```sh cd Examples/Interfaces/Interface rux run ``` ```text a circle with area 12.56 a rectangle with area 1.8 is the door square? false ``` ## Common mistakes ::mistake **Leaving out a requirement.**:br Every function the interface lists must appear in the `extend` block. Without `Name`, the compiler stops with: ```text error: implementation of interface 'Shape' for type 'Circle' is missing method 'Name' ``` :: ::mistake **Changing a requirement's signature.**:br Copy each header from the interface exactly — the same parameters and the same result type — and add only the `self` receiver in front. A `Circle` whose `Area` returned `float32` would not be answering the question `Shape` asks, even though the name matches. :: ::mistake **Forgetting `: Shape`.**:br A plain `extend Circle { … }` with the right methods in it makes no promise: the methods exist, but `Circle` is not a `Shape`. Nothing complains until you use it as one — `let s: Shape = wheel;` then fails with: ```text error: cannot assign 'Circle' to 'Shape' ``` :: ::mistake **Misspelling the interface.**:br`extend Circle : Shap { … }` is refused with: ```text error: interface 'Shap' is not defined ``` The interface must be declared, or imported, before a type can implement it. :: ## Try it yourself 1. Add `struct Triangle { base: float64; height: float64; }` and make it keep the `Shape` promise. Its area is half the base times the height. 2. Add a third requirement, `func Perimeter() -> float64;`, to `Shape`. Read the errors, then implement it for every shape. 3. Make a square door, `Rectangle { width: 1.0, height: 1.0 }`, and check that `IsSquare` says so. ## Learn more - [Interfaces](https://rux-lang.dev/docs/lang/interfaces/overview) in the Rux Reference - [Extension](https://rux-lang.dev/docs/learn/extension) — `extend` without an interface - [Interface value](https://rux-lang.dev/docs/learn/interface-value) — one variable that can hold any `Shape` - [Generic bound](https://rux-lang.dev/docs/learn/generic-bound) — an interface as a requirement on a generic type # Interface value ::note **You'll need**: [Interface](https://rux-lang.dev/docs/learn/interface), [Copy](https://rux-lang.dev/docs/learn/copy) :: In the [Interface](https://rux-lang.dev/docs/learn/interface) lesson, `wheel.Area()` could only ever mean Circle's `Area`: the compiler knew `wheel` was a `Circle`. An interface is also a **type** in its own right. A variable of type `Shape` can hold a circle now and a rectangle a moment later, and a call through it runs whichever `Area` belongs to the value inside. That is what lets values of different types share one variable, one array or one loop. ## Making an interface value ```rux // The annotation is what turns a circle into a Shape. var shape: Shape = wheel; PrintLine("holding a {} with area {}", shape.Name(), shape.Area()); ``` `shape` holds a copy of the circle, together with a note of which type that copy is. Without the annotation, `var shape = wheel;` would simply be another `Circle`. ## Dynamic dispatch Now put a rectangle in the same variable: ```rux // Same variable, different type inside, so the same calls now run Rectangle's code. shape = door; PrintLine("holding a {} with area {}", shape.Name(), shape.Area()); ``` The call is written the same way both times, yet it runs different code. `shape.Area()` follows the note to the `Area` of whatever type is inside right now: ```mermaid flowchart LR invoke["`shape.Area()`"] --> note{"Which type is
inside `shape` now?"} note -- "a `Circle`" --> c["`Circle`'s `Area`
`3.14 × radius × radius`"] note -- "a `Rectangle`" --> r["`Rectangle`'s `Area`
`width × height`"] c --> result["a `float64`"] r --> result ``` Choosing the function while the program runs, by the value inside rather than by anything written at the call, is called **dynamic dispatch**. Compare it with a call on a concrete type: | Call | Type of the receiver | Which `Area` runs is decided | | -------------- | -------------------- | ---------------------------------------------- | | `wheel.Area()` | `Circle` | when the program is compiled — always Circle's | | `shape.Area()` | `Shape` | while it runs — by the value inside | ## Many types in one array An array needs one element type, so a circle and a rectangle cannot share one directly. Two `Shape`s can: ```rux let shapes: Shape[2] = [wheel, door]; var total = 0.0; for each in shapes { total += each.Area(); } PrintLine("total area {}", total); ``` The annotation `Shape[2]` makes each element a `Shape`, exactly as `var shape: Shape` did. The loop then calls `Area` on every element without knowing, or caring, which shape it is: 12.56 + 2.0 = 14.56. ## A copy, not a view ```rux // An interface value holds a copy. Changing the original afterwards leaves the copy alone. var balloon = Circle { radius: 1.0 }; let photo: Shape = balloon; balloon.radius = 2.0; PrintLine("the balloon's area is {}, the photo's is {}", balloon.Area(), photo.Area()); ``` The balloon grows to an area of 12.56, but the photo still shows the radius-1 circle it was given, 3.14. The [Copy](https://rux-lang.dev/docs/learn/copy) rules apply as they would to any assignment. The next lesson, [Interface parameter](https://rux-lang.dev/docs/learn/interface-parameter), shows how to *borrow* a value through an interface instead. ## Only the promise is visible Through a `Shape`, you can reach only what `Shape` promises. Even while a rectangle is inside, `shape.width` is rejected with `error: interface type 'Shape' has no member 'width'`, and a method of Rectangle's own, such as `IsSquare` from the previous lesson, is refused the same way. The variable might hold a circle the next time that line runs, and a circle has neither. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Interfaces/InterfaceValue){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // A variable can have an interface as its type. `let shape: Shape = wheel;` makes an interface // value: it holds a copy of the circle, together with a note of which type that copy is. // // A call such as `shape.Area()` follows the note to Circle's own `Area`. Put a rectangle in the // same variable and the very same call runs Rectangle's `Area` instead. Which function runs is // decided while the program runs, by the value inside, not by anything written at the call. That // is called dynamic dispatch, and it is what lets values of different types share one variable, // one array, or one loop. import Io::PrintLine; interface Shape { func Area() -> float64; func Name() -> char8[..]; } struct Circle { radius: float64; } struct Rectangle { width: float64; height: float64; } extend Circle : Shape { func Area(self: &Circle) -> float64 { return 3.14 * self.radius * self.radius; } func Name(self: &Circle) -> char8[..] { return "circle"; } } extend Rectangle : Shape { func Area(self: &Rectangle) -> float64 { return self.width * self.height; } func Name(self: &Rectangle) -> char8[..] { return "rectangle"; } } func Main() -> int { let wheel = Circle { radius: 2.0 }; let door = Rectangle { width: 1.0, height: 2.0 }; // The annotation is what turns a circle into a Shape. var shape: Shape = wheel; PrintLine("holding a {} with area {}", shape.Name(), shape.Area()); // Same variable, different type inside, so the same calls now run Rectangle's code. shape = door; PrintLine("holding a {} with area {}", shape.Name(), shape.Area()); // A circle and a rectangle cannot share an array: `let shapes = [wheel, door];` is refused // with "array element 2 has type 'Rectangle', but element 1 established element type // 'Circle'". Two Shapes can, and the annotation makes each element a Shape, as it did above. let shapes: Shape[2] = [wheel, door]; var total = 0.0; for each in shapes { total += each.Area(); } PrintLine("total area {}", total); // An interface value holds a copy. Changing the original afterwards leaves the copy alone. var balloon = Circle { radius: 1.0 }; let photo: Shape = balloon; balloon.radius = 2.0; PrintLine("the balloon's area is {}, the photo's is {}", balloon.Area(), photo.Area()); // Only what Shape promises can be reached through it. `shape.width` is rejected even while a // rectangle is inside: "interface type 'Shape' has no member 'width'". return 0; } ``` ## Run it ```sh cd Examples/Interfaces/InterfaceValue rux run ``` ```text holding a circle with area 12.56 holding a rectangle with area 2.0 total area 14.56 the balloon's area is 12.56, the photo's is 3.14 ``` ## Common mistakes ::mistake **Leaving out the annotation.**:br`var shape = wheel;` makes `shape` a `Circle`, and `shape = door;` then fails with: ```text error: cannot assign 'Rectangle' to 'Circle' ``` Write `var shape: Shape = wheel;` to ask for an interface value. :: ::mistake **Mixing types in an unannotated array.**:br`let shapes = [wheel, door];` takes its element type from the first element and is refused with: ```text error: array element 2 has type 'Rectangle', but element 1 established element type 'Circle' ``` Annotate it as `Shape[2]`. :: ::mistake **Reaching past the interface.**:br`shape.width` and `shape.IsSquare()` fail with: ```text error: interface type 'Shape' has no member 'width' error: interface type 'Shape' has no member 'IsSquare' ``` If every shape needs it, add it to the interface; otherwise call it on a `Rectangle`. :: ::mistake **Expecting the interface value to follow the original.**:br An interface value holds a copy. Changing `balloon` afterwards does not change `photo`. :: ## Try it yourself 1. Add a `Triangle` that keeps the `Shape` promise, and put it in the array as a third element. What does the annotation become? 2. Loop over the array and print the name of the shape with the largest area. 3. In the balloon example, assign `balloon` to `photo` *after* changing the radius. Predict the output, then run it. ## Learn more - [Interface implementation](https://rux-lang.dev/docs/lang/interfaces/overview#implementing-an-interface) in the Rux Reference - [Copy](https://rux-lang.dev/docs/learn/copy) — why an interface value is a separate copy - [Interface parameter](https://rux-lang.dev/docs/learn/interface-parameter) — borrowing through an interface instead of copying - [Sum type](https://rux-lang.dev/docs/learn/sum-type) — the other way to hold "one of several types", when the list of types is fixed # Interface parameter ::note **You'll need**: [Interface value](https://rux-lang.dev/docs/learn/interface-value), [Mutable reference](https://rux-lang.dev/docs/learn/mutable-reference), [Mutating method](https://rux-lang.dev/docs/learn/mutating-method) :: The [Interface value](https://rux-lang.dev/docs/learn/interface-value) lesson stored a copy of a shape. Often you want something else: a function that works on the caller's *own* value, whatever its type, as long as it keeps a promise. A parameter written `&Gauge` or `&var Gauge` does exactly that. It borrows, as `&T` did in [Reference](https://rux-lang.dev/docs/learn/reference), and it accepts any type that implements `Gauge`. ## A function for any gauge ```rux // Only reads, so a shared borrow is enough. func Show(gauge: &Gauge) { PrintLine("the {} reads {}", gauge.Label(), gauge.Read()); } ``` `Show` never learns whether it was handed a thermostat or a volume knob. It calls `Label` and `Read`, and dynamic dispatch runs the right type's code. The caller passes its own variable, with no `&` and no conversion — the conversion to the interface happens at the call: ```rux Show(heating); Show(music); ``` Nothing is copied: `Show` sees the caller's value as it is right now. ## Requirements that write Turning a gauge up changes it, and the interface has to say so: ```rux interface Gauge { func Label() -> char8[..]; func Read() -> int32; func Adjust(self: &var Self, amount: int32); } ``` A requirement with no `self` only reads the value. One that changes it declares `self: &var Self`, where `Self` stands for whichever type implements the interface. Each implementation then takes `&var` of its own type, as in [Mutating method](https://rux-lang.dev/docs/learn/mutating-method): ```rux // A volume knob stops at 10, however far it is turned. func Adjust(self: &var Volume, amount: int32) { self.level += amount; if self.level > 10 { self.level = 10; } } ``` | Requirement in `Gauge` | Implementation's receiver | Callable through | | ---------------------------------------------- | ------------------------- | ------------------------- | | `func Read() -> int32;` | `self: &Thermostat` | `&Gauge` and `&var Gauge` | | `func Adjust(self: &var Self, amount: int32);` | `self: &var Thermostat` | `&var Gauge` only | ## Changes reach the caller To call `Adjust`, the parameter must be a writable borrow: ```rux func TurnUp(gauge: &var Gauge, amount: int32) { gauge.Adjust(amount); } ``` ```mermaid flowchart LR caller["`var heating`
(a `Thermostat`)"] -- "`TurnUp(heating, 5)`
borrowed as `&var Gauge`" --> invoke["`gauge.Adjust(5)`"] invoke -- "dispatch" --> impl["`Thermostat`'s `Adjust`"] impl -- "writes through the borrow" --> caller ``` Each type's own `Adjust` runs: the thermostat goes from 19 to 24, while the knob, turned from 7 by 5, stops at 10. And the last line, `heating.degrees is now 24`, proves the change landed on the caller's variable itself, not on a copy. Side by side with the previous lesson: | Written | What the code gets | Can it change the original? | | ----------------------------- | ------------------ | --------------------------- | | `let photo: Shape = balloon;` | a copy | no — it has its own copy | | `gauge: &Gauge` | a read-only borrow | no | | `gauge: &var Gauge` | a writable borrow | yes | ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Interfaces/InterfaceParameter){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // A function can ask for an interface instead of a concrete type, and then any type that keeps // the promise may be passed to it. The caller hands over its own thermostat or volume knob, and // the conversion to the interface happens at the call. // // Written with `&`, the parameter borrows, exactly as `&T` did in the Reference lesson: nothing is // copied, and the function sees the caller's value as it is right now. Written with `&var`, the // borrow is writable, so a change made through the interface lands on the caller's own variable. // // The interface has to say which of its requirements write. A requirement with no `self` only // reads the value; one that changes it declares `self: &var Self`, where `Self` stands for // whichever type implements the interface. Leave that out and every `Adjust` below is refused: // "method 'Adjust' of 'Thermostat' writes through its receiver, but requirement 'Adjust' of // interface 'Gauge' only reads it". import Io::PrintLine; interface Gauge { func Label() -> char8[..]; func Read() -> int32; func Adjust(self: &var Self, amount: int32); } struct Thermostat { degrees: int32; } struct Volume { level: int32; } extend Thermostat : Gauge { func Label(self: &Thermostat) -> char8[..] { return "thermostat"; } func Read(self: &Thermostat) -> int32 { return self.degrees; } // Adjusting changes the value, so this method takes `&var` self. func Adjust(self: &var Thermostat, amount: int32) { self.degrees += amount; } } extend Volume : Gauge { func Label(self: &Volume) -> char8[..] { return "volume"; } func Read(self: &Volume) -> int32 { return self.level; } // A volume knob stops at 10, however far it is turned. func Adjust(self: &var Volume, amount: int32) { self.level += amount; if self.level > 10 { self.level = 10; } } } // Only reads, so a shared borrow is enough. func Show(gauge: &Gauge) { PrintLine("the {} reads {}", gauge.Label(), gauge.Read()); } // Calls `Adjust`, which changes the value, so the borrow must be writable too. Written as // `gauge: &Gauge`, the call below is refused: "cannot call 'Adjust' through immutable reference // '&Gauge'". func TurnUp(gauge: &var Gauge, amount: int32) { gauge.Adjust(amount); } func Main() -> int { var heating = Thermostat { degrees: 19 }; var music = Volume { level: 7 }; Show(heating); Show(music); // Each type's own `Adjust` runs: the knob stops at 10, the thermostat does not. TurnUp(heating, 5); TurnUp(music, 5); // The changes were made to these very variables, not to copies of them. Show(heating); Show(music); PrintLine("heating.degrees is now {}", heating.degrees); // A writable borrow needs a writable variable. Declare `heating` with `let` and the call is // refused: "argument 1 to 'TurnUp' cannot borrow immutable 'heating' as '&var Gauge'". return 0; } ``` ## Run it ```sh cd Examples/Interfaces/InterfaceParameter rux run ``` ```text the thermostat reads 19 the volume reads 7 the thermostat reads 24 the volume reads 10 heating.degrees is now 24 ``` ## Common mistakes ::mistake **A requirement that does not say it writes.**:br Declare `Adjust` in the interface as `func Adjust(amount: int32);` and every implementation is refused: ```text error: method 'Adjust' of 'Thermostat' writes through its receiver, but requirement 'Adjust' of interface 'Gauge' only reads it ``` Add `self: &var Self` to the requirement. :: ::mistake **Calling a writing method through a read-only borrow.**:br With `gauge: &Gauge`, the call `gauge.Adjust(amount)` fails with: ```text error: cannot call 'Adjust' through immutable reference '&Gauge' ``` A function that changes the value needs `&var Gauge`. :: ::mistake **Passing a `let` variable to a `&var` parameter.**:br A writable borrow needs a writable variable. Declare `heating` with `let` and `TurnUp(heating, 5)` fails with: ```text error: argument 1 to 'TurnUp' cannot borrow immutable 'heating' as '&var Gauge' ``` `Show(heating)` still works, because it only reads. :: ## Try it yourself 1. Add a `Fan` with a `speed` that keeps the `Gauge` promise, and whose `Adjust` never lets the speed drop below 0. Turn it down by 5 from 3. 2. Write `func Reset(gauge: &var Gauge)` that brings any gauge back to 0 using only `Read` and `Adjust`. 3. Declare `music` with `let`. Which calls in `Main` still compile, and why? ## Learn more - [Mutable reference](https://rux-lang.dev/docs/learn/mutable-reference) — `&var` for concrete types - [Mutating method](https://rux-lang.dev/docs/learn/mutating-method) — `self: &var T` - [Display](https://rux-lang.dev/docs/learn/display) — a standard interface whose method takes a `&var TextWriter` parameter - [Interfaces](https://rux-lang.dev/docs/lang/interfaces/overview) in the Rux Reference # Display ::note **You'll need**: [Interface parameter](https://rux-lang.dev/docs/learn/interface-parameter), [Unit fallible](https://rux-lang.dev/docs/learn/unit-fallible), [Propagate](https://rux-lang.dev/docs/learn/propagate) :: `PrintLine("{}", value)` has printed numbers, text and booleans since the very first lessons. That is not special treatment for built-in types: each of them implements one interface, `Display` from the Text package. A type of your own prints the same way as soon as it implements `Display` too. This lesson gives a `Money` type the text `$12.05`. ## The Display interface `Display` asks for a single method. In the Text package it is declared as: ```rux func WriteDisplay(writer: &var TextWriter, spec: FormatSpec) -> ! FormatError; ``` | Part | What it is | | ------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `writer: &var TextWriter` | Wherever the text is going — the console, a string, a buffer. An [interface parameter](https://rux-lang.dev/docs/learn/interface-parameter), borrowed writable because writing moves it along. | | `spec: FormatSpec` | What the placeholder asked for, such as the width in `{:>8}`. | | `-> ! FormatError` | Writing can fail — the console may be closed, a buffer may be full — so the method is a [unit fallible](https://rux-lang.dev/docs/learn/unit-fallible). | These names come from two packages, so the lesson imports them, and its `Rux.toml` lists `Format` and `Text`: ```rux import Format::WriteFormat; import Io::PrintLine; import Text::{ Display, FormatError, FormatSpec, TextWriter, WriteBytes }; ``` ## Writing the text ```rux extend Money : Display { // `spec` carries what the placeholder asked for, such as the width in `{:>8}`. This // implementation ignores it, which a type is free to do. func WriteDisplay(self: &Money, writer: &var TextWriter, spec: FormatSpec) -> ! FormatError { var cents = self.cents; if cents < 0 { // One write that may fail. `?` hands a failure to the caller and stops here. WriteBytes(writer, "-")?; cents = -cents; } // `WriteFormat` is PrintLine's twin: the same placeholders, written into the writer. // `{:02}` pads the cents to two digits with zeros, so 5 cents shows as `05`. return WriteFormat(writer, "${}.{:02}", cents / 100, cents % 100); } } ``` The method is built from two writes, and either may fail: - `WriteBytes(writer, "-")?` writes the minus sign. The `?` from [Propagate](https://rux-lang.dev/docs/learn/propagate) passes a failure straight back to the caller and stops there. - `return WriteFormat(…)` writes the rest and hands back whatever that write reported — success or failure. `WriteFormat` takes the same placeholders as `PrintLine`. Here `{:02}` pads the cents to two digits, so 5 cents becomes `05` and the coin prints as `$0.05`. ## What happens when you print ```mermaid flowchart LR p["`PrintLine` with a `{}`
and a `Money`"] --> d["`Money`'s `WriteDisplay`"] d --> w1["`WriteBytes`: `'-'`
(only when negative)"] w1 --> w2["`WriteFormat`: `'$12.05'`"] w2 --> out["the console"] w1 -.->|"a failed write
returns early"| p ``` `PrintLine` checks every argument against `Display` — its arguments are, in effect, a list of interface values. Money now passes, so it goes into a placeholder like any number would: ```rux PrintLine("price: {}", price); PrintLine("refund: {}", refund); PrintLine("coin: {}", coin); PrintLine("{} back from {}", refund, price); ``` ## Ignoring the spec `spec` carries the placeholder's width, alignment, fill and precision. Money ignores it, which a type is free to do, but it has a visible effect: `PrintLine("[{:>10}]", price)` prints `[$12.05]` with no padding, because nothing in `WriteDisplay` applies the width. The [Format](https://rux-lang.dev/docs/learn/format) lesson covers what those placeholder options mean. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Interfaces/Display){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // `PrintLine("{}", value)` prints numbers, text and booleans because each of those types // implements one interface, `Display` from the Text package. A type of your own prints the same // way as soon as it implements `Display` too. // // `Display` asks for a single method, `WriteDisplay`. It is handed a writer, which stands for // wherever the text is going, and it writes the value's text into it. Writing can fail (the // console may be closed, a buffer may be full), so the method returns `! FormatError`, and a // failure from any step is passed straight on with `?` or `return`. import Format::WriteFormat; import Io::PrintLine; import Text::{ Display, FormatError, FormatSpec, TextWriter, WriteBytes }; // An amount of money, kept as whole cents so nothing is lost to rounding. struct Money { cents: int64; } extend Money : Display { // `spec` carries what the placeholder asked for, such as the width in `{:>8}`. This // implementation ignores it, which a type is free to do. func WriteDisplay(self: &Money, writer: &var TextWriter, spec: FormatSpec) -> ! FormatError { var cents = self.cents; if cents < 0 { // One write that may fail. `?` hands a failure to the caller and stops here. WriteBytes(writer, "-")?; cents = -cents; } // `WriteFormat` is PrintLine's twin: the same placeholders, written into the writer. // `{:02}` pads the cents to two digits with zeros, so 5 cents shows as `05`. return WriteFormat(writer, "${}.{:02}", cents / 100, cents % 100); } } func Main() -> int { let price = Money { cents: 1205 }; let refund = Money { cents: -350 }; let coin = Money { cents: 5 }; // Now Money goes into a placeholder like any number would. PrintLine("price: {}", price); PrintLine("refund: {}", refund); PrintLine("coin: {}", coin); PrintLine("{} back from {}", refund, price); // Take away the `extend` and every line above is refused, the first with "no matching // overload for 'PrintLine' with argument types (char8[..], Money)". return 0; } ``` Besides `Io`, its `Rux.toml` lists `Format` and `Text` under `[Dependencies]`. ## Run it ```sh cd Examples/Interfaces/Display rux run ``` ```text price: $12.05 refund: -$3.50 coin: $0.05 -$3.50 back from $12.05 ``` ## Common mistakes ::mistake **Printing a type that does not implement Display.**:br Take away the `extend` and every `PrintLine` with a `Money` in it is refused: ```text error: no matching overload for 'PrintLine' with argument types (char8[..], Money) ``` :: ::mistake **Dropping a write's result.**:br`WriteBytes(writer, "-");` without the `?` fails with: ```text error: fallible result of type '! FormatError' is discarded ``` Every write can fail, so each one is either passed on with `?` or returned. :: ::mistake **Forgetting the `return` on the last write.**:br`WriteFormat(writer, …);` on its own line is a discarded fallible too, with the same error. Write `return WriteFormat(…);`, so its success or failure becomes the method's own. :: ## Try it yourself 1. Give `struct Point { x: int32; y: int32; }` a `Display` that prints `(1, 2)`. 2. Print `price` with `PrintLine("[{:>10}]", price)` and explain why no padding appears. 3. Make a `Temperature` with a `celsius: int32` field print as `21 C`, and `-4 C` below zero. ## Learn more - [Format](https://rux-lang.dev/docs/learn/format) — widths, alignment and fill in placeholders - [Render](https://rux-lang.dev/docs/learn/render) — formatting into a `String` you keep - [Propagate](https://rux-lang.dev/docs/learn/propagate) — the `?` used on each write - The [Text](https://rux-lang.dev/docs/api/text) and [Format](https://rux-lang.dev/docs/api/format) packages in the API reference # Equatable ::note **You'll need**: [Interface](https://rux-lang.dev/docs/learn/interface), [Reference](https://rux-lang.dev/docs/learn/reference) :: Two values can be "the same" in more than one sense. The fractions 1/2 and 2/4 are written differently, yet they stand for the same number, and a program that calls them different will give wrong answers. `Equatable`, from the Core package, is the interface a type implements to say what equality means for it — once, in one place, so that every search and every comparison agrees. ## The Equatable interface `Equatable` asks for one method. In Core it is declared as: ```rux func Equals(other: &Self) -> bool; ``` `Self` stands for whichever type is implementing it, so a `Fraction` is only ever compared with another `Fraction`. The lesson imports it with `import Core::Equatable;`, and its `Rux.toml` lists `Core` under `[Dependencies]`. ```rux extend Fraction : Equatable { // Cross-multiplying compares the two numbers without dividing, so no remainder is lost: // 1/2 and 2/4 are equal because 1 * 4 == 2 * 2. func Equals(self: &Fraction, other: &Fraction) -> bool { return self.top * other.bottom == other.top * self.bottom; } } ``` With integers, dividing would make 1/2 and 1/3 both 0 — and so "equal". Cross-multiplying keeps everything whole: two fractions `a/b` and `c/d` are equal exactly when `a × d` equals `c × b`. ```rux PrintLine("1/2 equals 2/4: {}", half.Equals(twoQuarters)); PrintLine("1/2 equals 1/3: {}", half.Equals(third)); ``` ## Three promises Implementing `Equatable` is also a promise about how `Equals` behaves, and any code relying on it is entitled to assume all three: | Promise | In words | Checked in the program by | | ----------------------------- | -------------------------------------- | ------------------------------------------------------ | | Every value equals itself | 1/2 is 1/2 | `half.Equals(half)` | | The order does not matter | if 1/2 equals 2/4, then 2/4 equals 1/2 | `half.Equals(twoQuarters) == twoQuarters.Equals(half)` | | Equality passes along a chain | 1/2 = 2/4 and 2/4 = 4/8, so 1/2 = 4/8 | the three `Equals` calls joined with `&&` | A search, a duplicate check or a hash table relies on these without asking. A type that cannot keep them should not implement `Equatable` at all. Core's own documentation gives the example of a floating-point NaN, which does not even equal itself. ## One meaning, used everywhere Because the meaning is settled once, every loop that asks agrees with it: ```rux let pile: Fraction[4] = [third, twoQuarters, fourEighths, half]; var halves = 0; for each in pile { if each.Equals(half) { halves += 1; } } ``` `twoQuarters`, `fourEighths` and `half` itself all count, so the pile holds 3 halves. ## Equals is not == `Equals` is a method, not the `==` operator, and implementing `Equatable` leaves `==` exactly as it was. That is easy to trip over: `half == twoQuarters` still compiles, but it compares the fields one by one — 1 against 2, 2 against 4 — and answers `false`. The [Structural equality](https://rux-lang.dev/docs/learn/structural-equality) lesson explains that field-by-field `==`, and [Operator overload](https://rux-lang.dev/docs/learn/operator-overload) shows how a type gives `==` a meaning of its own. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Interfaces/Equatable){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // Two values can be "the same" in more than one sense. The fractions 1/2 and 2/4 are written // differently, yet they stand for the same number, and a program that calls them different will // give wrong answers. // // `Equatable`, from Core, is the interface a type implements to say what equality means for it. // It asks for one method, `Equals(other: &Self) -> bool`. `Self` stands for whichever type is // implementing it, so a Fraction is only ever compared with another Fraction. // // Implementing it is also a promise about how `Equals` behaves, which any code relying on it is // entitled to assume: // - every value equals itself; // - `a.Equals(b)` and `b.Equals(a)` always agree; // - if a equals b, and b equals c, then a equals c. import Core::Equatable; import Io::PrintLine; struct Fraction { top: int32; bottom: int32; } extend Fraction : Equatable { // Cross-multiplying compares the two numbers without dividing, so no remainder is lost: // 1/2 and 2/4 are equal because 1 * 4 == 2 * 2. func Equals(self: &Fraction, other: &Fraction) -> bool { return self.top * other.bottom == other.top * self.bottom; } } func Main() -> int { let half = Fraction { top: 1, bottom: 2 }; let twoQuarters = Fraction { top: 2, bottom: 4 }; let fourEighths = Fraction { top: 4, bottom: 8 }; let third = Fraction { top: 1, bottom: 3 }; PrintLine("1/2 equals 2/4: {}", half.Equals(twoQuarters)); PrintLine("1/2 equals 1/3: {}", half.Equals(third)); // The three promises, checked on these values. PrintLine("itself: {}", half.Equals(half)); PrintLine("either way: {}", half.Equals(twoQuarters) == twoQuarters.Equals(half)); PrintLine("in a chain: {}", half.Equals(twoQuarters) && twoQuarters.Equals(fourEighths) && half.Equals(fourEighths)); // Because the meaning is settled once, in one place, every search agrees with it. let pile: Fraction[4] = [third, twoQuarters, fourEighths, half]; var halves = 0; for each in pile { if each.Equals(half) { halves += 1; } } PrintLine("halves in the pile: {}", halves); // `Equals` is a method, not the `==` operator. Implementing Equatable leaves `==` exactly as // it was; the lessons on structural equality and operator overloading cover `==`. return 0; } ``` Besides `Io`, its `Rux.toml` lists `Core` under `[Dependencies]`. ## Run it ```sh cd Examples/Interfaces/Equatable rux run ``` ```text 1/2 equals 2/4: true 1/2 equals 1/3: false itself: true either way: true in a chain: true halves in the pile: 3 ``` ## Common mistakes ::mistake **Expecting `==` to call `Equals`.**:br`half == twoQuarters` is `false`, while `half.Equals(twoQuarters)` is `true`. The operator compares fields; the method uses your definition. Call `Equals` when you mean it. :: ::mistake **Forgetting the import.**:br Without `import Core::Equatable;`, the `extend` line fails with: ```text error: interface 'Equatable' is not defined ``` Core must also be listed in `Rux.toml`. :: ::mistake **Comparing with a different type.**:br`Self` means a `Fraction` compares only with a `Fraction`. `half.Equals(5)` fails with: ```text error: argument 1 to 'Equals' has type 'int', but parameter 'other' requires '&Fraction' ``` :: ## Try it yourself 1. Is `Fraction { top: -1, bottom: -2 }` equal to `half`? Work it out by cross-multiplying, then check. 2. Consider `Fraction { top: 0, bottom: 0 }`. Compare it with `half` and with `third`. Which of the three promises does it break? 3. Count how many fractions in `pile` equal `third`. ## Learn more - [Comparable](https://rux-lang.dev/docs/learn/comparable) — the next step: not just "equal?", but "which comes first?" - [Structural equality](https://rux-lang.dev/docs/learn/structural-equality) — what `==` does on a struct - [Reference](https://rux-lang.dev/docs/learn/reference) — the `&` in `other: &Self` - The [Core](https://rux-lang.dev/docs/api/core) package in the API reference # Comparable ::note **You'll need**: [Equatable](https://rux-lang.dev/docs/learn/equatable), [Enum](https://rux-lang.dev/docs/learn/enum), [Match expression](https://rux-lang.dev/docs/learn/match-expression) :: [Equatable](https://rux-lang.dev/docs/learn/equatable) answers "are these the same?". Sorting, searching and finding the largest need a different question: **which of two comes first?** `Comparable`, from the Core package, is the interface a type implements to answer it. Release numbers show why a type may need an order of its own. As text, "1.10.0" sorts before "1.9.4", because the character `1` comes before `9`. Compared part by part, as numbers, 1.10.0 is the newer release. ## Ordering: three answers in one `Comparable` asks for one method. In Core it is declared as: ```rux func Compare(other: &Self) -> Ordering; ``` The answer is not a `bool` but an `Ordering`, an [enum](https://rux-lang.dev/docs/learn/enum) from Core with three cases. One call answers "before, same or after?", where a `bool` would need two questions to tell "after" from "the same". | Case | Means | | ------------------- | --------------------------- | | `Ordering::Less` | this value comes first | | `Ordering::Equal` | neither comes first | | `Ordering::Greater` | the other value comes first | `Ordering` has small methods that ask about the answer: `IsLess`, `IsEqual`, `IsGreater`, `IsLessOrEqual` and `IsGreaterOrEqual`, plus `Reverse`, which swaps `Less` and `Greater`. The program uses two of them. Both names are imported with `import Core::{ Comparable, Ordering };`. ## Comparing part by part A helper orders two plain numbers: ```rux // Orders two numbers. Release compares its three parts with it. func CompareNumbers(left: int32, right: int32) -> Ordering { if left < right { return Ordering::Less; } if left > right { return Ordering::Greater; } return Ordering::Equal; } ``` `Release` then compares its parts in order of importance, and the first part that differs decides: ```rux extend Release : Comparable { // The first part that differs decides; a later part matters only on a tie. func Compare(self: &Release, other: &Release) -> Ordering { let major = CompareNumbers(self.major, other.major); if !major.IsEqual() { return major; } let minor = CompareNumbers(self.minor, other.minor); if !minor.IsEqual() { return minor; } return CompareNumbers(self.patch, other.patch); } } ``` ```mermaid flowchart LR major{"`major`
differs?"} -- "yes" --> a1["that answer"] major -- "no, a tie" --> minor{"`minor`
differs?"} minor -- "yes" --> a2["that answer"] minor -- "no, a tie" --> patch["compare `patch`:
its answer is final"] ``` For 1.9.4 against 1.10.0, the majors tie at 1, and the minors decide: 9 is less than 10, so the answer is `Less` and patch is never looked at. ## Turning an answer into words A [match expression](https://rux-lang.dev/docs/learn/match-expression) maps each case to a phrase, and the compiler checks that all three are covered: ```rux func Describe(order: Ordering) -> char8[..] { return match order { .Less => "older than", .Equal => "the same as", .Greater => "newer than" }; } ``` ## Finding the newest ```rux var newest = releases[0]; for each in releases { if each.Compare(newest).IsGreater() { newest = each; } } ``` Keep whichever compares greater, and after the loop `newest` is 2.0.1. Sorting works on the same idea: the [Sort](https://rux-lang.dev/docs/learn/sort) lesson's `SortBy` takes a function that answers with an `Ordering`. ## The promise As with `Equatable`, implementing `Comparable` is a promise. For any pair exactly one of the three answers holds; swapping the two sides swaps `Less` and `Greater`; and if a comes before b and b before c, then a comes before c. A type that implements both interfaces should also keep them in step: `Compare` says `Equal` exactly when `Equals` says `true`. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Interfaces/Comparable){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // `Comparable`, from Core, is the interface a type implements to say how its values are ordered: // which of two comes first. It asks for one method: // func Compare(other: &Self) -> Ordering // The answer is not a `bool` but an `Ordering`, an enum from Core with three cases: `Less`, // `Equal` and `Greater`. One call answers "before, same or after?", where a `bool` would need two // questions to tell "after" from "the same". // // Release numbers show why a type may need its own order. As text, "1.10.0" sorts before "1.9.4", // because the character 1 comes before 9. Compared part by part, as numbers, 1.10.0 is newer. // // The promise that comes with Comparable: exactly one of the three answers holds for any pair, // swapping the two sides swaps `Less` and `Greater`, and if a < b and b < c then a < c. import Core::{ Comparable, Ordering }; import Io::PrintLine; struct Release { major: int32; minor: int32; patch: int32; } // Orders two numbers. Release compares its three parts with it. func CompareNumbers(left: int32, right: int32) -> Ordering { if left < right { return Ordering::Less; } if left > right { return Ordering::Greater; } return Ordering::Equal; } extend Release : Comparable { // The first part that differs decides; a later part matters only on a tie. func Compare(self: &Release, other: &Release) -> Ordering { let major = CompareNumbers(self.major, other.major); if !major.IsEqual() { return major; } let minor = CompareNumbers(self.minor, other.minor); if !minor.IsEqual() { return minor; } return CompareNumbers(self.patch, other.patch); } } func Describe(order: Ordering) -> char8[..] { return match order { .Less => "older than", .Equal => "the same as", .Greater => "newer than" }; } func Main() -> int { let old = Release { major: 1, minor: 9, patch: 4 }; let fresh = Release { major: 1, minor: 10, patch: 0 }; PrintLine("1.9.4 is {} 1.10.0", Describe(old.Compare(fresh))); PrintLine("1.10.0 is {} 1.9.4", Describe(fresh.Compare(old))); PrintLine("1.9.4 is {} 1.9.4", Describe(old.Compare(old))); // Finding the newest: keep whichever compares greater. let releases: Release[4] = [old, Release { major: 2, minor: 0, patch: 1 }, fresh, Release { major: 2, minor: 0, patch: 0 }]; var newest = releases[0]; for each in releases { if each.Compare(newest).IsGreater() { newest = each; } } PrintLine("newest: {}.{}.{}", newest.major, newest.minor, newest.patch); return 0; } ``` Besides `Io`, its `Rux.toml` lists `Core` under `[Dependencies]`. ## Run it ```sh cd Examples/Interfaces/Comparable rux run ``` ```text 1.9.4 is older than 1.10.0 1.10.0 is newer than 1.9.4 1.9.4 is the same as 1.9.4 newest: 2.0.1 ``` ## Common mistakes ::mistake **Expecting `<` after implementing Comparable.**:br`Compare` is a method, and implementing `Comparable` adds no operators. `old < fresh` fails with: ```text error: operator '<' is not defined for 'Release' ``` The compiler adds the note "a struct is compared through the operators it declares, never by its representation". Use `old.Compare(fresh).IsLess()`, or declare `<` as in [Operator overload](https://rux-lang.dev/docs/learn/operator-overload). :: ::mistake **Comparing the parts in the wrong order.**:br The compiler cannot catch this one. Compare `patch` first and 1.9.4 comes out newer than 1.10.0, because 4 is greater than 0. The most important part must be compared first, and a later part consulted only on a tie. :: ## Try it yourself 1. Find the *oldest* release in the array, using `IsLess`. 2. Print `old.Compare(fresh).Reverse()` through `Describe`, and compare it with `fresh.Compare(old)`. 3. Implement `Comparable` for `struct Date { year: int32; month: int32; day: int32; }` and sort out which of two birthdays comes first. ## Learn more - [Enum](https://rux-lang.dev/docs/learn/enum) and [Match expression](https://rux-lang.dev/docs/learn/match-expression) — the tools `Ordering` is built from - [Sort](https://rux-lang.dev/docs/learn/sort) and [Tree map](https://rux-lang.dev/docs/learn/tree-map) — standard code that relies on an `Ordering` - [Derived operator](https://rux-lang.dev/docs/learn/derived-operator) — `<`, `>`, `<=` and `>=` on your own type - The [Core](https://rux-lang.dev/docs/api/core) package in the API reference # Structural equality ::note **You'll need**: [Struct](https://rux-lang.dev/docs/learn/struct), [Tuple](https://rux-lang.dev/docs/learn/tuple), [Variant](https://rux-lang.dev/docs/learn/variant), [Comparison](https://rux-lang.dev/docs/learn/comparison) :: `==` and `!=` work on more than numbers. Two structs of the same type can be compared without writing anything at all: they are equal when every field is equal. The same goes for tuples, arrays and variants, and for any mix of them. This is called **structural equality** — equal shape, equal parts, equal values — and it is the right answer for plain data such as points and dates. ## Field by field ```rux let a = Point { x: 1, y: 2 }; let b = Point { x: 1, y: 2 }; let flipped = Point { x: 2, y: 1 }; ``` `a` and `b` are two separate values, but field by field they are the same, so `a == b` is `true`. `flipped` has the same numbers in different fields: `x` is compared with `x` and `y` with `y`, so `a == flipped` is `false` and `a != flipped` is `true`. ## One level down, and the next A field that is itself a struct is compared by the same rule, one level down: ```rux let first = Segment { start: a, end: flipped }; let second = Segment { start: b, end: flipped }; PrintLine("segments: {}", first == second); ``` ```mermaid flowchart LR seg["`first == second`
(`Segment`)"] --> s["`start == start`
(`Point`)"] seg --> e["`end == end`
(`Point`)"] s --> sx["`x`: `1 == 1`"] s --> sy["`y`: `2 == 2`"] e --> ex["`x`: `2 == 2`"] e --> ey["`y`: `1 == 1`"] ``` The comparison only ever bottoms out in values that have their own `==`, such as integers. All four are equal, so the segments are too. ## Tuples, arrays and variants ```rux PrintLine("tuples: {}", (a, true) == (b, true)); let left: int32[3] = [1, 2, 3]; let right: int32[3] = [1, 2, 4]; PrintLine("arrays: {}", left == right); ``` ```rux let warm = Reading::Celsius(21); let alsoWarm = Reading::Celsius(21); let unknown = Reading::Missing; ``` | Kind of value | Equal when | Example in the program | | ------------- | ----------------------------------------- | ---------------------------------------------------------- | | Struct | every field is equal, compared in order | `a == b` is `true` | | Tuple | every element is equal | `(a, true) == (b, true)` is `true` | | Array | every element is equal | `[1, 2, 3]` vs `[1, 2, 4]` is `false` | | Variant | the case matches, and so does its payload | `warm == alsoWarm` is `true`, `warm == unknown` is `false` | ## Equality, not order Structural comparison stops at `==` and `!=`. There is no field-by-field `<`: is a point with a bigger `x` but a smaller `y` "less"? The compiler will not guess. `a < b` fails with `error: operator '<' is not defined for 'Point'`, and its note says why: "a struct is compared through the operators it declares, never by its representation". Structural equality also has its limits. As [Equatable](https://rux-lang.dev/docs/learn/equatable) showed, 1/2 and 2/4 have different fields but mean the same number. When a type means something else by "equal", it declares its own `==`, which the next lesson, [Operator overload](https://rux-lang.dev/docs/learn/operator-overload), shows. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Interfaces/StructuralEquality){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // `==` and `!=` work on more than numbers. Two structs of the same type can be compared without // writing anything: they are equal when every field is equal, compared in order. The same goes // for tuples, arrays and variants, and for any mix of them, because comparing a field that is // itself a struct simply repeats the rule one level down. // // This is called structural equality: equal shape, equal parts, equal values. It is the right // answer for plain data such as points and dates. When a type means something else by "equal", // as 1/2 and 2/4 did in the Equatable lesson, it defines its own `==`, which the next lesson // shows. import Io::PrintLine; struct Point { x: int32; y: int32; } struct Segment { start: Point; end: Point; } variant Reading { Missing, Celsius(int32) } func Main() -> int { let a = Point { x: 1, y: 2 }; let b = Point { x: 1, y: 2 }; let flipped = Point { x: 2, y: 1 }; // Two separate values, field by field the same. PrintLine("a == b: {}", a == b); PrintLine("a == flipped: {}", a == flipped); PrintLine("a != flipped: {}", a != flipped); // A struct inside a struct is compared by the same rule. let first = Segment { start: a, end: flipped }; let second = Segment { start: b, end: flipped }; PrintLine("segments: {}", first == second); // Tuples and arrays compare element by element. PrintLine("tuples: {}", (a, true) == (b, true)); let left: int32[3] = [1, 2, 3]; let right: int32[3] = [1, 2, 4]; PrintLine("arrays: {}", left == right); // Variants are equal when the case matches and so does the payload. let warm = Reading::Celsius(21); let alsoWarm = Reading::Celsius(21); let unknown = Reading::Missing; PrintLine("same reading: {}", warm == alsoWarm); PrintLine("vs missing: {}", warm == unknown); // Every part must have its own `==`, and a slice such as `char8[..]` has none. Add a // `name: char8[..]` field to Point and `a == b` is refused: "structural equality for 'Point' // is unavailable because element type 'char8[..]' has no '==' operator". return 0; } ``` ## Run it ```sh cd Examples/Interfaces/StructuralEquality rux run ``` ```text a == b: true a == flipped: false a != flipped: true segments: true tuples: true arrays: false same reading: true vs missing: false ``` ## Common mistakes ::mistake **A field with no `==` of its own.**:br Every part must be comparable, and a slice such as `char8[..]` is not. Add `name: char8[..]` to `Point` and `a == b` is refused: ```text error: structural equality for 'Point' is unavailable because element type 'char8[..]' has no '==' operator ``` The compiler's help suggests the way out: compare the fields you can explicitly, or declare `==` for the type yourself. :: ::mistake **Expecting `<` on a struct.**:br Only `==` and `!=` come for free. `a < b` fails with: ```text error: operator '<' is not defined for 'Point' ``` :: ::mistake **Expecting meaning, not shape.**:br A `Fraction` of 1/2 and one of 2/4 are not `==`, because their fields differ. Field-by-field equality knows nothing about what a type stands for. :: ## Try it yourself 1. Make a third segment with `start` and `end` swapped. Is it `==` to `first`? 2. Add a case `Fahrenheit(int32)` to `Reading` and compare `Reading::Celsius(21)` with `Reading::Fahrenheit(21)`. Predict the answer first. 3. Compare two arrays of `Point`, `Point[2]`, that differ only in their last `y`. ## Learn more - [Comparison](https://rux-lang.dev/docs/learn/comparison) — `==` and `!=` on numbers - [Struct](https://rux-lang.dev/docs/learn/struct), [Tuple](https://rux-lang.dev/docs/learn/tuple) and [Variant](https://rux-lang.dev/docs/learn/variant) — the values compared here - [Operator overload](https://rux-lang.dev/docs/learn/operator-overload) — giving a type its own `==` - [Comparison operators](https://rux-lang.dev/docs/lang/expressions/comparison) in the Rux Reference # Operator overload ::note **You'll need**: [Method](https://rux-lang.dev/docs/learn/method), [Constructor](https://rux-lang.dev/docs/learn/constructor), [Structural equality](https://rux-lang.dev/docs/learn/structural-equality) :: The operators from the [Operators](https://rux-lang.dev/docs/learn/operators) part are not reserved for numbers. A type of your own can say what `+`, `==` or `<` mean for it, by declaring a function whose name is the operator. The point is not cleverness: money adds to money, and `rent + food` says that plainly where `Money { cents: rent.cents + food.cents }` buries it. ## An operator is a function Operator functions go in an ordinary `extend` block, next to the [constructor](https://rux-lang.dev/docs/learn/constructor): ```rux // `self` is the left operand and the second parameter is the right one. Taking the right // operand by value lets it be a value built on the spot, as in `rent == Money(120000)`. // `other: &Money` works as well, but a borrow needs a named value on the right. func +(self: &Money, other: Money) -> Money { return Money { cents: self.cents + other.cents }; } ``` The function's name is the operator itself. When the compiler meets `rent + food` with a `Money` on the left, it calls this function with `self` borrowing `rent` and `other` holding `food`: | You write | The compiler calls | `self` | Right operand | Result | | ----------------------- | ------------------ | ------ | ------------- | ------- | | `rent + food` | `+` | `rent` | `food` | `Money` | | `rent - food` | `-` | `rent` | `food` | `Money` | | `rent * 3` | `*` | `rent` | `3` | `Money` | | `rent == Money(120000)` | `==` | `rent` | a new `Money` | `bool` | | `food < rent` | `<` | `food` | `rent` | `bool` | Once `+` is declared, the compound form works too: `sum += food` adds to a `var sum` of type `Money`. ## The two sides need not match ```rux // The two sides need not have the same type. Money times a count makes sense; money times // money does not, so only this one exists. func *(self: &Money, count: int64) -> Money { return Money { cents: self.cents * count }; } ``` The second parameter's type is whatever the right operand should be. Money times a count makes sense; money times money does not, so `rent * rent` is simply not defined. The order matters as well: `self` is always the *left* operand, so this function makes `rent * 3` work but not `3 * rent`. ## Comparisons answer with bool ```rux // Comparisons answer with `bool`, not with Money. func ==(self: &Money, other: Money) -> bool { return self.cents == other.cents; } func <(self: &Money, other: Money) -> bool { return self.cents < other.cents; } ``` A declared `==` replaces the field-by-field comparison from [Structural equality](https://rux-lang.dev/docs/learn/structural-equality). For `Money` both give the same answer, but a type like the `Fraction` from [Equatable](https://rux-lang.dev/docs/learn/equatable) could now make 1/2 `==` 2/4. And from these two, the compiler can work out `!=`, `>`, `<=` and `>=` — the subject of the next lesson. ## Only what you declare Money has no `/`, so `rent / 2` is an error rather than something invented on Money's behalf. Each operator you leave out is a decision: there is no sensible meaning for money divided by money, and dividing by a count would raise the question of what to do with the leftover cent. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Interfaces/OperatorOverload){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // The operators from the Operators part are not reserved for numbers. A type of your own can say // what `+`, `==` or `<` mean for it, by declaring a function whose name is the operator. // // The point is not cleverness. Money adds to money, and `rent + food` says that plainly where // `Money { cents: rent.cents + food.cents }` buries it. A declared `==` also replaces the // field-by-field comparison from the previous lesson, so a type decides what "equal" means. import Io::PrintLine; // Money as a whole number of cents, so no fraction of a cent ever goes missing. struct Money { cents: int64; } extend Money { func Money(cents: int64) -> Money { return Money { cents: cents }; } // `self` is the left operand and the second parameter is the right one. Taking the right // operand by value lets it be a value built on the spot, as in `rent == Money(120000)`. // `other: &Money` works as well, but a borrow needs a named value on the right. func +(self: &Money, other: Money) -> Money { return Money { cents: self.cents + other.cents }; } func -(self: &Money, other: Money) -> Money { return Money { cents: self.cents - other.cents }; } // The two sides need not have the same type. Money times a count makes sense; money times // money does not, so only this one exists. func *(self: &Money, count: int64) -> Money { return Money { cents: self.cents * count }; } // Comparisons answer with `bool`, not with Money. func ==(self: &Money, other: Money) -> bool { return self.cents == other.cents; } func <(self: &Money, other: Money) -> bool { return self.cents < other.cents; } } func Main() -> int { let rent = Money(120000); let food = Money(35050); // Each operator below calls one of the functions above. let total = rent + food; let left = rent - food; let quarter = rent * 3; PrintLine("rent + food = {} cents", total.cents); PrintLine("rent - food = {} cents", left.cents); PrintLine("rent * 3 = {} cents", quarter.cents); PrintLine("rent == 120000 cents: {}", rent == Money(120000)); PrintLine("food < rent: {}", food < rent); // Only the operators declared exist. Money has no `/`, so `rent / 2` is an error rather // than something invented on Money's behalf. return 0; } ``` ## Run it ```sh cd Examples/Interfaces/OperatorOverload rux run ``` ```text rent + food = 155050 cents rent - food = 84950 cents rent * 3 = 360000 cents rent == 120000 cents: true food < rent: true ``` ## Common mistakes ::mistake **Using an operator that was never declared.**:br`rent / 2` fails with: ```text error: operator '/' cannot combine left operand 'Money' with right operand 'int' ``` Declare `/` if Money should have it. :: ::mistake **Putting the operands the other way round.**:br`*` was declared with `Money` on the left, so `3 * rent` fails with: ```text error: operator '*' cannot combine left operand 'int' with right operand 'Money' ``` Write `rent * 3`. :: ::mistake **Borrowing the right operand.**:br Declare `==` as `func ==(self: &Money, other: &Money) -> bool` and `rent == Money(120000)` fails with: ```text error: cannot pass 'Money' to parameter of type '&Money' ``` A borrow needs a named value, not one built on the spot. Take the right operand by value, as the lesson does. :: ## Try it yourself 1. Declare `/` taking an `int64` count, and print `rent / 3`. What happens to the leftover cent? 2. Use `+=` in a loop to add up an array of `Money` values. 3. Write a `Vector { x: float64; y: float64; }` with `+` for two vectors and `*` for a vector and a `float64`. ## Learn more - [Derived operator](https://rux-lang.dev/docs/learn/derived-operator) — `!=`, `>`, `<=` and `>=` for free - [Arithmetic](https://rux-lang.dev/docs/learn/arithmetic) — the operators on numbers - [Constructor](https://rux-lang.dev/docs/learn/constructor) — the `Money(120000)` used on the right of `==` - [Arithmetic operators](https://rux-lang.dev/docs/lang/expressions/arithmetic) in the Rux Reference # Derived operator ::note **You'll need**: [Operator overload](https://rux-lang.dev/docs/learn/operator-overload) :: There are six comparison operators, but a type declares at most two of them. From `==` the compiler derives `!=`, and from `<` together with `==` it derives the other three. So there is less to write — and, more importantly, the six can never disagree with one another. ## Two declared Players are ranked by score alone, so two players with the same score tie, whatever their names: ```rux extend Player { func ==(self: &Player, other: Player) -> bool { return self.score == other.score; } func <(self: &Player, other: Player) -> bool { return self.score < other.score; } } ``` `Player` could not use field-by-field `==` from [Structural equality](https://rux-lang.dev/docs/learn/structural-equality) at all, because its `name` is a slice. The declared `==` is what makes players comparable in the first place. ## Four derived ```rux PrintLine("Ann != Bob {}", ann != bob); PrintLine("Bob > Ann {}", bob > ann); PrintLine("Ann <= Cy {}", ann <= cy); PrintLine("Ann >= Bob {}", ann >= bob); ``` None of these four operators is declared on `Player`. The compiler rewrites each one in terms of the two that are: | You write | The compiler uses | Ann 7, Bob 9, Cy 7 | | --------- | ----------------- | ----------------------- | | `a != b` | `!(a == b)` | `ann != bob` is `true` | | `a > b` | `b < a` | `bob > ann` is `true` | | `a <= b` | `a < b || a == b` | `ann <= cy` is `true` | | `a >= b` | `b < a || a == b` | `ann >= bob` is `false` | ```mermaid flowchart LR eq["`==` (declared)"] --> ne["`!=`"] lt["`<` (declared)"] --> gt["`>`"] lt --> le["`<=`"] eq --> le lt --> ge["`>=`"] eq --> ge ``` Notice `ann <= cy`: Ann is not less than Cy, but the two tie at 7, so the `==` half makes it `true`. ## Why they cannot disagree If a type wrote all six by hand, a slip in one — `>=` comparing names while `<` compares scores — would make `a >= b` and `a < b` true at once, and any code that sorts or searches would quietly misbehave. Deriving the four from two leaves nothing to slip. A type may still declare one of the derived operators itself, and then its own declaration is used instead. That is rarely a good idea: it is exactly how the six come to disagree. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Interfaces/DerivedOperator){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // There are six comparison operators, but a type declares at most two of them. From `==` the // compiler derives `!=`, and from `<` together with `==` it derives the other three: // a != b means !(a == b) // a > b means b < a // a <= b means a < b || a == b // a >= b means b < a || a == b // So there is less to write, and the six can never disagree with one another. // // A type may still declare one of the derived operators itself, and then its own declaration is // used instead. That is rarely a good idea: it is exactly how the six come to disagree. import Io::PrintLine; // Players are ranked by score alone. Two players with the same score tie, whatever their names. struct Player { name: char8[..]; score: int32; } extend Player { func ==(self: &Player, other: Player) -> bool { return self.score == other.score; } func <(self: &Player, other: Player) -> bool { return self.score < other.score; } } func Main() -> int { let ann = Player { name: "Ann", score: 7 }; let bob = Player { name: "Bob", score: 9 }; let cy = Player { name: "Cy", score: 7 }; // The two that were declared. PrintLine("Ann == Cy {}", ann == cy); PrintLine("Ann < Bob {}", ann < bob); // The four that were derived. PrintLine("Ann != Bob {}", ann != bob); PrintLine("Bob > Ann {}", bob > ann); PrintLine("Ann <= Cy {}", ann <= cy); PrintLine("Ann >= Bob {}", ann >= bob); // Derivation needs something to start from. Delete `<` and `bob > ann` is refused: // "operator '>' is not defined for 'Player'", with the hint "declare '>' on 'Player', or the // '<' it is derived from". And `Player` could not use field-by-field `==` at all, since its // `name` is a slice; the declared `==` is what makes players comparable. return 0; } ``` ## Run it ```sh cd Examples/Interfaces/DerivedOperator rux run ``` ```text Ann == Cy true Ann < Bob true Ann != Bob true Bob > Ann true Ann <= Cy true Ann >= Bob false ``` ## Common mistakes ::mistake **Nothing to derive from.**:br Delete `<` and `bob > ann` is refused with: ```text error: operator '>' is not defined for 'Player' ``` It comes together with the hint "declare '>' on 'Player', or the '<' it is derived from". `ann < bob` fails the same way. :: ::mistake **Deleting `==` from a type that cannot compare its fields.**:br Without the declared `==`, `ann == cy` falls back to structural equality, which `Player` cannot have: ```text error: structural equality for 'Player' is unavailable because element type 'char8[..]' has no '==' operator ``` `!=`, `<=` and `>=` are lost with it. :: ::mistake **Declaring a derived operator that disagrees.**:br A hand-written `!=` replaces the derived one. Declare it to return `true` always, and `ann != cy` and `ann == cy` are both `true`. Leave `!=`, `>`, `<=` and `>=` to the compiler. :: ## Try it yourself 1. Add `let dee = Player { name: "Dee", score: 9 };`. Predict all six comparisons between Bob and Dee, then print them. 2. Which of the six already work on `Money` from the [Operator overload](https://rux-lang.dev/docs/learn/operator-overload) lesson? Try each one. 3. Change the ranking so that a *lower* score is better, as in golf. How many functions did you have to change? ## Learn more - [Operator overload](https://rux-lang.dev/docs/learn/operator-overload) — declaring `==` and `<` in the first place - [Comparable](https://rux-lang.dev/docs/learn/comparable) — ordering through a method that answers with an `Ordering` - [Comparison](https://rux-lang.dev/docs/learn/comparison) — the six operators on numbers - [Comparison operators](https://rux-lang.dev/docs/lang/expressions/comparison) in the Rux Reference # Indexer ::note **You'll need**: [Operator overload](https://rux-lang.dev/docs/learn/operator-overload), [Enum value](https://rux-lang.dev/docs/learn/enum-value), [Mutating method](https://rux-lang.dev/docs/learn/mutating-method) :: Square brackets are an operator too. A type that declares `func []` can be read as `week[day]`, and one that also declares `func []=` can be written as `week[day] = 21`. They are declared in an `extend` block, just like `+` and `==` in [Operator overload](https://rux-lang.dev/docs/learn/operator-overload). The index need not be a number: here a week of temperatures is indexed by the day itself. ## The type underneath ```rux // The highest temperature of each day, stored in an ordinary array. struct Week { highs: int32[7]; } ``` A `Week` is an ordinary array in a struct. The indexer is what lets a reader write `week[Day::Friday]` instead of `week.highs[4]`, and lets the type decide which indexes exist. ## Reading and writing ```rux // Reading: `week[day]` calls this and gives back a copy of the value. func [](self: &Week, day: Day) -> int32 { return self.highs[day as uint]; } // Writing: `week[day] = value` calls this. It changes the week, so it takes `&var` self. func []=(self: &var Week, day: Day, value: int32) { self.highs[day as uint] = value; } ``` `day as uint` turns the enum case into its position, 0 for `Monday` through 6 for `Sunday`, as in [Enum value](https://rux-lang.dev/docs/learn/enum-value). The two functions split the work like this: | You write | The compiler calls | Receiver | Gets | | ------------------------ | ------------------ | ----------------- | ------------------------ | | `week[Day::Friday]` | `[]` | `self: &Week` | the day | | `week[Day::Friday] = 25` | `[]=` | `self: &var Week` | the day and the value 25 | Writing changes the week, so `[]=` takes a `&var` receiver, as a [mutating method](https://rux-lang.dev/docs/learn/mutating-method) does, and `week` must be declared with `var`. ```rux var week = Week { highs: [0; 7] }; week[Day::Monday] = 18; week[Day::Tuesday] = 21; week[Day::Friday] = 25; ``` A day nobody wrote, such as Sunday, still holds the `0` it started with. ## An index that cannot be wrong Because the index is a `Day`, an index the week does not have cannot even be written. `week[9]` is not an out-of-range day caught while the program runs — it is refused when the program is compiled, because a plain number is not a `Day`. The type of the index is part of the design. ## Two separate functions ```rux // Reading and writing are two separate functions, so changing a value in place takes both. week[Day::Friday] = week[Day::Friday] - 3; ``` ```mermaid flowchart LR read["`week[Day::Friday]`
calls `[]` → `25`"] --> sub["`25 - 3 = 22`"] sub --> write["`week[Day::Friday] = 22`
calls `[]=`"] ``` The right-hand side reads through `[]`, and the assignment writes through `[]=`. Neither function both reads and writes, which is why the shorter `week[Day::Friday] -= 3` is refused (see below). ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Interfaces/Indexer){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // Square brackets are an operator too. A type that declares `func []` can be read as `week[day]`, // and one that also declares `func []=` can be written as `week[day] = 21`. They are declared in // an `extend` block like `+` and `==` were. // // The index need not be a number. Here a week of temperatures is indexed by day, so a reader sees // `week[Day::Friday]`, and an index the week does not have, such as 9, cannot even be written: // a plain number is not a `Day`. import Io::PrintLine; enum Day { Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday } // The highest temperature of each day, stored in an ordinary array. struct Week { highs: int32[7]; } extend Week { // Reading: `week[day]` calls this and gives back a copy of the value. func [](self: &Week, day: Day) -> int32 { return self.highs[day as uint]; } // Writing: `week[day] = value` calls this. It changes the week, so it takes `&var` self. func []=(self: &var Week, day: Day, value: int32) { self.highs[day as uint] = value; } } func Main() -> int { var week = Week { highs: [0; 7] }; week[Day::Monday] = 18; week[Day::Tuesday] = 21; week[Day::Friday] = 25; PrintLine("Monday {}, Tuesday {}, Friday {}", week[Day::Monday], week[Day::Tuesday], week[Day::Friday]); // Reading and writing are two separate functions, so changing a value in place takes both. week[Day::Friday] = week[Day::Friday] - 3; PrintLine("Friday, corrected: {}", week[Day::Friday]); // A day nobody wrote still holds the zero it started with. PrintLine("Sunday {}", week[Day::Sunday]); // Writing `week[Day::Friday] -= 3` is refused, because no single function both reads and // writes: "operator '-=' cannot read and write through the '[]' operator on 'Week' at once". return 0; } ``` ## Run it ```sh cd Examples/Interfaces/Indexer rux run ``` ```text Monday 18, Tuesday 21, Friday 25 Friday, corrected: 22 Sunday 0 ``` ## Common mistakes ::mistake **A compound assignment through the brackets.**:br`week[Day::Friday] -= 3` fails with: ```text error: operator '-=' cannot read and write through the '[]' operator on 'Week' at once ``` Spell it out as `week[Day::Friday] = week[Day::Friday] - 3`. :: ::mistake **Indexing with the wrong type.**:br`week[9]` fails with: ```text error: no '[]' on 'Week' accepts an index of type 'int' ``` The indexer takes a `Day`, so write `week[Day::Sunday]`. :: ::mistake **Writing to a `let` value.**:br Declare `week` with `let` and every assignment fails with: ```text error: cannot modify immutable variable 'week' ``` `[]=` takes `&var self`, so the variable must be a `var`. Reading through `[]` still works on a `let`. :: ## Try it yourself 1. Add `func Warmest(self: &Week) -> int32` that returns the highest of the seven temperatures. 2. Make `[]=` refuse temperatures above 60 by leaving the old value in place. 3. Write a `Scores` type indexed by a `Player` enum of your own, with both `[]` and `[]=`. ## Learn more - [Operator overload](https://rux-lang.dev/docs/learn/operator-overload) — the other operators a type can declare - [Enum value](https://rux-lang.dev/docs/learn/enum-value) — `day as uint` - [Array](https://rux-lang.dev/docs/learn/array) — indexing with a number - [Array access](https://rux-lang.dev/docs/lang/arrays/overview#indexing) in the Rux Reference # Iterator ::note **You'll need**: [Interface](https://rux-lang.dev/docs/learn/interface), [For](https://rux-lang.dev/docs/learn/for), [Optional](https://rux-lang.dev/docs/learn/optional), [Coalesce exit](https://rux-lang.dev/docs/learn/coalesce-exit) :: `for` has walked ranges and arrays since the [For](https://rux-lang.dev/docs/learn/for) lesson. It can walk a type of your own too, once that type has one method, `Next`, which hands out one item per call and an [optional](https://rux-lang.dev/docs/learn/optional) `none` when there are no more. A type with such a method is called an **iterator**. This lesson builds one that counts down to liftoff. ## The Next method ```rux // Counts down from a starting number to 1. struct Countdown { remaining: int32; } extend Countdown : Iterator { // `&var`, because handing out an item moves the countdown along. func Next(self: &var Countdown) -> int32? { if self.remaining == 0 { return none; } let current = self.remaining; self.remaining -= 1; return current; } } ``` Three things make this an iterator: | Part | Why | | ---------------------- | -------------------------------------------------------------------------------- | | the name `Next` | `for` looks for a method with exactly this name | | `self: &var Countdown` | handing out an item moves the countdown along, so `Next` must write | | `-> int32?` | an item, or `none` for "no more". The item type is whatever the optional carries | ## The role has a name `extend Countdown : Iterator` uses the `Iterator` interface from Core, imported with `import Core::Iterator;`. But that interface lists no methods: an interface cannot spell out an item type that each iterator chooses for itself, so `for` goes by the shape of `Next` alone. Writing `: Iterator` names the role for a reader and records what the type is meant to be. Leave it out and the countdown still works with `for`. ## What for does ```rux // `for` calls `Next` until it sees `none`. The parentheses keep the struct's braces apart // from the loop body's. Print("for: "); for second in (Countdown { remaining: 5 }) { Print(" {}", second); } PrintLine(" liftoff"); ``` ```mermaid flowchart LR start["`for second in countdown`"] --> next["call `Next()`"] next --> q{"an item,
or none?"} q -- "an item" --> body["run the body
with `second` = the item"] body --> next q -- "none" --> done["leave the loop"] ``` There is no magic in it. The same walk written by hand is a [`loop`](https://rux-lang.dev/docs/learn/loop) with [`?? break`](https://rux-lang.dev/docs/learn/coalesce-exit): ```rux var countdown = Countdown { remaining: 5 }; Print("by hand:"); loop { let second = countdown.Next() ?? break; Print(" {}", second); } PrintLine(" liftoff"); ``` Both print `5 4 3 2 1 liftoff`. ## Used up as it goes ```rux // An iterator is used up as it goes. Once it has said `none`, it keeps saying `none`. PrintLine("anything left? {}", countdown.Next() is int32); ``` After the hand-written loop, `countdown.remaining` is 0, so every further call answers `none`, and `is int32` reports `false`. An iterator is a position in a walk, not a collection: to count down again, you make a new `Countdown`. The next lesson, [Iterable](https://rux-lang.dev/docs/learn/iterable), is about collections that can hand out a fresh iterator whenever one is needed. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Interfaces/Iterator){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // `for` has walked ranges and arrays since the Control flow part. It can walk a type of your own // too, once that type has one method: // func Next(self: &var T) -> Item? // Each call hands out the next item, or `none` when there are no more. `for` calls `Next` again // and again, runs the loop body with every item it gets, and stops at the first `none`. The item // type is whatever the optional carries: `int32` here. // // A type with such a `Next` is called an iterator. `extend Countdown : Iterator` names that role // for a reader, but Core's `Iterator` interface lists no methods, because an interface cannot // spell out an item type that each iterator chooses for itself. `for` goes by `Next` alone. import Core::Iterator; import Io::{ Print, PrintLine }; // Counts down from a starting number to 1. struct Countdown { remaining: int32; } extend Countdown : Iterator { // `&var`, because handing out an item moves the countdown along. func Next(self: &var Countdown) -> int32? { if self.remaining == 0 { return none; } let current = self.remaining; self.remaining -= 1; return current; } } func Main() -> int { // `for` calls `Next` until it sees `none`. The parentheses keep the struct's braces apart // from the loop body's. Print("for: "); for second in (Countdown { remaining: 5 }) { Print(" {}", second); } PrintLine(" liftoff"); // The same walk by hand. This is all that `for` does. var countdown = Countdown { remaining: 5 }; Print("by hand:"); loop { let second = countdown.Next() ?? break; Print(" {}", second); } PrintLine(" liftoff"); // An iterator is used up as it goes. Once it has said `none`, it keeps saying `none`. PrintLine("anything left? {}", countdown.Next() is int32); return 0; } ``` Besides `Io`, its `Rux.toml` lists `Core` under `[Dependencies]`. ## Run it ```sh cd Examples/Interfaces/Iterator rux run ``` ```text for: 5 4 3 2 1 liftoff by hand: 5 4 3 2 1 liftoff anything left? false ``` ## Common mistakes ::mistake **A read-only `Next`.**:br`func Next(self: &Countdown)` is refused: ```text error: iterator method 'Next' on 'Countdown' must take a mutable receiver ``` It comes with the note "advancing an iterator writes it, so 'Next' cannot borrow its receiver read-only". :: ::mistake **Returning the item without an optional.**:br With `-> int32` instead of `-> int32?`, there is no way to say "no more", and `for` refuses the type: ```text error: cannot iterate over 'Countdown' ``` It comes with the note "type 'Countdown' declares 'Next', but not as 'func Next(self: \&var Countdown) -> T?' returning a native optional". :: ::mistake **Leaving out the parentheses.**:br`for second in Countdown { remaining: 5 } {` takes the struct's `{` for the start of the loop body, and the parser stops with: ```text error: expected ';' after expression, but found ':' ``` Wrap a struct literal in parentheses after `in`. :: ::mistake **A different method name.**:br`for` looks for `Next` by name. Call it `Step` and the loop fails with: ```text error: cannot iterate over 'Countdown' ``` It comes with the help "iterate an array, a slice, a range, or a type declaring 'Next' or 'Iterate'". :: ## Try it yourself 1. Write an `Evens` iterator with `next` and `limit` fields that hands out 0, 2, 4, … up to `limit`. 2. Change `Countdown` so that it hands out 0 as its last item before `none`. 3. Declare `var countdown = Countdown { remaining: 3 };`, walk it with `for`, and then print `countdown.remaining`. Was the variable itself used up? ## Learn more - [Iterable](https://rux-lang.dev/docs/learn/iterable) — a collection that hands out fresh iterators - [For](https://rux-lang.dev/docs/learn/for) — the loop that drives `Next` - [Coalesce exit](https://rux-lang.dev/docs/learn/coalesce-exit) — the `?? break` in the hand-written loop - [For loops](https://rux-lang.dev/docs/lang/statements/loops#for) in the Rux Reference # Iterable ::note **You'll need**: [Iterator](https://rux-lang.dev/docs/learn/iterator), [Slice](https://rux-lang.dev/docs/learn/slice) :: The [Iterator](https://rux-lang.dev/docs/learn/iterator) lesson walked a countdown, which is used up as it goes. A collection is different: a shelf of books can be looked through any number of times, and looking does not use up the books. So a collection does not walk itself. It hands out a **fresh iterator** every time one is wanted, and the iterator keeps the position. ## Two types, two jobs ```rux struct Shelf { titles: char8[..][4]; } // The iterator: a view of the shelf's titles, and how far along it has got. struct ShelfCursor { titles: char8[..][..]; index: uint; } ``` `Shelf` holds four titles. `ShelfCursor` holds a [slice](https://rux-lang.dev/docs/learn/slice) that views them, and an index saying how far it has got. The cursor is an iterator exactly like `Countdown`: ```rux extend ShelfCursor : Iterator { func Next(self: &var ShelfCursor) -> char8[..]? { if self.index == self.titles.length { return none; } let title = self.titles[self.index]; self.index += 1; return title; } } ``` ## The Iterate method ```rux extend Shelf : Iterable { func Iterate(self: &Shelf) -> ShelfCursor { return ShelfCursor { titles: self.titles[..], index: 0 }; } } ``` `Iterate` borrows the shelf read-only and returns a new cursor that starts at the first book. As with `Iterator`, Core's `Iterable` lists no methods and only names the role; `for` goes by the method named `Iterate`. | | Iterator (`ShelfCursor`) | Iterable (`Shelf`) | | ----------------- | -------------------------------------------- | ------------------------------------------ | | Its method | `Next(self: &var ShelfCursor) -> char8[..]?` | `Iterate(self: &Shelf) -> ShelfCursor` | | Borrows itself as | `&var` — every call moves it along | `&` — handing out a cursor changes nothing | | After a full walk | used up | unchanged, ready for another loop | ## What for does with a collection ```mermaid flowchart LR loop["`for title in shelf`"] --> it["`shelf.Iterate()`
a fresh `ShelfCursor`"] it --> next["`cursor.Next()`"] next --> q{"a title,
or none?"} q -- "a title" --> body["run the body"] body --> next q -- "none" --> done["leave the loop"] ``` `for` calls `Iterate` once at the top of the loop, then drives that cursor with `Next` exactly as in the previous lesson. So a second loop over the same shelf gets a second cursor and starts from the first book again: ```rux Print("on the shelf:"); for title in shelf { Print(" {}", title); } PrintLine(); // A second loop gets a second iterator, so it starts from the first book again. var letters: uint = 0; for title in shelf { letters += title.length; } ``` 4 + 4 + 7 + 7 gives 22 letters in all. ## Separate positions You can also call `Iterate` yourself. Each call gives an independent cursor: ```rux // Two iterators from one shelf keep separate positions. var reader = shelf.Iterate(); var browser = shelf.Iterate(); reader.Next(); reader.Next(); PrintLine("one reader is at {}, the other at {}", reader.Next() ?? "", browser.Next() ?? ""); ``` `reader` has moved past two books and is at *Ulysses*; `browser` has not moved and is at *Dune*. The shelf itself never changed — the position lives in the iterator. A cursor borrows the shelf it views, so the shelf must outlive it, and must not be changed while a cursor over it is in use. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Interfaces/Iterable){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // The Iterator lesson walked a countdown, which is used up as it goes. A collection is different: // a shelf of books can be looked through any number of times, and looking does not use up the // books. // // So a collection does not walk itself. It provides one method, // func Iterate(self: &T) -> SomeIterator // which hands out a fresh iterator, starting at the beginning, every time it is called. `for` // calls it once at the top of each loop and then drives that iterator with `Next`. The collection // is only borrowed, so it is unchanged afterwards; the position lives in the iterator. // // As with `Iterator`, Core's `Iterable` interface lists no methods and only names the role. import Core::{ Iterable, Iterator }; import Io::{ Print, PrintLine }; struct Shelf { titles: char8[..][4]; } // The iterator: a view of the shelf's titles, and how far along it has got. struct ShelfCursor { titles: char8[..][..]; index: uint; } extend ShelfCursor : Iterator { func Next(self: &var ShelfCursor) -> char8[..]? { if self.index == self.titles.length { return none; } let title = self.titles[self.index]; self.index += 1; return title; } } extend Shelf : Iterable { func Iterate(self: &Shelf) -> ShelfCursor { return ShelfCursor { titles: self.titles[..], index: 0 }; } } func Main() -> int { let shelf = Shelf { titles: ["Dune", "Emma", "Ulysses", "Beloved"] }; Print("on the shelf:"); for title in shelf { Print(" {}", title); } PrintLine(); // A second loop gets a second iterator, so it starts from the first book again. var letters: uint = 0; for title in shelf { letters += title.length; } PrintLine("letters in all titles: {}", letters); // Two iterators from one shelf keep separate positions. var reader = shelf.Iterate(); var browser = shelf.Iterate(); reader.Next(); reader.Next(); PrintLine("one reader is at {}, the other at {}", reader.Next() ?? "", browser.Next() ?? ""); return 0; } ``` Besides `Io`, its `Rux.toml` lists `Core` under `[Dependencies]`. ## Run it ```sh cd Examples/Interfaces/Iterable rux run ``` ```text on the shelf: Dune Emma Ulysses Beloved letters in all titles: 22 one reader is at Ulysses, the other at Dune ``` ## Common mistakes ::mistake **A collection with neither `Next` nor `Iterate`.**:br Rename `Iterate` to `Cursor` and both loops fail with: ```text error: cannot iterate over 'Shelf' ``` They come with the help "iterate an array, a slice, a range, or a type declaring 'Next' or 'Iterate'". Keep the name `Iterate`. :: ::mistake **Taking `&var self` in `Iterate`.**:br Handing out a cursor does not change the collection, so `Iterate` borrows read-only. Declare it with `self: &var Shelf` and each `shelf.Iterate()` on the `let` shelf fails with: ```text error: cannot call 'Iterate' on immutable 'shelf' ``` :: ::mistake **Expecting a used cursor to start again.**:br A cursor is an iterator, and an iterator is used up: once `reader` has handed out *Beloved*, every further `reader.Next()` answers `none`. To walk the shelf again, ask it for a fresh cursor with `shelf.Iterate()` — which is exactly what each `for` loop does. :: ## Try it yourself 1. Count the titles longer than four letters with a `for` loop over `shelf`. 2. Add a method `Backwards(self: &Shelf)` that returns a cursor walking the titles from last to first, and loop over `shelf.Backwards()`. 3. Make three cursors from one shelf, advance each a different number of times, and print where each one is. ## Learn more - [Iterator](https://rux-lang.dev/docs/learn/iterator) — the `Next` half of the protocol - [Slice](https://rux-lang.dev/docs/learn/slice) — the view the cursor holds - [Tree map](https://rux-lang.dev/docs/learn/tree-map) — a standard collection that `for` walks the same way - [For loops](https://rux-lang.dev/docs/lang/statements/loops#for) in the Rux Reference # Part 13: Generics [Generic](https://rux-lang.dev/docs/learn/generic) in Part 4 gave a function a type parameter, so one body could serve `int`, `float64` and `char`. This part takes the idea all the way. Types get type parameters of their own — a `Pair`, a `Reading` — and so do their methods. Bounds turn "any `T`" into "any `T` that can do this", which is what lets a generic call methods, compare scores or print its values. And the language's own forms, `T?`, `T ! E` and `A | B`, turn out to be generic too, which is how a helper can be written once for every optional or every fallible there will ever be. ## What you will learn - Declaring structs and variants with type parameters, and naming the type arguments in a literal. - Giving a generic type methods with `extend Labeled`, including methods with type parameters of their own. - Bounding a type parameter by an interface, ``, and where the compiler checks the bound. - Requiring several interfaces at once with ``. - Writing reusable helpers over `T ! E` and `T?`, which cannot be extended. - Building sums from type parameters, `T | U`, and why they collapse when `T` and `U` are the same. ## What a bound decides Everything in this part comes back to one question: what may the body do with a `T`? The bound is the answer, and the compiler checks it where the generic is used. ```mermaid flowchart LR t(["A type parameter `T`"]) --> none["No bound: `<T>`
store, pass, return a `T`
(13.1–13.2)"] t --> one["One bound: `<T: Scored>`
+ call `Scored`'s methods
(13.3)"] t --> two["Several: `<T: Scored + Display>`
+ everything each one provides
(13.4)"] one --> invoke{"At each call:
does the type argument
implement every bound?"} two --> invoke invoke -- "yes" --> ok["compiled for that type,
calling its methods directly"] invoke -- "no" --> err["error at the call,
naming the missing method"] ``` | You want to… | Write | Lesson | | ----------------------------------------------- | ------------------------------- | ------------------------------------------------------------------ | | describe "two of something" | `struct Pair { … }` | [Generic type](https://rux-lang.dev/docs/learn/generic-type) | | give every `Pair` a method | `extend Pair { … }` | [Generic method](https://rux-lang.dev/docs/learn/generic-method) | | call a method on a `T` | `` | [Generic bound](https://rux-lang.dev/docs/learn/generic-bound) | | call methods from two interfaces | `` | [Multiple bounds](https://rux-lang.dev/docs/learn/multiple-bounds) | | write one helper for every optional or fallible | `func F(outcome: T ! E)` | [Generic outcome](https://rux-lang.dev/docs/learn/generic-outcome) | | return one of two types | `-> T | U`, matched with `else` | [Generic sum](https://rux-lang.dev/docs/learn/generic-sum) | ## Lessons | | Lesson | What you will learn | | ---- | ------------------------------------------------------------------ | ------------------------------------------------------------------------ | | 13.1 | [Generic type](https://rux-lang.dev/docs/learn/generic-type) | a struct with a type parameter: `Pair` | | 13.2 | [Generic method](https://rux-lang.dev/docs/learn/generic-method) | methods on a generic type, and methods with type parameters of their own | | 13.3 | [Generic bound](https://rux-lang.dev/docs/learn/generic-bound) | require a type parameter to implement an interface | | 13.4 | [Multiple bounds](https://rux-lang.dev/docs/learn/multiple-bounds) | require several interfaces at once with `A + B` | | 13.5 | [Generic outcome](https://rux-lang.dev/docs/learn/generic-outcome) | write helpers that work for any optional or result | | 13.6 | [Generic sum](https://rux-lang.dev/docs/learn/generic-sum) | generic sums, and what happens when both members are the same type | ## Before you start Finish [Part 12: Interfaces](https://rux-lang.dev/docs/learn/interfaces): a bound is an interface, and [Display](https://rux-lang.dev/docs/learn/display) is the one most generics end up needing. The lessons also build on [Generic](https://rux-lang.dev/docs/learn/generic) and [Callback](https://rux-lang.dev/docs/learn/callback) from Part 4, [Struct](https://rux-lang.dev/docs/learn/struct) and [Variant match](https://rux-lang.dev/docs/learn/variant-match) from Part 6, the outcome tools of [Part 8](https://rux-lang.dev/docs/learn/optionals) and [Part 9](https://rux-lang.dev/docs/learn/errors), and [Sum type](https://rux-lang.dev/docs/learn/sum-type) from Part 10. Each lesson's package is in the Examples repository's `Generics/` folder: ```sh cd Examples/Generics/GenericType rux run ``` ## After this part [Part 14: Text](https://rux-lang.dev/docs/learn/text) puts generics to work straight away: `String`, `StringView` and `StringBuilder` are ordinary types from the Text package, and every value you print goes through the `Display` interface you bounded on here. Later, [Part 17: Collections](https://rux-lang.dev/docs/learn/collections) is built from generic types — a vector, a map and a set of any element type. For the full rules behind this part, see [Generic functions](https://rux-lang.dev/docs/lang/generics/overview), [Interfaces](https://rux-lang.dev/docs/lang/interfaces/overview) and [Methods](https://rux-lang.dev/docs/lang/structs/methods) in the Rux Reference. # Generic type ::note **You'll need**: [Generic](https://rux-lang.dev/docs/learn/generic), [Struct](https://rux-lang.dev/docs/learn/struct), [Variant match](https://rux-lang.dev/docs/learn/variant-match) :: The [Generic](https://rux-lang.dev/docs/learn/generic) lesson gave a *function* a type parameter, so one body served `int`, `float64` and `char`. A *type* can take a type parameter too. `struct Pair` is not one struct but a pattern for many: `Pair` and `Pair` are two different types stamped out of the same declaration. This is how a single definition can describe "two of something" or "a reading of something" without deciding in advance what that something is. ## A struct with a type parameter The parameter goes in angle brackets after the name, and the fields use it like any other type: ```rux // Two values of the same type, whatever that type is. struct Pair { first: T; second: T; } ``` Both fields are the same `T`, so a pair is always two values of one type. Each use of `Pair` picks its own `T`, and the compiler lays out a separate struct for each one — a pair of `int32` holds two numbers, a pair of `char8[..]` holds two slices. A type may take several parameters, and they need not agree: ```rux // A type may take several parameters, and they need not agree. struct Entry { key: K; value: V; } ``` | Written | What it is | | ------------------------- | ------------------------------------------- | | `Pair` | the declaration — a pattern, not yet a type | | `Pair` | a type: two `int32` fields | | `Pair` | another type: two text fields | | `Entry` | a type with two parameters, filled in order | ## Making a value: the literal names its type arguments A struct literal spells out the type arguments after the name: ```rux let point = Pair { first: 3, second: 4 }; let words = Pair { first: "left", second: "right" }; ``` The literal does not guess `T` from its fields. `Pair { first: 3, second: 4 }` is refused, even though both fields are plainly numbers — and with `` written down, `3` and `4` become `int32` values, just as a literal beside a typed value does. ## A generic function over a generic type A generic function can take a generic type. Here `T` is never written at the call: it is read out of the `Pair` passed in, the same way [Generic](https://rux-lang.dev/docs/learn/generic) inferred it from plain arguments. ```rux func Swapped(pair: Pair) -> Pair { return Pair { first: pair.second, second: pair.first }; } ``` `Swapped(point)` is `Swapped`, and it returns a `Pair` with the fields the other way round — `4 3`. ## A generic variant Variants take type parameters the same way. A case's payload can be a `T`: ```rux // A measurement that may be exact, a range, or missing altogether. variant Reading { Exact(T), Between(T, T), Missing } ``` A case with a payload learns `T` from it, the way a function learns from its arguments. A case without one has nothing to learn from, so the type has to come from somewhere else — an annotation on the variable: ```rux let temperature = Reading::Between(18.5, 21.0); let floor: Reading = Reading::Exact(7); let lost: Reading = Reading::Missing; ``` ```mermaid flowchart LR c["`Reading::…`"] --> q{"Does the case
carry a payload?"} q -- "yes: `Between(18.5, 21.0)`" --> p["`T` comes from the payload:
`Reading<float64>`"] q -- "no: `Missing`" --> a{"Is there an annotation
or a parameter type?"} a -- "yes" --> ok["`T` comes from it:
`Reading<int32>`"] a -- "no" --> err["`error: requires 1 type argument`"] ``` An annotation also wins over the payload: `floor` is a `Reading`, so its `7` is an `int32` rather than an `int`. `Lowest` then works for every reading at once. Its `match` is the one from [Variant match](https://rux-lang.dev/docs/learn/variant-match), with `T` standing in for the payload type: ```rux func Lowest(reading: Reading, fallback: T) -> T { return match reading { .Exact(value) => value, .Between(low, _) => low, .Missing => fallback }; } ``` ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Generics/GenericType){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // The Generic lesson gave a function a type parameter. A type can have one too: `struct Pair` // is not one struct but a pattern for many, and `Pair` and `Pair` are two // different types stamped out of it. Each one is laid out for its own `T`, so a pair of bytes is // small and a pair of strings is wide. // // Variants work the same way. A generic variant's cases can carry a `T`, and that is how one // declaration describes "a reading of something" without saying what is being read. import Io::PrintLine; // Two values of the same type, whatever that type is. struct Pair { first: T; second: T; } // A type may take several parameters, and they need not agree. struct Entry { key: K; value: V; } // A measurement that may be exact, a range, or missing altogether. variant Reading { Exact(T), Between(T, T), Missing } // A generic function can take a generic type. `T` is inferred from the pair it is given. func Swapped(pair: Pair) -> Pair { return Pair { first: pair.second, second: pair.first }; } func Lowest(reading: Reading, fallback: T) -> T { return match reading { .Exact(value) => value, .Between(low, _) => low, .Missing => fallback }; } func Main() -> int { // A struct literal names its type arguments. A literal does not guess `T` from its fields, // so `Pair { first: 3, second: 4 }` is rejected: "struct initializer for 'Pair' requires 1 // type argument, but 0 were provided". let point = Pair { first: 3, second: 4 }; let words = Pair { first: "left", second: "right" }; let flipped = Swapped(point); PrintLine("point {} {}", flipped.first, flipped.second); PrintLine("words {} {}", words.first, words.second); let age = Entry { key: "age", value: 42 }; PrintLine("entry {} = {}", age.key, age.value); // A case with a payload learns `T` from it, the way a generic function learns from its // arguments, so this is a `Reading`. An annotation supplies `T` too: `floor` is a // `Reading`, so its 7 is an `int32`. A case without a payload has nothing to learn // from, so the annotation is what tells `Missing` which reading it is. let temperature = Reading::Between(18.5, 21.0); let floor: Reading = Reading::Exact(7); let lost: Reading = Reading::Missing; PrintLine("lowest {}", Lowest(temperature, 0.0)); PrintLine("lowest {}", Lowest(floor, 0)); PrintLine("lowest {}", Lowest(lost, -1)); return 0; } ``` ## Run it ```sh cd Examples/Generics/GenericType rux run ``` ```text point 4 3 words left right entry age = 42 lowest 18.5 lowest 7 lowest -1 ``` ## Common mistakes ::mistake **Leaving the type arguments off a struct literal.**:br`Pair { first: 3, second: 4 }` fails with: ```text error: struct initializer for 'Pair' requires 1 type argument, but 0 were provided ``` Write `Pair { … }`. The same goes for a type with two parameters: `Entry { … }` is refused with: ```text requires 2 type arguments, but 1 was provided ``` :: ::mistake **A case with no payload and no annotation.**:br`let lost = Reading::Missing;` fails with: ```text error: variant case 'Reading::Missing' requires 1 type argument, but 0 were provided ``` Annotate the variable — `let lost: Reading = Reading::Missing;` — or name the type at the case: `Reading::Missing()`. :: ::mistake **Fields of a different type than `T`.**:br Once `T` is fixed, every field declared as `T` must be that type. `Pair { first: 3, second: "four" }` fails with: ```text error: field 'second' in initializer for 'Pair' has type 'char8[..]', but its declaration requires 'int32' ``` :: ## Try it yourself 1. Make a `Pair` and pass it to `Swapped`. You do not need to change `Swapped` at all. 2. Write `Highest(reading: Reading, fallback: T) -> T`, which returns the *upper* end of a `Between`. 3. Add a case `Approximately(T)` to `Reading`. Which function stops compiling, and why? ## Learn more - [Generic functions](https://rux-lang.dev/docs/lang/generics/overview) and [Variants with data](https://rux-lang.dev/docs/lang/variants/overview) in the Rux Reference - [Generic](https://rux-lang.dev/docs/learn/generic) — type parameters on functions - [Generic method](https://rux-lang.dev/docs/learn/generic-method) — giving `Pair` methods of its own - [Generic sum](https://rux-lang.dev/docs/learn/generic-sum) — another way to build a type out of type parameters # Generic method ::note **You'll need**: [Generic type](https://rux-lang.dev/docs/learn/generic-type), [Constructor](https://rux-lang.dev/docs/learn/constructor), [Mutating method](https://rux-lang.dev/docs/learn/mutating-method), [Callback](https://rux-lang.dev/docs/learn/callback), [Tuple](https://rux-lang.dev/docs/learn/tuple) :: A generic type gets methods the same way any type does: through `extend`. The difference is one pair of angle brackets. The block is written `extend Labeled`, and that `T` is in scope for every method inside, so a single block serves `Labeled`, `Labeled` and every other instantiation. A method can also bring a type parameter of its *own*, chosen afresh at each call. ## One extend block for every T `Labeled` is a value with a name attached: ```rux struct Labeled { label: char8[..]; value: T; } ``` Its methods live in `extend Labeled`. Inside, `T` means "whatever this instantiation's `T` is", and the receivers are written with it — `&Labeled` to read, `&var Labeled` to change, exactly as in [Mutating method](https://rux-lang.dev/docs/learn/mutating-method): ```rux extend Labeled { // A constructor, as for any struct. It returns the instantiation it was called on. func Labeled(label: char8[..], value: T) -> Labeled { return Labeled { label: label, value: value }; } func Get(self: &Labeled) -> T { return self.value; } func Set(self: &var Labeled, value: T) { self.value = value; } ``` To call the [constructor](https://rux-lang.dev/docs/learn/constructor), put the type argument on the type name, and the rest is an ordinary call: ```rux var count = Labeled("count", 7); count.Set(15); ``` From then on `count` is a `Labeled`, so `Get` returns an `int32` and `Set` accepts only an `int32`. Nothing is written per type: the compiler produces `Get` for `int32` because `count` needs it. ## A method with a type parameter of its own `With` declares a second parameter, `U`, which has nothing to do with the type's `T`. `T` comes from the receiver; `U` comes from this call's argument: ```rux // `T` comes from the receiver; `U` comes from this call's argument. func With(self: &Labeled, other: U) -> (T, U) { return (self.value, other); } ``` The same `count` can be paired with text on one line and with a `bool` on the next. `U` is inferred from the argument, or written out after the method name when you want to be explicit: ```rux let fruit = count.With("apples"); let flag = count.With(true); ``` | Parameter | Declared on | Fixed when | In `count.With("apples")` | | --------- | ---------------------- | ---------------------------- | ------------------------- | | `T` | the type, `Labeled` | the value is made | `int32` | | `U` | the method, `With` | each call, from its argument | `char8[..]` | ## Changing the instantiation A method's result can be a *different* instantiation of the same type. `Map` keeps the label and turns the value into something else through a [callback](https://rux-lang.dev/docs/learn/callback): ```rux func Map(self: &Labeled, change: func(T) -> U) -> Labeled { return Labeled { label: self.label, value: change(self.value) }; } ``` Here `U` is inferred from the callback's result type. `Half` returns a `float64` and `IsLarge` a `bool`, so the same `Labeled` becomes a `Labeled` in one call and a `Labeled` in the other: ```rux let half = count.Map(Half); let large = count.Map(IsLarge); ``` ```mermaid flowchart LR c["`count`
`Labeled<int32>`"] -- "`Map(Half)`
`Half: int32 → float64`" --> h["`half`
`Labeled<float64>`"] c -- "`Map(IsLarge)`
`IsLarge: int32 → bool`" --> l["`large`
`Labeled<bool>`"] ``` ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Generics/GenericMethod){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // A generic type gets methods the same way any type does, through `extend`. The block is // written `extend Labeled`, and that `T` is in scope for every method inside it: one block // serves `Labeled`, `Labeled` and every other instantiation. // // A method may also declare a type parameter of its own, which is chosen at each call and has // nothing to do with the type's. `With` below pairs the stored `T` with a `U` that can be // different every time it is called. import Io::PrintLine; // A value with a name attached to it. struct Labeled { label: char8[..]; value: T; } extend Labeled { // A constructor, as for any struct. It returns the instantiation it was called on. func Labeled(label: char8[..], value: T) -> Labeled { return Labeled { label: label, value: value }; } func Get(self: &Labeled) -> T { return self.value; } func Set(self: &var Labeled, value: T) { self.value = value; } // `T` comes from the receiver; `U` comes from this call's argument. func With(self: &Labeled, other: U) -> (T, U) { return (self.value, other); } // The result can be a different instantiation of the same type: a `Labeled` becomes a // `Labeled`, keeping its label and changing its value through `change`. func Map(self: &Labeled, change: func(T) -> U) -> Labeled { return Labeled { label: self.label, value: change(self.value) }; } } func Half(value: int32) -> float64 { return (value as float64) / 2.0; } func IsLarge(value: int32) -> bool { return value > 100; } func Main() -> int { // The type argument goes on the type name, then the constructor runs as usual. var count = Labeled("count", 7); count.Set(15); PrintLine("{} = {}", count.label, count.Get()); // `U` is inferred from the argument, or written out after the method name. let fruit = count.With("apples"); let flag = count.With(true); PrintLine("with {} {}", fruit.0, fruit.1); PrintLine("with {} {}", flag.0, flag.1); // `U` inferred from the callback's result type. let half = count.Map(Half); let large = count.Map(IsLarge); PrintLine("{} / 2 = {}", half.label, half.Get()); PrintLine("{} > 100 is {}", large.label, large.Get()); return 0; } ``` ## Run it ```sh cd Examples/Generics/GenericMethod rux run ``` ```text count = 15 with 15 apples with 15 true count / 2 = 7.5 count > 100 is false ``` ## Common mistakes ::mistake **Writing `extend Labeled` without its parameter.**:br`extend Labeled { … }` fails with: ```text error: struct type 'Labeled' requires 1 type argument, but 0 were provided ``` Every method that mentions `T` then adds: ```text error: type 'T' is not defined in this scope ``` The block must declare the parameter it uses: `extend Labeled`. :: ::mistake **Calling the constructor without a type argument.**:br`Labeled("count", 7)` fails with: ```text error: constructor for 'Labeled' requires 1 type argument, but 0 were provided ``` Write `Labeled("count", 7)`. :: ::mistake **Changing a `let` binding.**:br`Set` takes `&var Labeled`, so it needs a `var`. With `let count = …`, `count.Set(15)` fails with: ```text error: cannot call 'Set' on immutable 'count' ``` Generics change nothing about [mutability](https://rux-lang.dev/docs/learn/mutable). :: ## Try it yourself 1. Make a `Labeled` called `"name"` holding `"Ada"`, and print it through `Get`. 2. Add `func Relabel(self: &Labeled, label: char8[..]) -> Labeled`, which returns a copy with a new label. 3. Write a function `Describe(value: int32) -> char8[..]` that returns `"small"` or `"large"`, and pass it to `Map`. What type is the result? 4. Call `count.With(count)`. What are `T` and `U`, and what does the tuple hold? ## Learn more - [Methods](https://rux-lang.dev/docs/lang/structs/methods) in the Rux Reference - [Generic type](https://rux-lang.dev/docs/learn/generic-type) — declaring `Labeled` in the first place - [Extension](https://rux-lang.dev/docs/learn/extension) and [Constructor](https://rux-lang.dev/docs/learn/constructor) — the same `extend` and constructors on ordinary types - [Generic bound](https://rux-lang.dev/docs/learn/generic-bound) — methods a `T` is promised to have # Generic bound ::note **You'll need**: [Generic](https://rux-lang.dev/docs/learn/generic), [Interface](https://rux-lang.dev/docs/learn/interface), [Extension](https://rux-lang.dev/docs/learn/extension) :: An unconstrained `` promises nothing about `T`. The body may store a `T`, pass it on and hand it back, but it cannot call a method on it, because nothing says the method exists. A **bound** makes that promise. `` accepts only types that implement the interface `Scored`, and in return the body may call `Scored`'s methods on any `T`. It is the generic counterpart of the [Interface](https://rux-lang.dev/docs/learn/interface) lesson: the same interface, used to choose which types may come in. ## A bound is written after a colon Here is the interface, and one type that implements it: ```rux interface Scored { func Score() -> int32; } extend Player : Scored { func Score(self: &Player) -> int32 { return self.points; } } ``` `Best` names the interface after its type parameter: ```rux func Best(first: T, second: T) -> T { if second.Score() > first.Score() { return second; } return first; } ``` `Score` is callable on `first` and `second` only because of the bound. Remove `: Scored` and the body itself is rejected — not a particular call, the definition — because a plain `T` has no `Score`. The winner comes back as a `T`. Called with two `Player` values, `Best` returns a `Player`, so `winner.name` and `winner.points` are right there; it never turns into "some `Scored`". ## The check happens at the call ```mermaid flowchart LR invoke["`Best(ana, bo)`"] --> t["`T = Player`"] t --> q{"Does `Player`
implement `Scored`?"} q -- "yes" --> inst["`Best` is compiled for `Player`;
`Score()` calls `Player`'s `Score`"] q -- "no" --> err["error at the call:
`type argument … does not satisfy`
`interface bound 'Scored'`"] ``` The compiler works out `T` from the arguments first, then checks the bound. A type without an implementation is rejected where it is passed in, with a note naming the method it is missing — never somewhere deep inside the body. That makes the bound a contract you can read from the signature alone: anything `Scored` may be passed, and nothing else. ## Primitives qualify only through an implementation `int32` has no `Score` until something gives it one. An `extend` block on a primitive does, and from then on a bare number is its own score: ```rux extend int32 : Scored { func Score(self: &int32) -> int32 { return self; } } ``` Note the call in `Main`: ```rux PrintLine("best number {}", Best(3, 9)); ``` The `` matters. Two unsuffixed literals make `T` an `int` — the [Literal](https://rux-lang.dev/docs/learn/literal) rule — and `int` is a different type from `int32`, one that nothing has made `Scored`. Writing `T` out turns `3` and `9` into `int32` values. ## A bound travels `Margin` has a bound of its own, and that is what lets it call `Best`: ```rux func Margin(first: T, second: T) -> int32 { let winner = Best(first, second); return winner.Score() * 2 - first.Score() - second.Score(); } ``` Inside `Margin`, `T` is known only to be `Scored`. That is exactly what `Best` requires, so the call is accepted. A generic that calls another generic must promise at least what the callee demands. ## A bound costs nothing at run time A bound and an [interface value](https://rux-lang.dev/docs/learn/interface-value) both use an interface, but they work differently: | | Bound: `` | Interface value: `Scored` | | ----------------------- | ------------------------------------------------ | --------------------------------------------- | | Which type? | one concrete type per call, fixed when compiling | any implementing type, decided while running | | Method call | direct, as if written for that type | looked up through the value at run time | | What comes back | the same `T` that went in — a `Player` | a `Scored`; the `Player` is no longer visible | | Mixed types in one call | no — `first` and `second` are both `T` | yes | Each instantiation calls its own type's method directly, as if `Best` had been written out by hand for `Player` and again for `int32`. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Generics/GenericBound){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // An unconstrained `` promises nothing about `T`, so a generic body can only move a `T` // around. A bound changes that: `` accepts only types that implement `Scored`, and // in return the body may call `Scored`'s methods on any `T`. // // The check happens at the call. A type without an implementation is rejected where it is // passed in, with a note naming the method it is missing, never somewhere deep in the body. // // Unlike an interface value, a bound costs nothing at run time. Each instantiation calls its // own type's method directly, as if the function had been written out by hand for that type. import Io::PrintLine; interface Scored { func Score() -> int32; } struct Player { name: char8[..]; points: int32; } extend Player : Scored { func Score(self: &Player) -> int32 { return self.points; } } // Primitives satisfy a bound the same way: only through an implementation. `int32` has no // `Score` until this block gives it one, and then a bare number is its own score. extend int32 : Scored { func Score(self: &int32) -> int32 { return self; } } // `Score` is callable on `first` and `second` only because of the bound. The winner is handed // back as a `T`, so a `Player` comes back as a `Player`, not as a `Scored`. func Best(first: T, second: T) -> T { if second.Score() > first.Score() { return second; } return first; } // How far the winner leads. A bound travels: a `T` that is `Scored` here satisfies `Best` too. func Margin(first: T, second: T) -> int32 { let winner = Best(first, second); return winner.Score() * 2 - first.Score() - second.Score(); } func Main() -> int { let ana = Player { name: "Ana", points: 12 }; let bo = Player { name: "Bo", points: 17 }; let winner = Best(ana, bo); PrintLine("best player {} with {}", winner.name, winner.points); PrintLine("margin {}", Margin(ana, bo)); // An unsuffixed literal is an `int`, which has no `Score`, so the type is written out. PrintLine("best number {}", Best(3, 9)); // `Best(2.5, 1.5)` is rejected: "type argument 'float64' does not satisfy interface bound // 'Scored'". A `float64` can be compared with `>`, but nothing has made it `Scored`. return 0; } ``` ## Run it ```sh cd Examples/Generics/GenericBound rux run ``` ```text best player Bo with 17 margin 5 best number 9 ``` ## Common mistakes ::mistake **Calling a method on an unbound `T`.**:br Without the bound, `second.Score()` fails with: ```text error: no interface bound on type parameter 'T' provides method 'Score' ``` The compiler suggests the fix: ```text help: add a bound whose interface declares 'Score', as in 'T: SomeInterface' ``` :: ::mistake **Passing a type that is not `Scored`.**:br`Best(2.5, 1.5)` fails with an error and a note: ```text error: type argument 'float64' does not satisfy interface bound 'Scored' on type parameter 'T' interface 'Scored' requires method 'Score', which type 'float64' does not implement ``` A `float64` can be compared with `>`, but nothing has made it `Scored`. :: ::mistake **Bare literals become `int`, not `int32`.**:br`Best(3, 9)` fails the same way, naming `'int'`: the literals have no typed partner, so `T` is `int`, and only `int32` was given a `Score`. Write `Best(3, 9)`, or pass `int32` variables. :: ::mistake **Calling a bounded generic from an unbounded one.**:br If `Margin` were `` without the bound, its call `Best(first, second)` would fail with: ```text error: type argument 'T' does not satisfy interface bound 'Scored' on type parameter 'T' ``` The help says what to do: ```text add the bound to the enclosing declaration, as in 'T: Scored' ``` :: ## Try it yourself 1. Add a third player and write `BestOfThree(a: T, b: T, c: T) -> T` using `Best` twice. 2. Implement `Scored` for `float64` — perhaps the value rounded down with `as int32` — and make `Best(2.5, 1.5)` compile. 3. Declare a `struct Team` with a `wins` field, implement `Scored` for it, and pass two teams to `Margin`. Nothing in `Margin` or `Best` changes. 4. Try `Best(ana, 9)`. Why is a `Player` and an `int32` rejected, even though both are `Scored`? ## Learn more - [Generic functions](https://rux-lang.dev/docs/lang/generics/overview) and [Interfaces](https://rux-lang.dev/docs/lang/interfaces/overview) in the Rux Reference - [Interface](https://rux-lang.dev/docs/learn/interface) and [Extension](https://rux-lang.dev/docs/learn/extension) — declaring and implementing `Scored` - [Interface value](https://rux-lang.dev/docs/learn/interface-value) — the run-time alternative to a bound - [Multiple bounds](https://rux-lang.dev/docs/learn/multiple-bounds) — requiring two interfaces at once # Multiple bounds ::note **You'll need**: [Generic bound](https://rux-lang.dev/docs/learn/generic-bound), [Display](https://rux-lang.dev/docs/learn/display) :: One bound gives a generic one set of methods. Often it needs two: `Scored` to decide who wins, and [Display](https://rux-lang.dev/docs/learn/display) to print the winner with `{}`. Bounds are joined with `+`. `` accepts only a type that implements **both** interfaces, and the body may use everything either one provides. ## Joining bounds with + ```rux func Announce(first: T, second: T) { if second.Score() > first.Score() { PrintLine("{} beats {}", second, first); } else { PrintLine("{} holds off {}", first, second); } } ``` `Score()` is allowed because of `Scored`. Passing `first` and `second` to `{}` is allowed because of `Display`. Inside the body a `T` is exactly what its bounds say it is, and nothing more — with only ``, each `PrintLine` here is rejected, as the [Generic](https://rux-lang.dev/docs/learn/generic) lesson warned it would be. ```mermaid flowchart LR t(["A type argument `T`"]) --> s{"implements
`Scored`?"} s -- "no" --> e1["`error: does not satisfy`
`interface bound 'Scored'`"] s -- "yes" --> d{"implements
`Display`?"} d -- "no" --> e2["`error: does not satisfy`
`interface bound 'Display'`"] d -- "yes" --> ok["`Announce` compiled for `T`:
may call `Score()` and print with `{}`"] ``` ## Each type meets each bound its own way `Player` needs both implementations. `Scored` is the one from [Generic bound](https://rux-lang.dev/docs/learn/generic-bound); `Display` comes from the Text package, and a player prints as their name: ```rux // A player prints as their name. extend Player : Display { func WriteDisplay(self: &Player, writer: &var TextWriter, spec: FormatSpec) -> ! FormatError { return writer.Write(self.name); } } ``` `int32` is already `Display` — the standard packages give every number that implementation, which is why numbers have always printed with `{}`. So it needs only `Scored`: ```rux // `int32` already implements `Display` in the standard packages, so it needs only `Scored`. extend int32 : Scored { func Score(self: &int32) -> int32 { return self; } } ``` | Type | `Scored` | `Display` | `Announce` accepts it? | | --------- | ------------------------ | -------------------------- | ---------------------- | | `Player` | `extend Player : Scored` | `extend Player : Display` | yes | | `int32` | `extend int32 : Scored` | from the standard packages | yes | | `float64` | none | from the standard packages | no — not `Scored` | | `int` | none | from the standard packages | no — not `Scored` | That last row is why `Main` declares its numbers as `int32` before passing them: ```rux let low: int32 = 3; let high: int32 = 9; Announce(high, low); ``` ## Every bound is checked on its own The compiler checks each bound separately and reports the one that fails. `Announce(2.5, 1.5)` is rejected because `float64` is `Display` but not `Scored`. Delete the `extend Player : Display` block and `Announce(ana, bo)` is rejected the other way round — `Player` is `Scored` but cannot print. There is no partial credit: a type that meets one bound out of two is as unwelcome as one that meets none. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Generics/MultipleBounds){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // One bound gives a generic one set of methods. When it needs two, the bounds are joined with // `+`: `` accepts only a type that implements both interfaces, and the // body may use everything either one provides. // // Here `Scored` decides who wins and `Display` lets the body print a `T` with `{}`. With only // ``, each `PrintLine` below is rejected: "no matching overload for 'PrintLine' with // argument types (char8[..], T, T)". A placeholder needs `Display`, and a `T` is only what its // bounds say it is. import Io::PrintLine; import Text::{ Display, FormatError, FormatSpec, TextWriter }; interface Scored { func Score() -> int32; } struct Player { name: char8[..]; points: int32; } extend Player : Scored { func Score(self: &Player) -> int32 { return self.points; } } // A player prints as their name. extend Player : Display { func WriteDisplay(self: &Player, writer: &var TextWriter, spec: FormatSpec) -> ! FormatError { return writer.Write(self.name); } } // `int32` already implements `Display` in the standard packages, so it needs only `Scored`. extend int32 : Scored { func Score(self: &int32) -> int32 { return self; } } func Announce(first: T, second: T) { if second.Score() > first.Score() { PrintLine("{} beats {}", second, first); } else { PrintLine("{} holds off {}", first, second); } } func Main() -> int { let ana = Player { name: "Ana", points: 12 }; let bo = Player { name: "Bo", points: 17 }; Announce(ana, bo); let low: int32 = 3; let high: int32 = 9; Announce(high, low); // Each bound is checked on its own. `Announce(2.5, 1.5)` is rejected because `float64` // is `Display` but not `Scored`; a type that is `Scored` but cannot print is rejected too. return 0; } ``` Besides `Io`, its `Rux.toml` lists `Text` under `[Dependencies]`. ## Run it ```sh cd Examples/Generics/MultipleBounds rux run ``` ```text Bo beats Ana 9 holds off 3 ``` ## Common mistakes ::mistake **Writing a comma instead of `+`.**:br`` does not mean "both". The comma starts a *second type parameter*, here confusingly named `Display`, so `T` is bound by `Scored` alone. Every `PrintLine` in the body then fails with: ```text error: no matching overload for 'PrintLine' with argument types (char8[..], T, T) ``` Every call fails with: ```text error: function 'Announce' requires 2 type arguments, but 0 were provided ``` :: ::mistake **Leaving out the bound the body uses.**:br With only ``, printing a `T` fails with: ```text error: no matching overload for 'PrintLine' with argument types (char8[..], T, T) ``` Everything the body does with a `T` has to come from some bound. :: ::mistake **A type that meets only one bound.**:br Without `extend Player : Display`, `Announce(ana, bo)` fails with an error and a note: ```text error: type argument 'Player' does not satisfy interface bound 'Display' on type parameter 'T' interface 'Display' requires method 'WriteDisplay', which type 'Player' does not implement ``` :: ## Try it yourself 1. Swap `ana` and `bo` in the call to `Announce`. Which line is printed now? 2. Make a player print as `Bo (17)` by calling `WriteFormat` inside `WriteDisplay`, as `Money` did in [Display](https://rux-lang.dev/docs/learn/display). It comes from the Format package, so add `Format` to `[Dependencies]` too. 3. Add a `struct Team` that is `Scored` but not `Display`, and read the error when you pass two teams to `Announce`. Then give it a `Display` implementation. ## Learn more - [Interfaces](https://rux-lang.dev/docs/lang/interfaces/overview) and [Generic functions](https://rux-lang.dev/docs/lang/generics/overview) in the Rux Reference - [Generic bound](https://rux-lang.dev/docs/learn/generic-bound) — one bound, and how it is checked - [Display](https://rux-lang.dev/docs/learn/display) — implementing `WriteDisplay` - [Format](https://rux-lang.dev/docs/learn/format) — what the `spec` passed to `WriteDisplay` describes # Generic outcome ::note **You'll need**: [Generic](https://rux-lang.dev/docs/learn/generic), [Outcome](https://rux-lang.dev/docs/learn/outcome), [Catch fallback](https://rux-lang.dev/docs/learn/catch-fallback), [Optional propagate](https://rux-lang.dev/docs/learn/optional-propagate), [The is operator](https://rux-lang.dev/docs/learn/is) :: Some questions get asked of outcomes again and again: "the value, or this fallback", "did it work?", "what went wrong, if anything?". For a struct you would answer them with methods. Optionals, fallibles and sums are different: they are built into the language rather than declared by a package, so there is no package to own methods on them, and `extend` refuses them. The answer is a **generic function** whose parameter spells the form out — `T ! E` or `T?` — and which therefore works for every success type and every error type at once. ## A parameter that spells out the form `ValueOr` takes any fallible and a fallback of its success type: ```rux // The success, or `fallback` when there is none. func ValueOr(outcome: T ! E, fallback: T) -> T { return outcome catch { else => fallback }; } ``` Nothing is written at the call. Given `Divide(12, 4)`, an `int32 ! DivisionByZero`, the compiler reads `T = int32` and `E = DivisionByZero` straight out of the argument's type, the way it read `T` out of a `Pair` in [Generic type](https://rux-lang.dev/docs/learn/generic-type). The body is the [catch fallback](https://rux-lang.dev/docs/learn/catch-fallback) you already know; the only new thing is that it is written once for every fallible there will ever be. | Parameter written | Accepts | Helpers in this lesson | | ----------------- | --------------------------------- | --------------------------------- | | `T ! E` | any fallible with a success value | `ValueOr`, `SuccessOf`, `ErrorOf` | | `T?` | any optional | `Both` | | `T?[..]` | a slice of optionals of one type | `CountPresent` | ## Turning one form into another Two small helpers move between the forms. `SuccessOf` keeps the success and forgets why there might not be one; `ErrorOf` keeps the other channel: ```rux func SuccessOf(outcome: T ! E) -> T? { return match outcome { .Success(value) => .Some(value), .Failure(_) => none }; } func ErrorOf(outcome: T ! E) -> E? { return match outcome { .Success(_) => none, .Failure(error) => .Some(error) }; } ``` ```mermaid flowchart LR f(["`T ! E`"]) -- "`SuccessOf`" --> s(["`T?`"]) f -- "`ErrorOf`" --> e(["`E?`"]) f -- "`ValueOr(fallback)`" --> t(["`T`"]) f -- "`Succeeded` / `Failed`" --> b(["`bool`"]) ``` `ErrorOf(broken)` is a `DivisionByZero?`, so `Main` can open it with a presence pattern and read the error's own field: ```rux match ErrorOf(broken) { error? => PrintLine("ErrorOf cannot divide {} by zero", error.numerator), none => PrintLine("ErrorOf nothing went wrong") } ``` ## Core ships two of these The two questions everybody asks are already in `Core`, written exactly this way. `Succeeded(outcome)` and `Failed(outcome)` answer which channel an outcome holds, without unwrapping it: ```rux import Core::{ Failed, Succeeded }; ``` Their signatures are `Succeeded(outcome: T ! E) -> bool` and the same for `Failed` — generic functions over a fallible, like the ones in this lesson. ## Optionals too `Both` combines two optionals of possibly different types. The postfix `?` from [Optional propagate](https://rux-lang.dev/docs/learn/optional-propagate) does the work: if either is `none`, the function returns `none` on the spot. ```rux func Both(first: T?, second: U?) -> (T, U)? { return (first?, second?); } ``` And a helper can take a whole slice of optionals. `T?[..]` is a slice of `T?`, so an `int32?[4]` array is passed straight to it, and [`is`](https://rux-lang.dev/docs/learn/is) asks whether each one holds a `T`: ```rux func CountPresent(values: T?[..]) -> uint { var count: uint = 0; for value in values { if value is T { count++; } } return count; } ``` ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Generics/GenericOutcome){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // Optionals, fallibles and sums are built into the language rather than declared by a package, // so there is no package to own methods on them. `extend int32 ! DivisionByZero { ... }` is // rejected: "cannot extend native type 'int32 ! DivisionByZero'". A question you keep asking of // an outcome is written instead as a generic function whose parameter spells the form out: // `T ! E`, or `T?`. // // Such a helper works for every success type and every error type at once, and nothing needs // to be written at the call: `T` and `E` are read straight out of the argument's type. // // `Core` ships the two everybody needs, written exactly this way: `Succeeded(outcome)` and // `Failed(outcome)` answer which channel an outcome holds without unwrapping it. import Core::{ Failed, Succeeded }; import Io::PrintLine; struct DivisionByZero { numerator: int32; } func Divide(numerator: int32, denominator: int32) -> int32 ! DivisionByZero { if denominator == 0 { fail DivisionByZero { numerator: numerator }; } return numerator / denominator; } // The success, or `fallback` when there is none. func ValueOr(outcome: T ! E, fallback: T) -> T { return outcome catch { else => fallback }; } // Keeps the success and forgets why there might not be one. func SuccessOf(outcome: T ! E) -> T? { return match outcome { .Success(value) => .Some(value), .Failure(_) => none }; } // The other channel: the error, if there is one. func ErrorOf(outcome: T ! E) -> E? { return match outcome { .Success(_) => none, .Failure(error) => .Some(error) }; } // Optionals too: both values when both are present, and nothing otherwise. func Both(first: T?, second: U?) -> (T, U)? { return (first?, second?); } // And a whole array of them: an `int32?[4]` is passed straight to the `T?[..]` slice. func CountPresent(values: T?[..]) -> uint { var count: uint = 0; for value in values { if value is T { count++; } } return count; } func Main() -> int { let even = Divide(12, 4); let broken = Divide(7, 0); PrintLine("ValueOr {} {}", ValueOr(even, -1), ValueOr(broken, -1)); PrintLine("Succeeded {} {}", Succeeded(even), Succeeded(broken)); PrintLine("Failed {} {}", Failed(even), Failed(broken)); PrintLine("SuccessOf {}", SuccessOf(even) ?? 0); match ErrorOf(broken) { error? => PrintLine("ErrorOf cannot divide {} by zero", error.numerator), none => PrintLine("ErrorOf nothing went wrong") } let width: int32? = 80; let height: int32? = 24; let missing: char8[..]? = none; match Both(width, height) { size? => PrintLine("Both {} x {}", size.0, size.1), none => PrintLine("Both incomplete") } PrintLine("Both complete: {}", Both(width, missing) is (int32, char8[..])); let readings: int32?[4] = [3, none, 5, none]; PrintLine("CountPresent {} of {}", CountPresent(readings), readings.length); return 0; } ``` Besides `Io`, its `Rux.toml` lists `Core` under `[Dependencies]`. ## Run it ```sh cd Examples/Generics/GenericOutcome rux run ``` ```text ValueOr 3 -1 Succeeded true false Failed false true SuccessOf 3 ErrorOf cannot divide 7 by zero Both 80 x 24 Both complete: false CountPresent 2 of 4 ``` ## Common mistakes ::mistake **Trying to extend an optional or a fallible.**:br`extend int32 ! DivisionByZero { … }` fails with: ```text error: cannot extend native type 'int32 ! DivisionByZero' ``` `extend int32? { … }` fails with: ```text cannot extend native type 'int32?' ``` The note explains why, and the help gives this lesson's answer: ```text a sum, optional, fallible, or unit type has no declaring package to own methods or interface implementations write a generic function that takes the native type as a parameter ``` :: ::mistake **Passing a plain value where a fallible is expected.**:br`ValueOr(12, -1)` fails with: ```text error: function 'ValueOr' requires 2 type arguments, but 0 were provided ``` A plain `int` has no error type, so there is nothing to read `E` from. Only a real `T ! E` fills in both parameters. :: ## Try it yourself 1. Write `OrElse(value: T?, fallback: T) -> T` with `??`, and call it with an `int32?` and a `char8[..]?`. 2. Write `IsPresent(value: T?) -> bool`, then rewrite `CountPresent` to use it. 3. Write `Either(first: T ! E, second: T ! E) -> T ! E` that returns `first` if it succeeded and `second` otherwise. 4. Use `ValueOr` on the result of a function from an earlier lesson that returns a different fallible. Did you have to change `ValueOr`? ## Learn more - [Outcome](https://rux-lang.dev/docs/learn/outcome) and [Catch fallback](https://rux-lang.dev/docs/learn/catch-fallback) — the forms these helpers take apart - [Optional propagate](https://rux-lang.dev/docs/learn/optional-propagate) and [Is](https://rux-lang.dev/docs/learn/is) — the tools inside `Both` and `CountPresent` - [Error handling](https://rux-lang.dev/docs/lang/errors/overview) in the Rux Reference - [Generic sum](https://rux-lang.dev/docs/learn/generic-sum) — the third native form, `A | B`, with type parameters # Generic sum ::note **You'll need**: [Generic](https://rux-lang.dev/docs/learn/generic), [Sum type](https://rux-lang.dev/docs/learn/sum-type), [Typed pattern](https://rux-lang.dev/docs/learn/typed-pattern) :: A [sum type](https://rux-lang.dev/docs/learn/sum-type) can be built from type parameters: `T | U` is "a `T` or a `U`", whatever they turn out to be. That raises a question the Sum type lesson already answered for ordinary types. A sum is a **set** of types, so when `T` and `U` are the same type, `T | U` has only one member — and collapses to that type. This lesson shows the collapse, and the one habit it asks of every generic `match`: end it in `else`. ## A sum of type parameters `Choose` hands back one of two values of possibly different types: ```rux func Choose(takeFirst: bool, first: T, second: U) -> T | U { if takeFirst { return first; } return second; } ``` With two different types, the result keeps whichever member it was given. `port` holds the `int32` 8080; `flag` holds the `bool` `true`: ```rux let port = Choose(true, 8080, false); let flag = Choose(false, 8080, true); ``` ## When T and U are the same type With the same type twice, `int32 | int32` is just `int32`. The result is an ordinary number, ready for arithmetic, and no `match` is needed to get at it: ```rux let count: int32 = Choose(false, 3, 4); PrintLine("int32 | int32 {}", count + 1); ``` ```mermaid flowchart LR s["`T | U`"] --> q{"Are `T` and `U`
the same type?"} q -- "no: `int32`, `bool`" --> two["`bool | int32`
two members"] q -- "yes: `int32`, `int32`" --> one["`int32 | int32 = int32`
one member — a plain `int32`"] ``` | Instantiation | `T | U` becomes | Members | | ---------------------- | --------------- | ------- | | `Choose` | `bool | int32` | 2 | | `Choose` | `int32` | 1 | ## Why the match ends in else `Side` reports which member a `T | U` holds. The natural way to write it would be one typed arm per member — but its second arm is `else`: ```rux func Side(value: T | U) -> char8[..] { return match value { first: T => "first", else => "second" }; } ``` Consider `Side`. The sum has collapsed to `int32`, so the first arm, `first: int32 =>`, matches **every** value. A second arm `second: U =>` would be `second: int32 =>`, coming after an arm that already took everything — an unreachable arm, which the compiler rejects. It rejects it for that instantiation only, and the note names the call responsible: ```text error: match arm is unreachable because an earlier pattern matches every value note: in 'Side' instantiated with T = int32, U = int32 by the call at … ``` An `else` arm is never reported as unreachable. So a `match` over `T | U` ends in `else`, and stays valid for every pair of type arguments — including the pair where `else` is never used: ```rux PrintLine("collapsed side {}", Side(count)); ``` That call prints `first`. A collapsed sum has nothing to tell apart. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Generics/GenericSum){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // A sum can be built from type parameters: `T | U` is "a T or a U", whatever they turn out to be. // That raises a question the SumType lesson already answered. A sum is a set of types, so when // `T` and `U` are the same type, `T | U` has only one member and collapses to that type. // `Choose` returns a plain `int32`, ready for arithmetic. // // The collapse matters to a generic `match`. `Side` cannot write a second arm `second: U =>`: // at `Side` that arm would come after `first: int32 =>`, which already matched // everything, and the instantiation is rejected — "match arm is unreachable because an earlier // pattern matches every value", with a note "in 'Side' instantiated with T = int32, U = int32 // by the call at ..." that points at the call in `Main` responsible. An `else` arm is never // reported as unreachable, so a match over `T | U` ends in `else` and stays valid for every pair // of type arguments. import Io::PrintLine; // Hands back one of two values of possibly different types. func Choose(takeFirst: bool, first: T, second: U) -> T | U { if takeFirst { return first; } return second; } // Which member a `T | U` holds. When the sum has collapsed, the first arm takes every value. func Side(value: T | U) -> char8[..] { return match value { first: T => "first", else => "second" }; } func Main() -> int { // Two different types: the result keeps whichever member it was given. let port = Choose(true, 8080, false); let flag = Choose(false, 8080, true); PrintLine("int32 | bool {} {}", Side(port), Side(flag)); // The same type twice: `int32 | int32` is `int32`, so the result is an ordinary number. let count: int32 = Choose(false, 3, 4); PrintLine("int32 | int32 {}", count + 1); // A collapsed sum has nothing to tell apart. The `else` arm is still there, unused. PrintLine("collapsed side {}", Side(count)); return 0; } ``` ## Run it ```sh cd Examples/Generics/GenericSum rux run ``` ```text int32 | bool first second int32 | int32 5 collapsed side first ``` ## Common mistakes ::mistake **One typed arm per type parameter.**:br Writing `second: U =>` as the last arm of `Side` builds for `Side` but fails for `Side` with: ```text error: match arm is unreachable because an earlier pattern matches every value ``` A note follows, naming the instantiation and the call. End a generic `match` over a sum in `else`. :: ::mistake **Expecting T and U to be inferred from a sum.**:br`Side(port)` fails with: ```text error: argument 1 to 'Side' has type 'bool8 | int32', but parameter 'value' requires 'T | U' ``` (`bool8` is the full name of `bool`.) A sum is a set of types, and the compiler does not split one back into a `T` and a `U`. Write the type arguments: `Side(port)`. :: ::mistake **Leaving the arguments to choose the types.**:br`Choose(true, 8080, false)` compiles, but the bare literal makes `T` an `int`, and the result is a `bool8 | int` — a different type from the `bool8 | int32` that `Side` expects. The error says exactly that. Write `Choose(…)`, or pass `int32` variables. :: ## Try it yourself 1. Call `Choose` and `Side` on its result. What does `Side` print for each member? 2. Call `Choose(true, false, true)` and use the result directly in an `if`. Why is no `match` needed? 3. Write `FirstOr(value: T | U, fallback: T) -> T`, which returns the `T` member or the fallback, with a `first: T` arm and `else`. Try it with `` and with ``. ## Learn more - [Sum type](https://rux-lang.dev/docs/learn/sum-type) and [Typed pattern](https://rux-lang.dev/docs/learn/typed-pattern) — sums and their arms - [Exhaustive](https://rux-lang.dev/docs/learn/exhaustive) — why the compiler checks every arm - [Generic outcome](https://rux-lang.dev/docs/learn/generic-outcome) — generic helpers over the other native forms - [`match`](https://rux-lang.dev/docs/lang/patterns/match) in the Rux Reference # Part 14: Text Text has been in every program since Hello, World, and so far it has been simple: a literal in quotes, printed with `{}`. This part looks underneath. A literal turns out to be a slice of UTF-8 bytes, which is why its length can surprise you; the Text package adds views that promise their bytes are text, Strings that own their bytes, and builders that grow them. Then the part turns outwards — Unicode's three ways of counting characters, laying out columns of numbers, rendering text you keep, parsing numbers back out of it, and reading lines a person types. It ends with whole texts: cutting them into lines and joining pieces back together, and searching them with regular expressions. ## What you will learn - What a string literal is — a read-only `char8[..]` of UTF-8 bytes — and the escapes it can hold. - The three encodings, `c8`, `c16` and `c32`, and why lengths count code units rather than characters. - Borrowing text with `StringView`, owning it with `String`, and building it with `StringBuilder`. - Checking and decoding UTF-8, and telling bytes, scalars and graphemes apart. - Changing case correctly beyond ASCII, where one letter can become two. - Placeholder specs for width, alignment, precision, bases, zeros and signs. - Rendering into a `String` with `Render`, parsing numbers with `ParseInt32`, and reading lines with `ReadLine`. - Walking the lines of a text with `Lines`, joining pieces with `Join`, and comparing text without regard to case with `FoldCase`. - Regular expressions with the Regex package: testing and finding matches, capture groups, every match in turn, splitting and replacing. ## The text types at a glance ```mermaid flowchart LR lit(["A literal
`char8[..]`"]) -- "`StringView::FromValidated`
or `FromBytes` (checked)" --> view["`StringView`
borrowed, known to be UTF-8
(14.3)"] lit -- "`String::FromBytes`" --> str["`String`
owns its bytes
(14.4)"] sb["`StringBuilder`
grows a buffer
(14.5)"] -- "`IntoString`" --> str sb -- "`View`" --> view str -- "`View`" --> view r["`Render(pattern, values)`
(14.11)"] --> str in["`ReadLine`
(14.13)"] -- "appends to" --> sb view -- "`ParseInt32`
(14.12)" --> num(["a number"]) view -- "`Lines`
(14.14)" --> view view -- "`Join`
(14.14)" --> str ``` | You have… | And want to… | Use | | ----------------------------- | ---------------------------------- | ------------------------------------- | | bytes that might not be text | be sure they are UTF-8 | `StringView::FromBytes` or `Validate` | | text someone else owns | trim, search, split it | `StringView` | | text a function made | hand it back, keep it | `String` | | pieces arriving one at a time | join them without copying them all | `StringBuilder` | | values and a pattern | text you keep | `Render` | | text that should be a number | the number, or why not | `ParseInt32` and friends | | one text with line breaks | each line on its own | `StringView.Lines` | | several pieces | one text with separators | `Join` | | text with a shape, not fixed | test it, find it, take it apart | `Regex` | ## Lessons | | Lesson | What you will learn | | ----- | ---------------------------------------------------------------- | ------------------------------------------------------------------------ | | 14.1 | [String literal](https://rux-lang.dev/docs/learn/string-literal) | what a string literal is: read-only `char8` code units | | 14.2 | [Encoding](https://rux-lang.dev/docs/learn/encoding) | `c8`, `c16` and `c32` literals, and code units versus characters | | 14.3 | [String view](https://rux-lang.dev/docs/learn/string-view) | borrow text without copying it | | 14.4 | [String](https://rux-lang.dev/docs/learn/string) | own text that lives as long as you need it | | 14.5 | [String builder](https://rux-lang.dev/docs/learn/string-builder) | build text a piece at a time | | 14.6 | [UTF-8](https://rux-lang.dev/docs/learn/utf8) | check and decode UTF-8 bytes | | 14.7 | [Unicode](https://rux-lang.dev/docs/learn/unicode) | bytes, code points and grapheme clusters, and why their counts differ | | 14.8 | [Unicode case](https://rux-lang.dev/docs/learn/unicode-case) | change case beyond ASCII, where one letter can become two | | 14.9 | [Format](https://rux-lang.dev/docs/learn/format) | control width and alignment when formatting values | | 14.10 | [Format number](https://rux-lang.dev/docs/learn/format-number) | control precision and number base when formatting numbers | | 14.11 | [Render](https://rux-lang.dev/docs/learn/render) | format values into a `String` instead of the console | | 14.12 | [Parse](https://rux-lang.dev/docs/learn/parse) | turn text into a number, and handle text that is not one | | 14.13 | [Input](https://rux-lang.dev/docs/learn/input) | read a line typed by the user, and notice when input ends | | 14.14 | [Lines and joining](https://rux-lang.dev/docs/learn/join-lines) | split text into lines and join pieces back together, and change its case | | 14.15 | [Regular expressions](https://rux-lang.dev/docs/learn/regex) | test and find matches of a regular expression | | 14.16 | [Regex captures](https://rux-lang.dev/docs/learn/regex-capture) | capture groups, every match, splitting and replacing | ## Before you start Finish [Part 13: Generics](https://rux-lang.dev/docs/learn/generics). Text leans on almost everything before it: slices from [Part 5](https://rux-lang.dev/docs/learn/sequences), optionals and fallibles from [Part 8](https://rux-lang.dev/docs/learn/optionals) and [Part 9](https://rux-lang.dev/docs/learn/errors) — nearly every text operation can fail — [Destructor](https://rux-lang.dev/docs/learn/destructor) from Part 11 for the memory a `String` gives back, and [Display](https://rux-lang.dev/docs/learn/display) and [Iterator](https://rux-lang.dev/docs/learn/iterator) from Part 12. Each lesson's package is in the Examples repository's `Text/` folder: ```sh cd Examples/Text/StringLiteral rux run ``` Several lessons pass an `Allocator` around without explaining it yet. For now it is simply where a `String`'s bytes come from; [Part 15: Memory](https://rux-lang.dev/docs/learn/memory) opens it up. ## After this part [Part 15: Memory](https://rux-lang.dev/docs/learn/memory) explains the allocators and pointers this part used without looking inside — the `@written` of [Unicode case](https://rux-lang.dev/docs/learn/unicode-case) and the `Allocator` every `String` was given. [Part 16: Numbers](https://rux-lang.dev/docs/learn/numbers) then ends with the checkpoint projects [Circle](https://rux-lang.dev/docs/learn/circle) and [Quadratic](https://rux-lang.dev/docs/learn/quadratic), which read numbers typed by the user with this part's `ReadLine` and the Format package's parsers. For the language rules behind literals, see [String literals](https://rux-lang.dev/docs/lang/types/text), [Literals](https://rux-lang.dev/docs/lang/lexical/literals) and the [character types](https://rux-lang.dev/docs/lang/types/characters) in the Rux Reference, and the [Text](https://rux-lang.dev/docs/api/text), [Format](https://rux-lang.dev/docs/api/format), [Io](https://rux-lang.dev/docs/api/io) and [Regex](https://rux-lang.dev/docs/api/regex) packages in the API reference. # String literal ::note **You'll need**: [Character](https://rux-lang.dev/docs/learn/character), [For](https://rux-lang.dev/docs/learn/for), [Slice](https://rux-lang.dev/docs/learn/slice), [Writable slice](https://rux-lang.dev/docs/learn/writable-slice) :: Text has been in every lesson so far — every `PrintLine` starts with one — and it was never a special string type. A literal such as `"hello"` is a `char8[..]`: the read-only [slice](https://rux-lang.dev/docs/learn/slice) from the Sequences part, viewing UTF-8 bytes that the compiler stored inside the program. Everything a slice can do, a literal can do. This lesson looks at what that means — and at the two surprises that follow from it. ## A literal is a slice ```rux let word = "hello"; PrintLine("{} has {} bytes", word, word.length); PrintLine("first {}, last {}", word[0], word[word.length - 1]); PrintLine("word[1..4] is {}", word[1..4]); ``` | Slice operation | On `word` | Result | | --------------- | ----------------------- | ------------------------- | | `.length` | `word.length` | `5` | | indexing | `word[0]` | `h`, one `char8` | | a range | `word[1..4]` | `ell`, another slice | | passing it on | `PrintLine("{}", word)` | any `char8[..]` parameter | | a `for` loop | `for c in word` | each `char8` in turn | Because a literal is just a slice, a function that takes `char8[..]` accepts text without any conversion, and a range of a literal is text too. ## The length counts bytes `.length` counts the slice's elements, and the elements of a `char8[..]` are bytes — UTF-8 *code units*, not characters. For plain English letters each character is one byte, so the difference is invisible. It shows up as soon as the text leaves ASCII: ```rux let euro = "\u{20AC}"; PrintLine("{} is {} bytes", euro, euro.length); ``` A reader sees one character, the euro sign, but UTF-8 stores it in three bytes, so its length is 3. The next lesson, [Encoding](https://rux-lang.dev/docs/learn/encoding), is about exactly that gap. ## Escapes A backslash starts an **escape**: a character that is awkward or impossible to type between quotes. Each escape is written with two or more characters but stores fewer bytes — `"\n"` is one byte, a newline. ```rux PrintLine("quote \"to be\""); PrintLine("backslash C:\Rux\Bin"); PrintLine("tab one\ttwo"); PrintLine("newline first\n second"); ``` | Escape | Stores | | ---------- | --------------------------------------- | | `\"` | a double quote, without ending the text | | `\'` | a single quote | | `\` | one backslash | | `\n` | a newline | | `\t` | a tab | | `\r` | a carriage return | | `\0` | a zero byte | | `\u{20AC}` | the Unicode character with that number | The compiler also knows `\a`, `\b`, `\f` and `\v`, the old terminal control characters. Any other letter after a backslash is an error. ## Read-only: copy to change The bytes of a literal live in a read-only part of the program, and a `char8[..]` is a read-only view of them. So a literal can be read, but never changed in place. To change text, copy its bytes into storage the program owns — here an array — and change the copy: ```rux var letters: char8[5]; for i in 0..word.length { letters[i] = word[i]; } letters[0] = c8'j'; PrintLine("{} became {}", word, letters[..]); ``` `c8'j'` is a character literal of type `char8`, one UTF-8 byte. `letters[..]` is a slice of the whole array, which `{}` prints as text — `jello`, while `word` is still `hello`. ```mermaid flowchart LR ro["Read-only program data
`h e l l o`"] -- "viewed by" --> w["`word: char8[..]`
read only"] ro -- "copied byte by byte" --> a["`letters: char8[5]`
owned by `Main`"] a -- "`letters[0] = c8'j'`" --> j["`j e l l o`"] ``` ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Text/StringLiteral){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // Text has been in every lesson so far, and it was never a special string type. A literal such // as "hello" is a `char8[..]` — the read-only slice from the Sequences part, viewing UTF-8 bytes // that the compiler stored inside the program. Everything a slice can do, a literal can do: // `.length`, indexing, ranges, and passing to a function that takes a `char8[..]`. // // Two things follow from that. The length counts bytes (the encoding's code units), not // characters. And the bytes live in a read-only part of the program, so a literal can be read // but never changed in place. import Io::PrintLine; func Main() -> int { let word = "hello"; PrintLine("{} has {} bytes", word, word.length); PrintLine("first {}, last {}", word[0], word[word.length - 1]); PrintLine("word[1..4] is {}", word[1..4]); // A backslash starts an escape: a character that is awkward or impossible to type between // quotes. Each escape is written with two or more characters but stores fewer bytes. PrintLine("quote \"to be\""); PrintLine("backslash C:\\Rux\\Bin"); PrintLine("tab one\ttwo"); PrintLine("newline first\n second"); PrintLine("\"\\n\" is {} byte", "\n".length); // `\u{...}` names any Unicode character by its number. The euro sign takes three bytes // in UTF-8, so its length is 3 even though a reader sees one character. The next lesson // is about exactly that gap. let euro = "\u{20AC}"; PrintLine("{} is {} bytes", euro, euro.length); // The literal itself cannot change: `word[0] = c8'j';` is rejected with "cannot modify // elements through read-only slice 'char8[..]'". To change text, copy its bytes into storage // the program owns — here an array — and change the copy. var letters: char8[5]; for i in 0..word.length { letters[i] = word[i]; } letters[0] = c8'j'; PrintLine("{} became {}", word, letters[..]); return 0; } ``` ## Run it ```sh cd Examples/Text/StringLiteral rux run ``` ```text hello has 5 bytes first h, last o word[1..4] is ell quote "to be" backslash C:\Rux\Bin tab one two newline first second "\n" is 1 byte € is 3 bytes hello became jello ``` ## Common mistakes ::mistake **Changing a literal in place.**:br`word[0] = c8'j';` fails with: ```text error: cannot modify elements through read-only slice 'char8[..]' ``` Copy the bytes into an array (or, later, a [String builder](https://rux-lang.dev/docs/learn/string-builder)) and change the copy. :: ::mistake **A single backslash in a path.**:br`"C:\Rux\Bin"` fails with: ```text error: escape sequence '\R' is not recognized ``` The same error follows for `\B`. Double each backslash: `"C:\Rux\Bin"`. Worse, a path such as `"C:\new"` compiles without complaint — `\n` is a real escape, so the text quietly contains a newline. :: ::mistake **Indexing one past the end.**:br The last byte is `word[word.length - 1]`. `word[word.length]` compiles, but stops the program with: ```text Panic: index out of range ``` :: ## Try it yourself 1. Count how many times `l` appears in `"hello"` with a `for` loop over the literal. 2. Print the length of `"naïve"`. Is it what you expected? Which character costs the extra byte? 3. Copy `"stressed"` into an array backwards and print it. (The [String](https://rux-lang.dev/docs/learn/string) lesson does the same thing and explains what can go wrong with non-ASCII text.) 4. Print a line that contains a tab, a quote and a backslash, using only escapes. ## Learn more - [String literals](https://rux-lang.dev/docs/lang/types/text) and [Literals](https://rux-lang.dev/docs/lang/lexical/literals) in the Rux Reference - [Slice](https://rux-lang.dev/docs/learn/slice) and [Writable slice](https://rux-lang.dev/docs/learn/writable-slice) — what a `char8[..]` and `letters[..]` are - [Encoding](https://rux-lang.dev/docs/learn/encoding) — why one character can be several bytes # Encoding ::note **You'll need**: [String literal](https://rux-lang.dev/docs/learn/string-literal), [Function](https://rux-lang.dev/docs/learn/function), [Convert](https://rux-lang.dev/docs/learn/convert) :: Every character has a number, its **scalar value**: `A` is 65, `€` is 8364, the rocket emoji 🚀 is 128640. An **encoding** decides how that number is stored as a run of fixed-size *code units*. Rux can write a literal in three encodings, and the same text takes a different number of units in each. That is why [String literal](https://rux-lang.dev/docs/learn/string-literal) found the euro sign to be three "long": `.length` counts code units, not characters. ## Three encodings, three literal types A prefix on the literal picks the encoding, and with it the element type of the slice: | Literal | Type | Encoding | Code unit | | ----------- | ------------ | ------------------ | --------- | | `"text"` | `char8[..]` | UTF-8 | 1 byte | | `c8"text"` | `char8[..]` | UTF-8, spelled out | 1 byte | | `c16"text"` | `char16[..]` | UTF-16 | 2 bytes | | `c32"text"` | `char32[..]` | UTF-32 | 4 bytes | The same prefixes pick a character literal's width: `c8'A'` is one `char8` code unit, as in the previous lesson. The program's `Show` takes all three slice types, so the same text can be measured in each encoding side by side: ```rux func Show(eight: char8[..], sixteen: char16[..], thirtyTwo: char32[..]) { PrintLine("{} UTF-8 {}, UTF-16 {}, UTF-32 {}", thirtyTwo, eight.length, sixteen.length, thirtyTwo.length); } ``` ## How the counts drift apart | Text | Scalar values | UTF-8 units | UTF-16 units | UTF-32 units | | ------ | -------------- | ----------- | ------------ | ------------ | | `Rux` | 82, 117, 120 | 3 | 3 | 3 | | `café` | …, 233 for `é` | 5 | 4 | 4 | | `€` | 8364 | 3 | 1 | 1 | | `🚀` | 128640 | 4 | 2 | 1 | - **ASCII** — every encoding uses one unit per character, and the counts agree. That is why the difference is so easy to miss. - **`é`** — two UTF-8 bytes, but one unit in the wider encodings. - **`€`** — three UTF-8 bytes, still one UTF-16 unit. - **The rocket** lies beyond the 65,536 values one UTF-16 unit can hold, so UTF-16 splits it into two units called a **surrogate pair**. Only UTF-32 holds it whole. ```mermaid flowchart LR r(["🚀 scalar value `128640`"]) --> u8["UTF-8
4 units of 1 byte"] r --> u16["UTF-16
2 units of 2 bytes
(a surrogate pair)"] r --> u32["UTF-32
1 unit of 4 bytes"] ``` A UTF-32 unit is wide enough for any scalar, so in a `char32[..]` the count of units *is* the count of scalars. The narrower encodings spend several units on one scalar once the text leaves plain ASCII. ## Indexing returns a code unit `[i]` gives the `i`-th code unit of the slice's own encoding — not the `i`-th character: ```rux let rocket16 = c16"🚀"; let rocket32 = c32"🚀"; PrintLine("rocket16[0] is {}", rocket16[0] as uint32); PrintLine("rocket32[0] is {}", rocket32[0] as uint32); ``` `rocket32[0]` is the whole rocket, 128640. `rocket16[0]` is 55357: the first half of a surrogate pair, a number but no character at all on its own. The `as uint32` [conversion](https://rux-lang.dev/docs/learn/convert) prints the units as numbers, which is the honest way to look at half a character. Which encoding to use? UTF-8 is the default for a reason: it is what files, terminals and the network speak, and the Text package works in it. The wider literals exist for the places that need them — Windows APIs take UTF-16, and the Unicode package works on `char32[..]`, where one unit is one scalar. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Text/Encoding){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // A character has a number, its scalar value: `A` is 65, `€` is 8364, the rocket emoji is 128640. // An encoding decides how that number is stored as a run of fixed-size code units, and Rux // literals can be written in three of them: // // "text" char8[..] UTF-8, one-byte units — the default // c8"text" char8[..] the same, with the encoding spelled out // c16"text" char16[..] UTF-16, two-byte units // c32"text" char32[..] UTF-32, four-byte units // // The same prefixes pick a character literal's width: `c8'A'` is one `char8` code unit. // // `.length` and indexing always count code units of the slice's own encoding. A UTF-32 unit is // wide enough for any scalar, so there the count of units is the count of scalars. The narrower // encodings spend several units on one scalar once the text leaves plain ASCII. import Io::PrintLine; // The three parameter types are the three literal types, so this function shows the same text // in each encoding side by side. func Show(eight: char8[..], sixteen: char16[..], thirtyTwo: char32[..]) { PrintLine("{} UTF-8 {}, UTF-16 {}, UTF-32 {}", thirtyTwo, eight.length, sixteen.length, thirtyTwo.length); } func Main() -> int { // ASCII: every encoding uses one unit per character, and the counts agree. Show("Rux", c16"Rux", c32"Rux"); // `é` takes two UTF-8 bytes but one unit in the wider encodings. Show("café", c16"café", c32"café"); // The euro sign takes three UTF-8 bytes. Show("€", c16"€", c32"€"); // The rocket lies beyond the 65,536 values one UTF-16 unit can hold, so UTF-16 splits it // into two units called a surrogate pair. Only UTF-32 holds it whole. Show("🚀", c16"🚀", c32"🚀"); // Indexing returns a code unit, not a character. The first unit of the UTF-16 rocket is // half a surrogate pair: a number, but no character at all on its own. let rocket16 = c16"🚀"; let rocket32 = c32"🚀"; PrintLine("rocket16[0] is {}", rocket16[0] as uint32); PrintLine("rocket32[0] is {}", rocket32[0] as uint32); return 0; } ``` ## Run it ```sh cd Examples/Text/Encoding rux run ``` ```text Rux UTF-8 3, UTF-16 3, UTF-32 3 café UTF-8 5, UTF-16 4, UTF-32 4 € UTF-8 3, UTF-16 1, UTF-32 1 🚀 UTF-8 4, UTF-16 2, UTF-32 1 rocket16[0] is 55357 rocket32[0] is 128640 ``` ## Common mistakes ::mistake **Passing one encoding where another is expected.**:br The three slice types are different types, and nothing converts between them silently. `Show("Rux", "Rux", c32"Rux")` fails with: ```text error: argument 2 to 'Show' has type 'char8[..]', but parameter 'sixteen' requires 'char16[..]' ``` Write the prefix: `c16"Rux"`. :: ::mistake **A character literal too wide for its unit.**:br`c8'€'` fails with: ```text error: character '€' (U+20AC) does not fit one 'char8' code unit ``` `c16'🚀'` fails likewise for `char16`. The help suggests a string literal instead, such as `c8"€"`, which may use several units. :: ::mistake **Printing half a surrogate pair.**:br Without `as uint32`, `rocket16[0]` prints as `�`, a replacement mark: half a pair is not a character, so there is nothing real to show. :: ## Try it yourself 1. Call `Show` with `naïve`, `日本` and `Ελλάδα`. Which encoding is shortest for each? 2. Print every unit of `c16"🚀"` as a number with a `for` loop. 3. Find a character other than an emoji that needs a surrogate pair in UTF-16. Hint: its scalar value must be above 65,535. ## Learn more - [`char8`](https://rux-lang.dev/docs/lang/types/characters), [`char16`](https://rux-lang.dev/docs/lang/types/characters) and [`char32`](https://rux-lang.dev/docs/lang/types/characters) in the Rux Reference - [Character](https://rux-lang.dev/docs/learn/character) — the character types from Part 1 - [UTF-8](https://rux-lang.dev/docs/learn/utf8) — checking and decoding UTF-8 bytes one scalar at a time - [Unicode](https://rux-lang.dev/docs/learn/unicode) — a third way to count, the one a reader means # String view ::note **You'll need**: [Encoding](https://rux-lang.dev/docs/learn/encoding), [Coalesce](https://rux-lang.dev/docs/learn/coalesce), [Iterator](https://rux-lang.dev/docs/learn/iterator) :: A `char8[..]` is just bytes. Nothing promises they are valid UTF-8, so every function handed one has to check them again — or simply hope. `StringView`, from the Text package, is the same borrowed slice with that promise attached. The bytes are checked **once**, when the view is made, and everything after may rely on them being text. A view also owns nothing: making one copies no bytes and allocates nothing, and every operation on it answers with another view into the same bytes. ## Making a view There are two ways in, depending on who vouches for the bytes: ```rux let line = StringView::FromValidated(" Ada Lovelace, mathematician "); let checked = StringView::FromBytes("Grace Hopper") ?? StringView(); ``` | Call | Checks the bytes? | Returns | Use it for | | ------------------------------ | ----------------- | ------------- | ----------------------------------- | | `StringView::FromValidated(b)` | no — trusts you | `StringView` | literals, which are always UTF-8 | | `StringView::FromBytes(b)` | yes | `StringView?` | bytes from a file, a socket, a user | | `StringView()` | — | an empty view | a fallback after `??` | `FromBytes` returns `none` when the bytes are not text, so it pairs naturally with [`??`](https://rux-lang.dev/docs/learn/coalesce). A view prints with `{}` like any text. ## Trim, search and cut Every one of these returns a new view of the same bytes. Nothing is copied, and the original text never changes. ```rux let trimmed = line.Trim(); let comma = StringView::FromValidated(","); let at = trimmed.IndexOf(comma) ?? trimmed.Length(); PrintLine("starts with Ada {}", trimmed.StartsWith(StringView::FromValidated("Ada"))); let name = trimmed.Part(0, at) ?? StringView(); ``` - `Trim` drops white space — spaces, tabs and line ends — from both ends. `TrimStart` and `TrimEnd` do one end each. - `IndexOf` answers with a **byte** position, or `none` when there is nothing to find — so `?? trimmed.Length()` means "the whole text, if there is no comma". `StartsWith`, `EndsWith` and `Contains` answer yes or no. - `Part(start, end)` cuts out bytes `start` up to `end`, as an optional view. Note that the needle is a view too. Every search takes a `StringView`, so a literal needle is wrapped with `FromValidated` first. ```mermaid flowchart LR b["The bytes of the literal
`␣␣Ada Lovelace, mathematician␣␣`"] line["`line`
the whole literal"] --> b t["`trimmed = line.Trim()`
without the spaces"] --> b n["`name = trimmed.Part(0, 12)`
`Ada Lovelace`"] --> b ``` Because all three point into the same bytes, those bytes must outlive every view of them — exactly as an array must outlive a slice of it. A literal lives as long as the program, so here nothing can go wrong. ## Split into pieces `Split` walks the pieces between separators. It is an [iterator](https://rux-lang.dev/docs/learn/iterator), so a `for` loop takes the pieces one at a time, each a view of its own: ```rux let space = StringView::FromValidated(" "); for word in name.Split(space) { PrintLine("word [{}] {} bytes", word, word.Length()); } ``` ## Positions are bytes, and cuts must fall between characters `Length`, `IndexOf` and `Part` all count bytes, like the literals underneath. But a view promised to be text, so it will not cut a character in half. In `née` the `é` covers bytes 1 and 2: ```rux let accented = StringView::FromValidated("née"); let whole = accented.Part(0, 4) ?? StringView(); let broken = accented.Part(0, 2) ?? StringView::FromValidated("(refused)"); ``` `Part(0, 4)` is the whole word. `Part(0, 2)` would end in the middle of `é`, so it is refused and returns `none`. A plain slice, `"née"[0..2]`, would have cut it anyway — [UTF-8](https://rux-lang.dev/docs/learn/utf8) shows what such a cut leaves behind. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Text/StringView){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // A `char8[..]` is just bytes: nothing promises they are valid UTF-8, so every function handed // one has to check them again or simply hope. `StringView`, from the Text package, is the same // borrowed slice with that promise attached. The bytes are checked once, when the view is made, // and everything after may rely on them being text. // // A view owns nothing. Making one copies no bytes and allocates nothing, and each operation // below answers with another view into the same bytes — so the text it looks at must outlive // it, exactly as an array must outlive a slice of it. import Io::PrintLine; import Text::StringView; func Main() -> int { // `FromValidated` takes the caller's word that the bytes are UTF-8, which a literal always // is. `FromBytes` checks instead, and returns `none` when they are not text. let line = StringView::FromValidated(" Ada Lovelace, mathematician "); let checked = StringView::FromBytes("Grace Hopper") ?? StringView(); PrintLine("checked [{}]", checked); // Trimming does not change the text. It returns a narrower view of the same bytes. let trimmed = line.Trim(); PrintLine("trimmed [{}]", trimmed); // Searching answers with a byte position, or `none` when there is nothing to find. let comma = StringView::FromValidated(","); let at = trimmed.IndexOf(comma) ?? trimmed.Length(); PrintLine("comma at byte {}", at); PrintLine("starts with Ada {}", trimmed.StartsWith(StringView::FromValidated("Ada"))); // `Part` cuts out a smaller view by byte positions, here the name before the comma. let name = trimmed.Part(0, at) ?? StringView(); PrintLine("name [{}]", name); // `Split` walks the pieces between separators, each one a view of its own. let space = StringView::FromValidated(" "); for word in name.Split(space) { PrintLine("word [{}] {} bytes", word, word.Length()); } // Positions are bytes, and a cut inside a character is refused rather than made. In "née" // the `é` covers bytes 1 and 2, so ending a part at byte 2 would split it in half. let accented = StringView::FromValidated("née"); let whole = accented.Part(0, 4) ?? StringView(); let broken = accented.Part(0, 2) ?? StringView::FromValidated("(refused)"); PrintLine("part 0..4 {}", whole); PrintLine("part 0..2 {}", broken); return 0; } ``` Besides `Io`, its `Rux.toml` lists `Text` under `[Dependencies]`. ## Run it ```sh cd Examples/Text/StringView rux run ``` ```text checked [Grace Hopper] trimmed [Ada Lovelace, mathematician] comma at byte 12 starts with Ada true name [Ada Lovelace] word [Ada] 3 bytes word [Lovelace] 8 bytes part 0..4 née part 0..2 (refused) ``` ## Common mistakes ::mistake **Searching with a plain literal.**:br`trimmed.IndexOf(",")` fails with: ```text error: argument 1 to 'IndexOf' has type 'char8[..]', but parameter 'needle' requires 'StringView' ``` Wrap the needle: `StringView::FromValidated(",")`. :: ::mistake **Forgetting that `Part` and `FromBytes` may fail.**:br Both return an optional. Without `??`, `PrintLine("{}", name)` fails with: ```text error: no matching overload for 'PrintLine' with argument types (char8[..], StringView?) ``` `name.Split(space)` fails with: ```text error: type 'StringView?' has no field 'Split' ``` :: ::mistake **`.length` instead of `Length()`.**:br A view is a struct, not a slice, so `word.length` fails with: ```text error: struct 'StringView' has no field 'length' ``` Its size is a method: `word.Length()`. :: ## Try it yourself 1. Use `LastIndexOf` to cut out the surname, `Lovelace`, without splitting. 2. Split `"red,green,,blue"` on a comma. How many pieces do you get, and what is the third one? 3. Check that the trimmed line `EndsWith` `"mathematician"` and `Contains` `"Love"`. 4. Print `accented.ScalarCount()` next to `accented.Length()`. ## Learn more - [Text](https://rux-lang.dev/docs/api/text) in the API reference - [Slice](https://rux-lang.dev/docs/learn/slice) — the borrowed view underneath - [String](https://rux-lang.dev/docs/learn/string) — text that owns its bytes, for when a view is not enough - [UTF-8](https://rux-lang.dev/docs/learn/utf8) — the check that `FromBytes` makes # String ::note **You'll need**: [String view](https://rux-lang.dev/docs/learn/string-view), [Fallible main](https://rux-lang.dev/docs/learn/fallible-main), [Destructor](https://rux-lang.dev/docs/learn/destructor), [Interface value](https://rux-lang.dev/docs/learn/interface-value) :: A [view](https://rux-lang.dev/docs/learn/string-view) borrows, so it can never outlive the bytes it looks at. Text that a function builds and hands back, or that must be kept after its source is gone, needs an **owner**. That is `String`: it keeps its own copy of the bytes, in memory it asked an allocator for, and gives that memory back in its [destructor](https://rux-lang.dev/docs/learn/destructor) when the value's life ends. ## Borrowed or owned | | `StringView` | `String` | | ---------- | --------------------------------- | -------------------------------------- | | Holds | a view of someone else's bytes | its own copy of the bytes | | Making one | free: no copy, no allocation | copies the bytes into allocated memory | | Can fail? | only `FromBytes`, with `none` | yes: `String ! TextError` | | Lives | no longer than the bytes it views | as long as the `String` itself | | Cleans up | nothing to clean up | its destructor frees the memory | ## Where the memory comes from A `String` needs an allocator to ask for memory. `Main` makes the system's allocator and passes it on as an [interface value](https://rux-lang.dev/docs/learn/interface-value) of type `Allocator`: ```rux var system = SystemAllocator(); let allocator: Allocator = system; ``` The allocator itself is the subject of the [Memory](https://rux-lang.dev/docs/learn/memory) part. For now it is simply where a String's bytes come from. ## Returning text a function made `Reversed` builds its letters in a local array, which is gone once the function returns. A view of that array would be left pointing at nothing, so the function returns a `String` that owns a copy: ```rux func Reversed(allocator: Allocator, word: char8[..]) -> String ! TextError { var letters: char8[16]; for i in 0..word.length { letters[i] = word[word.length - 1 - i]; } return String::FromBytes(allocator, letters[..word.length]); } ``` Two things can go wrong, so the result is a [fallible](https://rux-lang.dev/docs/learn/fallible) `String ! TextError`: | `TextError` case | When | | ---------------- | ---------------------------------------------------------- | | `OutOfMemory` | the allocator could not supply the storage | | `InvalidUtf8` | `FromBytes` was given bytes that are not text | | `LengthOverflow` | a length passed what a `uint` can hold | | `NotABoundary` | a position fell inside a character rather than between two | The UTF-8 check is not a formality here. Reversed byte by byte, `né` puts the two bytes of `é` in the wrong order, and `FromBytes` fails with `TextError::InvalidUtf8` rather than make a `String` that is not text. `Main` is a [fallible main](https://rux-lang.dev/docs/learn/fallible-main), `func Main() -> ! TextError`, so `?` passes any such failure on and the program exits with status 1: ```rux var word = Reversed(allocator, "stressed")?; ``` ## Copying with Clone `Clone` makes an independent copy with storage of its own, and it can fail too, because the copy needs memory: ```rux let saved = word.Clone()?; word.ReplaceWith(Reversed(allocator, "drawer")?); ``` `ReplaceWith` gives `word` new text and frees its old bytes. `saved` has its own copy, so it is untouched: `word` is now `reward`, `saved` is still `desserts`. Plain assignment, `let copy = saved;`, would copy too — a `String` has a [custom copy](https://rux-lang.dev/docs/learn/custom-copy). But assignment has no way to report failure, so it ends the program if memory runs out. `Clone` hands that failure back as a `TextError`, which is why it is the one to use when failure must be handled. ## Lending a view Whenever borrowed text is enough, a `String` lends out a view without copying anything: ```rux let view = saved.View(); PrintLine("view {}, {} characters", view, view.ScalarCount()); ``` The view is valid as long as `saved` is. No cleanup is written anywhere: `word` and `saved` each release their own memory at the end of `Main`, as the destructor lesson promised. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Text/String){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // A view borrows, so it can never outlive the bytes it looks at. Text that a function builds // and hands back, or that must be kept after its source is gone, needs an owner. That is // `String`: it keeps its own copy of the bytes, in memory it asked an allocator for, and gives // that memory back in its destructor when the value's life ends. // // Asking for memory can fail, and so can checking that bytes are UTF-8, so the calls that // make a `String` return `String ! TextError`. `Main` is fallible here, and `?` passes any such // failure on. The allocator itself is the subject of the Memory part; for now it is simply // where a String's bytes come from. import Allocator::{ Allocator, SystemAllocator }; import Io::PrintLine; import Text::{ String, TextError }; // The reversed letters exist only in this function's array, which is gone once it returns. A // view of them would be left pointing at nothing, so the function returns a String that owns // a copy. `FromBytes` checks the bytes are text before copying them, and that check matters // here: reversed byte by byte, "né" puts the two bytes of `é` in the wrong order, and the // call fails with `TextError::InvalidUtf8`. The array has room for words of up to 16 bytes. func Reversed(allocator: Allocator, word: char8[..]) -> String ! TextError { var letters: char8[16]; for i in 0..word.length { letters[i] = word[word.length - 1 - i]; } return String::FromBytes(allocator, letters[..word.length]); } func Main() -> ! TextError { var system = SystemAllocator(); let allocator: Allocator = system; var word = Reversed(allocator, "stressed")?; PrintLine("word {}, {} bytes", word, word.Length()); // `Clone` makes an independent copy with storage of its own. Replacing the original's text // afterwards leaves the clone exactly as it was. let saved = word.Clone()?; word.ReplaceWith(Reversed(allocator, "drawer")?); PrintLine("word {}", word); PrintLine("saved {}", saved); // `let copy = saved;` would also copy, but plain assignment has no way to report failure, // so it ends the program if memory runs out. `Clone` hands that failure back as a // `TextError` instead, which is why it is the one to use when failure must be handled. // A String lends out a view whenever borrowed text is enough, without copying anything. let view = saved.View(); PrintLine("view {}, {} characters", view, view.ScalarCount()); // No cleanup is written: `word` and `saved` each release their own memory at the end of // `Main`, as the Destructor lesson promised. } ``` Besides `Io`, its `Rux.toml` lists `Allocator` and `Text` under `[Dependencies]`. ## Run it ```sh cd Examples/Text/String rux run ``` ```text word desserts, 8 bytes word reward saved desserts view desserts, 8 characters ``` ## Common mistakes ::mistake **Forgetting the `?`.**:br`var word = Reversed(allocator, "stressed");` compiles on its own, but `word` is then a `String ! TextError`, not a `String`. The next use fails: ```text error: type 'String ! TextError' has no field 'Length' ``` Printing it fails with: ```text error: no matching overload for 'PrintLine' with argument types (char8[..], String ! TextError) ``` :: ::mistake **Returning a slice of a local array.**:br A function declared `-> char8[..]` that ends with `return letters[..word.length];` compiles — but the slice points into an array that no longer exists once the function returns, and whatever it reads afterwards is anyone's guess. Text a function makes must be returned as a `String`, which owns it. :: ::mistake **Ignoring that `FromBytes` checks.**:br Change `"drawer"` to `"né"` and the program prints its first line, then stops with exit status 1: the reversed bytes are not UTF-8, `FromBytes` fails, and `?` passes `InvalidUtf8` out of `Main`. :: ## Try it yourself 1. Reverse `"né"` and handle the failure with a `match` on `.Success` and `.Failure` instead of `?`, printing a message of your own. 2. Make a `String` from a view with `String::FromView(allocator, view)`. 3. Use `Substring(start, end)` to copy the first four bytes of `saved` into a new `String`. 4. Compare `word` and `saved` with `Equals`, before and after `ReplaceWith`. ## Learn more - [Text](https://rux-lang.dev/docs/api/text) in the API reference - [String view](https://rux-lang.dev/docs/learn/string-view) — the borrowed form a `String` lends out - [Destructor](https://rux-lang.dev/docs/learn/destructor) and [Custom copy](https://rux-lang.dev/docs/learn/custom-copy) — how a `String` frees and copies its memory - [Allocator](https://rux-lang.dev/docs/learn/allocator) — where the memory comes from # String builder ::note **You'll need**: [String](https://rux-lang.dev/docs/learn/string), [Mutable reference](https://rux-lang.dev/docs/learn/mutable-reference), [Unit fallible](https://rux-lang.dev/docs/learn/unit-fallible), [Propagate](https://rux-lang.dev/docs/learn/propagate) :: A [`String`](https://rux-lang.dev/docs/learn/string) has no way to add to its text — it can only be replaced whole. Building text a piece at a time out of Strings alone would mean making a new String at every step and copying everything built so far into it — the longer the text, the more each step costs. `StringBuilder` is the tool for that job. It keeps one growing buffer, appends into it, and asks the allocator for a larger one only when the room runs out. When the text is finished, it hands the buffer over as a `String`. ## Length and capacity A builder tracks two numbers: `Length`, the text so far, and `Capacity`, the room for it. A new builder has allocated nothing yet; its buffer appears with the first append. ```rux var builder = StringBuilder(allocator); ``` `Join` appends the colours one at a time and reports both numbers after each: ```rux func Join(builder: &var StringBuilder, words: char8[..][..]) -> ! TextError { for i in 0..words.length { if i > 0 { let separator = i == words.length - 1 ? " and " : ", "; builder.Append(separator)?; } builder.Append(words[i])?; PrintLine("added {}: {} bytes, room for {}", words[i], builder.Length(), builder.Capacity()); } } ``` | After adding | Length | Capacity | What happened | | ------------ | ------ | -------- | ------------------------------- | | `red` | 3 | 16 | the first buffer is allocated | | `orange` | 11 | 16 | fits; only the new bytes copied | | `yellow` | 19 | 32 | out of room: the buffer doubles | | `green` | 26 | 32 | fits | | `blue` | 35 | 64 | doubles again | The room doubles each time it runs out, so most appends copy just the bytes being added, and the rare move to a bigger buffer gets rarer as the text grows. The builder is passed as `&var StringBuilder` — a [mutable reference](https://rux-lang.dev/docs/learn/mutable-reference) — so `Join` grows the caller's builder rather than a copy of it. ## Every append can fail Growing the buffer means asking for memory, and that can fail, so every append returns `! TextError` — a [unit fallible](https://rux-lang.dev/docs/learn/unit-fallible). Each one is followed by `?`, which [propagates](https://rux-lang.dev/docs/learn/propagate) a failure and otherwise carries on. | Method | Appends | | ------------------- | --------------------------------------------- | | `Append(text)` | a `char8[..]` or a `StringView` | | `AppendScalar(c)` | one character, any `char32`, encoded as UTF-8 | | `AppendAscii(byte)` | one ASCII `char8` | ```rux builder.Append(" ")?; builder.AppendScalar('✓')?; ``` The check mark is one character but three UTF-8 bytes, which is why the finished text is 39 bytes, not 37. ## Taking the text out `View` looks at the text so far without taking it — a [string view](https://rux-lang.dev/docs/learn/string-view) of the builder's buffer. `IntoString` hands the buffer itself to a `String`, without copying a byte, and leaves the builder empty, ready to build something else: ```rux PrintLine("view {}", builder.View()); let sentence = builder.IntoString(); PrintLine("string {}", sentence); PrintLine("builder now holds {} bytes", builder.Length()); ``` ```mermaid flowchart LR b["`StringBuilder`
buffer: 39 bytes"] -- "`View()`
borrow, no copy" --> v["`StringView`"] b -- "`IntoString()`
hand over the buffer;
builder left empty" --> s["`String`
owns the 39 bytes"] b -- "`ToString()`
copy, may fail" --> c["`String`
a copy; builder keeps its text"] ``` | Method | Returns | Copies? | Builder afterwards | | -------------- | -------------------- | ------- | ------------------ | | `View()` | `StringView` | no | unchanged | | `IntoString()` | `String` | no | empty | | `ToString()` | `String ! TextError` | yes | unchanged | `IntoString` cannot fail — nothing is allocated — which is why it needs no `?`. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Text/StringBuilder){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // A `String` cannot grow: it can be cleared or replaced whole, but never appended to, so building // text a piece at a time out of Strings alone would copy everything built so far at every step. // `StringBuilder` is the tool for that job. It keeps one growing buffer, appends into it, and asks // the allocator for a larger one only when the room runs out. `Length` is the text so far and // `Capacity` the room for it. The room doubles each time it runs out, so most appends copy just // the bytes being added, and the rare move to a bigger buffer gets rarer as the text grows. // // Each append can fail, because growing the buffer can, so each returns `! TextError`. When the // text is finished, `IntoString` hands the buffer over as a String without copying it. import Allocator::{ Allocator, SystemAllocator }; import Io::PrintLine; import Text::{ StringBuilder, TextError }; // Joins words into a list a person would write: "a, b and c". The builder is borrowed `&var`, // so the caller's builder is the one that grows. Watch the room: 16, then 32, then 64. func Join(builder: &var StringBuilder, words: char8[..][..]) -> ! TextError { for i in 0..words.length { if i > 0 { let separator = i == words.length - 1 ? " and " : ", "; builder.Append(separator)?; } builder.Append(words[i])?; PrintLine("added {}: {} bytes, room for {}", words[i], builder.Length(), builder.Capacity()); } } func Main() -> ! TextError { var system = SystemAllocator(); let allocator: Allocator = system; // A new builder has allocated nothing yet. Its buffer appears with the first append. var builder = StringBuilder(allocator); let colours: char8[..][5] = ["red", "orange", "yellow", "green", "blue"]; Join(builder, colours)?; // Single characters go in with `AppendScalar`, which encodes any character as UTF-8. builder.Append(" ")?; builder.AppendScalar('✓')?; // `View` looks at the text so far without taking it. PrintLine("view {}", builder.View()); // `IntoString` hands the buffer itself to a String. The builder is left empty, ready to // build something else. let sentence = builder.IntoString(); PrintLine("string {}", sentence); PrintLine("builder now holds {} bytes", builder.Length()); } ``` Besides `Io`, its `Rux.toml` lists `Allocator` and `Text` under `[Dependencies]`. ## Run it ```sh cd Examples/Text/StringBuilder rux run ``` ```text added red: 3 bytes, room for 16 added orange: 11 bytes, room for 16 added yellow: 19 bytes, room for 32 added green: 26 bytes, room for 32 added blue: 35 bytes, room for 64 view red, orange, yellow, green and blue ✓ string red, orange, yellow, green and blue ✓ builder now holds 0 bytes ``` ## Common mistakes ::mistake **Dropping an append's result.**:br`builder.Append(" ");` on its own fails with: ```text error: fallible result of type '! TextError' is discarded ``` The note says why: ```text a failure that nothing handles is lost ``` Add `?`, or handle it with `catch`. :: ::mistake **A builder declared with `let`.**:br Appending changes the builder, so it must be a `var`. With `let builder`, the call `Join(builder, colours)` fails with: ```text error: argument 1 to 'Join' cannot borrow immutable 'builder' as '&var StringBuilder' ``` Each `builder.Append` fails with: ```text cannot call 'Append' on immutable 'builder' ``` :: ::mistake **Appending a character with `Append`.**:br`builder.Append('✓')` fails with: ```text error: no matching overload for method 'Append' on type 'StringBuilder' with argument types (char32) ``` `Append` takes text. A single character goes in with `AppendScalar`. :: ## Try it yourself 1. Replace `IntoString` with `ToString()?` and see what the last line prints now. 2. Make the builder with `StringBuilder::WithCapacity(allocator, 64)?` instead. How do the `room for` numbers change? 3. Write `Repeat(builder: &var StringBuilder, text: char8[..], count: int) -> ! TextError` and use it to build a line of 40 dashes. 4. After `IntoString`, build a second sentence in the same builder. ## Learn more - [Text](https://rux-lang.dev/docs/api/text) in the API reference - [String](https://rux-lang.dev/docs/learn/string) — what `IntoString` produces - [Unit fallible](https://rux-lang.dev/docs/learn/unit-fallible) and [Propagate](https://rux-lang.dev/docs/learn/propagate) — `! TextError` and `?` - [Input](https://rux-lang.dev/docs/learn/input) — a builder that `ReadLine` fills with each line typed # UTF-8 ::note **You'll need**: [Encoding](https://rux-lang.dev/docs/learn/encoding), [Outcome](https://rux-lang.dev/docs/learn/outcome), [Catch](https://rux-lang.dev/docs/learn/catch) :: UTF-8 stores each character as one to four bytes, and the bytes follow strict rules: the first byte of a character says how many bytes follow, and every byte after it is a *continuation byte* of a particular shape. Not every run of bytes obeys them. Text cut in the wrong place, or bytes that were never text, break the rules. The Text package has the two tools that sit underneath every [view](https://rux-lang.dev/docs/learn/string-view) and [String](https://rux-lang.dev/docs/learn/string): one that checks, and one that decodes. ## The bytes of née `"née"` is four bytes: `n`, then two for `é`, then `e`. ```mermaid flowchart LR b0["byte 0
`n`
a 1-byte character"] --- b1["byte 1
start of `é`
says: 2 bytes"] --- b2["byte 2
continuation
of `é`"] --- b3["byte 3
`e`
a 1-byte character"] ``` `word[..2]` takes bytes 0 and 1, so it ends with a character whose second byte is missing. `word[2..]` starts with byte 2, a continuation byte with nothing before it. Both are perfectly good `char8[..]` slices, and neither is valid UTF-8. ## Decoding one character at a time ```rux DecodeAt(bytes, index) -> DecodedScalar ! Utf8Error ``` `DecodeAt` reads the character that starts at `index` and returns a `DecodedScalar` with two fields: `scalar`, the character as a `char32`, and `width`, how many bytes it took. Stepping `index` by each character's width walks the text one character at a time: ```rux var index: uint = 0; while index < word.length { let decoded = DecodeAt(word, index) catch { else => return 1 }; PrintLine("byte {} {} {} byte(s)", index, decoded.scalar, decoded.width); index += decoded.width; } ``` The result is fallible, because `index` might not be the start of a character at all. Here a failure cannot happen — the literal is valid and the loop only ever lands on starts — so [`catch`](https://rux-lang.dev/docs/learn/catch) simply ends the program with status 1 if it somehow did. ## Checking the whole text ```rux Validate(bytes) -> ! Utf8Failure ``` `Validate` checks every byte. On success there is nothing to return; on failure, a `Utf8Failure` says what was wrong and where: | Field | Type | Meaning | | -------- | ----------- | -------------------------------------- | | `reason` | `Utf8Error` | what was wrong | | `index` | `uint` | the byte where the bad sequence starts | `Check` takes the outcome apart with a [`match`](https://rux-lang.dev/docs/learn/outcome) on `.Success` and `.Failure`: ```rux func Check(label: char8[..], bytes: char8[..]) { match Validate(bytes) { .Success(_) => PrintLine("{} valid", label), .Failure(failure) => PrintLine("{} {} at byte {}", label, failure.reason, failure.index) } } ``` `Utf8Error` has three cases, and each prints its own description: | Case | Means | Printed as | | --------------------- | ------------------------------------------------------------------------ | --------------------------------- | | `Truncated` | a character starts, but the bytes run out before it ends | `truncated UTF-8 sequence` | | `InvalidStart` | a byte that cannot start a character, such as a stray continuation byte | `invalid UTF-8 start byte` | | `InvalidContinuation` | a byte where a continuation byte was required, or one of the wrong shape | `invalid UTF-8 continuation byte` | `word[..2]` fails as `Truncated` at byte 1, where `é` starts and never finishes. `word[2..]` fails as `InvalidStart` at byte 0 — which is byte 2 of the original word. `Truncated` is worth telling apart from the others. It is what the end of a buffer looks like when more bytes are still to come, so a program reading in chunks may just need to read more. The other two mean the bytes are not UTF-8, and no amount of reading will change that. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Text/Utf8){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // UTF-8 stores each character as one to four bytes, and not every run of bytes is valid UTF-8. // Text cut in the wrong place, or bytes that were never text, break its rules. The Text package // has the two tools underneath every view and String: // // Validate(bytes) -> ! Utf8Failure is all of it UTF-8, and if not, where? // DecodeAt(bytes, index) -> DecodedScalar ! Utf8Error which character starts here? // // A `Utf8Failure` carries two fields: `reason`, a `Utf8Error` saying what was wrong, and `index`, // the byte where the trouble starts. A `DecodedScalar` carries the character and its width. import Io::PrintLine; import Text::{ DecodeAt, Validate }; func Check(label: char8[..], bytes: char8[..]) { match Validate(bytes) { .Success(_) => PrintLine("{} valid", label), .Failure(failure) => PrintLine("{} {} at byte {}", label, failure.reason, failure.index) } } func Main() -> int { // "née" is four bytes: `n`, then two for `é`, then `e`. let word = "née"; // Decoding walks the text one character at a time, stepping by each character's width. var index: uint = 0; while index < word.length { let decoded = DecodeAt(word, index) catch { else => return 1 }; PrintLine("byte {} {} {} byte(s)", index, decoded.scalar, decoded.width); index += decoded.width; } // A slice of a literal counts bytes, so a careless range can cut `é` in half. Validation // finds both kinds of damage: a character whose bytes run out, and a stray byte from the // middle of a character with nothing before it. Check("whole ", word); Check("word[..2] ", word[..2]); Check("word[2..] ", word[2..]); return 0; } ``` Besides `Io`, its `Rux.toml` lists `Text` under `[Dependencies]`. ## Run it ```sh cd Examples/Text/Utf8 rux run ``` ```text byte 0 n 1 byte(s) byte 1 é 2 byte(s) byte 3 e 1 byte(s) whole valid word[..2] truncated UTF-8 sequence at byte 1 word[2..] invalid UTF-8 start byte at byte 0 ``` ## Common mistakes ::mistake **Using a decode result as the character.**:br`DecodeAt` is fallible. Without `catch`, `decoded.scalar` fails with: ```text error: type 'DecodedScalar ! Utf8Error' has no field 'scalar' ``` :: ::mistake **Stepping one byte at a time.**:br With `index += 1` instead of `index += decoded.width`, the loop lands on byte 2 — the middle of `é` — and `DecodeAt` fails there. Always step by the width you were given. :: ::mistake **Trusting a slice of text to be text.**:br A range of a literal counts bytes, so a careless `word[..2]` cuts a character in half without any complaint. Ranges on a `char8[..]` are byte operations; a view's `Part` refuses such a cut, and `Validate` finds the damage afterwards. :: ## Try it yourself 1. Count the characters in `"née"` with `CountScalars` from the Text package, and check it against your decoding loop. 2. Run `Check` on `word[1..3]` and on `word[3..]`. Which ones are valid, and why? 3. Change the decoding loop to print each character's scalar value as a number, with `decoded.scalar as uint32`. 4. Decode `"🚀"`. What width does `DecodeAt` report? ## Learn more - [Text](https://rux-lang.dev/docs/api/text) in the API reference - [Encoding](https://rux-lang.dev/docs/learn/encoding) — scalar values and code units - [Outcome](https://rux-lang.dev/docs/learn/outcome) and [Catch](https://rux-lang.dev/docs/learn/catch) — the two ways this program opens a fallible - [Unicode](https://rux-lang.dev/docs/learn/unicode) — when one character is several scalars # Unicode ::note **You'll need**: [Encoding](https://rux-lang.dev/docs/learn/encoding), [UTF-8](https://rux-lang.dev/docs/learn/utf8) :: [Encoding](https://rux-lang.dev/docs/learn/encoding) found two ways to count the same text: code units and scalars. There is a third, and it is the one a reader means. Ask a person how many characters are in `café` and they will say four — however the computer happens to store it. This lesson counts the same text all three ways, and finds text where all three answers differ. ## Three levels of text | Level | What it is | Counted here with | | ------------- | --------------------------------------------------- | ----------------- | | **bytes** | how UTF-8 stores the text | `utf8.length` | | **scalars** | the characters Unicode numbers, one `char32` each | `utf32.length` | | **graphemes** | what a person would point at and call one character | `CountGraphemes` | The program passes each text twice — as UTF-8 for the byte count, and as UTF-32, where one unit is one scalar: ```rux func Count(utf8: char8[..], utf32: char32[..]) { PrintLine("{} bytes {}, scalars {}, graphemes {}", utf8, utf8.length, utf32.length, CountGraphemes(utf32)); } ``` `CountGraphemes` comes from the Unicode package, which knows where graphemes begin and end. Like everything in that package, it works on `char32[..]`. ## When the counts differ ```rux Count("cafe", c32"cafe"); Count("caf\u{E9}", c32"caf\u{E9}"); Count("cafe\u{301}", c32"cafe\u{301}"); Count("\u{1F1FA}\u{1F1E6}", c32"\u{1F1FA}\u{1F1E6}"); ``` | Text | Spelled as | Bytes | Scalars | Graphemes | | ------ | -------------------------------- | ----- | ------- | --------- | | `cafe` | four ASCII letters | 4 | 4 | 4 | | `café` | `é` as one scalar, U+00E9 | 5 | 4 | 4 | | `café` | `e` + U+0301, a combining accent | 6 | 5 | 4 | | 🇺🇦 | two regional indicators | 8 | 2 | 1 | **Plain ASCII** — all three counts agree, which is why the difference is so easy to miss. **`é` as one scalar** — two bytes, but one scalar and one grapheme. **`e` plus a combining accent** — U+0301 is a scalar of its own that attaches to the letter before it. On screen it looks exactly like the line above, yet every count differs: six bytes, five scalars, four graphemes. **A flag** — the Ukrainian flag is two "regional indicator" letters, U and A, four bytes each. A screen draws the pair as one picture, so it is one grapheme. ```mermaid flowchart LR t(["`café`, written with
a combining accent"]) --> g["4 graphemes
`c` · `a` · `f` · `é`"] g --> s["5 scalars
`c` · `a` · `f` · `e` · `U+0301`"] s --> b["6 bytes
`63 61 66 65 CC 81`"] ``` ## Which count is right? It depends on the question: | Question | Count | | -------------------------------------------------------------- | --------- | | How much room does it take in a file or a buffer? | bytes | | What does an encoder or a case mapping work through? | scalars | | Where does a cursor step? Does it fit "maximum 20 characters"? | graphemes | Bytes measure storage, scalars are what an encoding works with, and graphemes are what a person sees. A text field that limits a name to 20 "characters" by counting bytes would reject a perfectly short name written in Ukrainian, and a cursor that stepped by scalars would stop between a letter and its accent. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Text/Unicode){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // The Encoding lesson found two ways to count the same text: code units and scalars. There is a // third, and it is the one a reader means. Text has three levels: // // bytes how UTF-8 stores it // scalars the characters Unicode numbers, one `char32` each // graphemes what a person would point at and call one character // // A grapheme can be made of several scalars. An accent may be its own scalar that attaches to // the letter before it, and a flag is two "regional indicator" letters that a screen draws as // one picture. The Unicode package knows where graphemes begin and end. import Io::PrintLine; import Unicode::CountGraphemes; // The same text twice: as UTF-8 for the byte count, and as UTF-32, where one unit is one scalar. func Count(utf8: char8[..], utf32: char32[..]) { PrintLine("{} bytes {}, scalars {}, graphemes {}", utf8, utf8.length, utf32.length, CountGraphemes(utf32)); } func Main() -> int { // Plain ASCII: all three counts agree, which is why the difference is easy to miss. Count("cafe", c32"cafe"); // `é` as one scalar: two bytes, but one scalar and one grapheme. Count("caf\u{E9}", c32"caf\u{E9}"); // `e` followed by U+0301, a combining acute accent. It looks the same as the line above, // yet every count differs: six bytes, five scalars, four graphemes. Count("cafe\u{301}", c32"cafe\u{301}"); // The Ukrainian flag: two regional indicators, four bytes each, drawn as one grapheme. Count("\u{1F1FA}\u{1F1E6}", c32"\u{1F1FA}\u{1F1E6}"); // Which count is right depends on the question. Bytes measure storage, scalars are what an // encoding works with, and graphemes are what a cursor steps over or a "maximum 20 // characters" rule should count. return 0; } ``` Besides `Io`, its `Rux.toml` lists `Unicode` under `[Dependencies]`. ## Run it ```sh cd Examples/Text/Unicode rux run ``` ```text cafe bytes 4, scalars 4, graphemes 4 café bytes 5, scalars 4, graphemes 4 café bytes 6, scalars 5, graphemes 4 🇺🇦 bytes 8, scalars 2, graphemes 1 ``` ## Common mistakes ::mistake **Counting graphemes in UTF-8.**:br`CountGraphemes` takes `char32[..]`. `CountGraphemes(utf8)` fails with: ```text error: argument 1 to 'CountGraphemes' has type 'char8[..]', but parameter 'text' requires 'char32[..]' ``` :: ::mistake **Assuming text that looks the same is the same.**:br The two `café` lines print identically, but one is 5 bytes and the other 6. Compared byte by byte they are different texts. Deciding that they mean the same thing is called *normalisation*, and it is a separate step. :: ## Try it yourself 1. Count the family emoji 👨‍👩‍👧, written as `"\u{1F468}\u{200D}\u{1F469}\u{200D}\u{1F467}"`. How many scalars does one picture take? 2. Count a waving hand with a skin tone, `"\u{1F44B}\u{1F3FD}"`. 3. Count `"한국"`, then the same first syllable written as three separate jamo, `"\u{1112}\u{1161}\u{11AB}"`. 4. Write a function that reports whether a name fits in 20 graphemes. ## Learn more - [Encoding](https://rux-lang.dev/docs/learn/encoding) — bytes and scalars - [UTF-8](https://rux-lang.dev/docs/learn/utf8) — how the bytes are decoded into scalars - [Unicode case](https://rux-lang.dev/docs/learn/unicode-case) — another Unicode operation that works on scalars - [Format](https://rux-lang.dev/docs/learn/format) — what a placeholder's width counts # Unicode case ::note **You'll need**: [Unicode](https://rux-lang.dev/docs/learn/unicode), [Writable slice](https://rux-lang.dev/docs/learn/writable-slice) :: Changing case looks like a job for one character at a time: `a` becomes `A`, `é` becomes `É`. For most letters that is true. A few break the pattern. The German `ß` has no single uppercase letter — it becomes `SS`. The ligature `fi` becomes `FI`. A function that returns one character has nowhere to put the second letter, so the Unicode package offers two kinds of mapping: a **simple** one, one scalar in and one out, and a **full** one that may write several. ## The simple mapping `ToUpperSimple` takes a `char32` and returns a `char32`. It is easy to use — print each result as it comes: ```rux func UpperSimple(text: char32[..]) { for c in text { Print("{}", ToUpperSimple(c)); } PrintLine(""); } ``` For a character whose uppercase form is more than one letter, there is no right single answer, so the simple mapping leaves it unchanged: `Straße` becomes `STRAßE`. ## The full mapping writes into a buffer `ToUpperFull` writes its answer — up to three scalars — into a buffer you provide, and reports how many it wrote: ```rux ToUpperFull(scalar: char32, into: var char32[..], written: *var uint) -> bool ``` ```rux var mapped: char32[3]; var written: uint = 0; var total: uint = 0; for c in text { if ToUpperFull(c, mapped[..], @written) { for i in 0..written { Print("{}", mapped[i]); } total += written; } } ``` Three parts of that call deserve a closer look: - **`mapped[..]`** is a [writable slice](https://rux-lang.dev/docs/learn/writable-slice) of the buffer, for `ToUpperFull` to fill. Three scalars is the most any character maps to. - **`@written`** hands over *where* `written` lives, so the function can store the count there. That is a pointer — the subject of [Pointer](https://rux-lang.dev/docs/learn/pointer) and [Out parameter](https://rux-lang.dev/docs/learn/out-parameter) in the Memory part. For now, read it as "put the count in `written`". - **The `bool` result** is `false` only if the buffer is too small for the answer. ## Where simple and full disagree | Text | Simple | Full | Scalars | | -------------- | -------------- | -------------- | ---------- | | `crème brûlée` | `CRÈME BRÛLÉE` | `CRÈME BRÛLÉE` | 12 from 12 | | `Straße` | `STRAßE` | `STRASSE` | 7 from 6 | | `fix` | `fiX` | `FIX` | 3 from 2 | ```mermaid flowchart LR c["`ß`"] -- "`ToUpperSimple`" --> s["`ß`
no single uppercase,
left unchanged"] c -- "`ToUpperFull`" --> f["`S S`
`written = 2`"] ``` Ordinary letters, accented or not, map one to one either way. Only the special cases separate the two — and when they do, the uppercase text is **longer** than the text it came from. So uppercasing text is a text-to-text operation, not a loop that swaps each character in place. Code that converts a fixed-size buffer in place, character by character, is quietly wrong for German, and for a handful of other languages too. Lowercase has its own pair, `ToLowerSimple` and `ToLowerFull`. It has special cases of its own: the Turkish capital `İ`, a dotted I, lowercases in full to `i` followed by a combining dot — two scalars. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Text/UnicodeCase){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // Changing case looks like a job for one character at a time: `a` becomes `A`, `é` becomes `É`. // For most letters that is true, and the Unicode package's "simple" mappings do exactly that, // one scalar in and one scalar out. // // A few characters break the pattern. The German `ß` has no single uppercase letter; it becomes // "SS". The ligature `fi` becomes "FI". A function that returns one `char32` has nowhere to put // the second letter, so the simple mapping leaves such a character unchanged. The "full" mapping // writes up to three scalars into a buffer instead, and so uppercase text can be longer than the // text it came from. import Io::{ Print, PrintLine }; import Unicode::{ ToUpperFull, ToUpperSimple }; func UpperSimple(text: char32[..]) { for c in text { Print("{}", ToUpperSimple(c)); } PrintLine(""); } func UpperFull(text: char32[..]) { // Three scalars is the most any character maps to. `mapped[..]` is a writable view of the // buffer for `ToUpperFull` to fill, and it stores how many scalars it wrote in `written`. // The `@` hands over where `written` lives so the function can write there; that is a // pointer, the subject of the Memory part. The call returns false only if the buffer is // too small. var mapped: char32[3]; var written: uint = 0; var total: uint = 0; for c in text { if ToUpperFull(c, mapped[..], @written) { for i in 0..written { Print("{}", mapped[i]); } total += written; } } PrintLine(" ({} scalars from {})", total, text.length); } func Main() -> int { // Ordinary letters, accented or not, map one to one either way. UpperSimple(c32"crème brûlée"); UpperFull(c32"crème brûlée"); PrintLine(""); // Here the two disagree. The simple mapping keeps `ß` and `fi` as they were; the full // mapping spells them out, and the text grows. UpperSimple(c32"Straße"); UpperFull(c32"Straße"); UpperSimple(c32"fix"); UpperFull(c32"fix"); // So uppercasing text is a text-to-text operation, not a loop that swaps each character // in place. Lowercase has its own pair, `ToLowerSimple` and `ToLowerFull`. return 0; } ``` Besides `Io`, its `Rux.toml` lists `Unicode` under `[Dependencies]`. ## Run it ```sh cd Examples/Text/UnicodeCase rux run ``` ```text CRÈME BRÛLÉE CRÈME BRÛLÉE (12 scalars from 12) STRAßE STRASSE (7 scalars from 6) fiX FIX (3 scalars from 2) ``` ## Common mistakes ::mistake **A buffer too small for the answer.**:br`ToUpperFull('ß', small[..], @written)` with `var small: char32[1];` returns `false` and writes nothing usable — `SS` needs two scalars. Use a buffer of three, which fits every character. :: ::mistake **Expecting case changes to undo each other.**:br Uppercasing `Straße` gives `STRASSE`, and lowercasing that gives `strasse`, not `straße`. The full mappings lose information, so a round trip does not bring back the original. :: ::mistake **Ignoring the result.**:br If `ToUpperFull` returns `false`, `written` says nothing about this character. The program checks the result with `if` before reading the buffer; do the same. :: ## Try it yourself 1. Write `LowerFull` in the same shape as `UpperFull`, and lowercase `c32"İSTANBUL"`. How many scalars come out of eight? 2. Lowercase `c32"STRASSE"` with it. Do you get `straße` back? 3. Uppercase `c32"floor"` both ways. (`fl` is another ligature.) 4. Change `UpperFull` to count how many characters had no single-scalar answer, that is, how many times `written` was greater than 1. ## Learn more - [Unicode](https://rux-lang.dev/docs/learn/unicode) — scalars and graphemes - [Writable slice](https://rux-lang.dev/docs/learn/writable-slice) — the `mapped[..]` the function fills - [Out parameter](https://rux-lang.dev/docs/learn/out-parameter) — what `@written` is, properly explained - [String builder](https://rux-lang.dev/docs/learn/string-builder) — `AppendScalar` collects the mapped scalars into text # Format ::note **You'll need**: [Console](https://rux-lang.dev/docs/learn/console), [Unicode](https://rux-lang.dev/docs/learn/unicode) :: Every lesson so far has used `{}` to drop a value into a line. A placeholder can also say how much room the value gets and where in that room it sits — which is how output lines up in columns. The instructions go after a colon inside the braces, and are called the placeholder's **spec**. The spec belongs to the placeholder, not to the value, so the same value can be laid out differently in different places without being changed. ## The spec | Placeholder | Means | `"Rux"` becomes | | ----------- | -------------------------------- | --------------- | | `{}` | the value as it is | `Rux` | | `{:8}` | at least 8 characters wide | `Rux` | | `{:<8}` | … with the value on the left | `Rux` | | `{:^8}` | … in the middle | `Rux` | | `{:>8}` | … on the right | `Rux` | | `{:*^8}` | … in the middle, padded with `*` | `**Rux***` | The parts always come in the same order: an optional fill character, an optional alignment (`<`, `^` or `>`), then the width. ```mermaid flowchart LR open["`{:`"] --> fill["fill
optional
`*` `.` `-` …"] --> align["alignment
optional
`<` `^` `>`"] --> width["width
`8`"] --> close["`}`"] ``` ## Width is a minimum A shorter value is padded up to the width. Numbers go to the right by default and text to the left, which is what a column of each usually wants: ```rux PrintLine("number [{:8}]", count); PrintLine("text [{:8}]", word); ``` Width never cuts. A value wider than its field is printed whole and pushes past it, so `{:2}` with `123456` prints all six digits: ```rux PrintLine("narrow [{:2}]", 123456); ``` ## Alignment and fill An alignment overrides the default, for numbers and text alike: ```rux PrintLine("left [{:<8}] [{:<8}]", count, word); PrintLine("centre [{:^8}] [{:^8}]", count, word); PrintLine("right [{:>8}] [{:>8}]", count, word); ``` When the padding does not split evenly, centring puts the extra space on the right: `Rux` in eight is two spaces, `Rux`, three spaces. A fill character goes before the alignment and replaces the spaces: ```rux PrintLine("dots [{:.<8}] [{:.>8}]", word, count); PrintLine("stars [{:*^8}]", word); ``` ## Width counts characters, not bytes `née` is four bytes but three characters, and the width counts characters — Unicode scalars — so accented text lines up with plain text: ```rux PrintLine("accent [{:8}] [{:8}]", "née", "nee"); ``` That is what makes a table work, whatever is in it. Each row uses the same three placeholders, and the columns line up even though `crêpes` has a two-byte `ê`: ```rux PrintLine("{:<10}{:>6}{:>8}", "item", "count", "price"); PrintLine("{:<10}{:>6}{:>8}", "widgets", 12, 450); PrintLine("{:<10}{:>6}{:>8}", "sprockets", 5, 1975); PrintLine("{:<10}{:>6}{:>8}", "crêpes", 1440, 25); ``` The name column is left-aligned in 10, and the two number columns are right-aligned in 6 and 8 — the usual choice for figures, so their units line up. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Text/Format){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // Every lesson has used `{}` to drop a value into a line. A placeholder can also say how much // room the value gets and where in that room it sits, which is how output lines up in columns. // The part after a colon is the placeholder's spec: // // {:8} at least 8 characters wide // {:<8} ... with the value on the left // {:^8} ... in the middle // {:>8} ... on the right // {:*^8} ... in the middle, padded with `*` instead of spaces // // The spec belongs to the placeholder, not to the value, so the same value can be laid out // differently in different places without being changed. import Io::PrintLine; func Main() -> int { let count = 42; let word = "Rux"; // Width is a minimum. Shorter values are padded; numbers go to the right by default and // text to the left, which is what a column of each usually wants. PrintLine("number [{:8}]", count); PrintLine("text [{:8}]", word); // Width never cuts. A value wider than its field is printed whole and pushes past it. PrintLine("narrow [{:2}]", 123456); // Alignment overrides the default, for numbers and text alike. PrintLine("left [{:<8}] [{:<8}]", count, word); PrintLine("centre [{:^8}] [{:^8}]", count, word); PrintLine("right [{:>8}] [{:>8}]", count, word); // A fill character before the alignment replaces the spaces. PrintLine("dots [{:.<8}] [{:.>8}]", word, count); PrintLine("stars [{:*^8}]", word); // Width counts characters, not bytes, so accented text lines up with plain text. PrintLine("accent [{:8}] [{:8}]", "née", "nee"); // What all of this is for: a table whose columns line up whatever is in them. PrintLine(""); PrintLine("{:<10}{:>6}{:>8}", "item", "count", "price"); PrintLine("{:<10}{:>6}{:>8}", "widgets", 12, 450); PrintLine("{:<10}{:>6}{:>8}", "sprockets", 5, 1975); PrintLine("{:<10}{:>6}{:>8}", "crêpes", 1440, 25); return 0; } ``` ## Run it ```sh cd Examples/Text/Format rux run ``` ```text number [ 42] text [Rux ] narrow [123456] left [42 ] [Rux ] centre [ 42 ] [ Rux ] right [ 42] [ Rux] dots [Rux.....] [......42] stars [**Rux***] accent [née ] [nee ] item count price widgets 12 450 sprockets 5 1975 crêpes 1440 25 ``` ## Common mistakes ::mistake **More placeholders than values, or fewer.**:br The compiler counts the placeholders of a pattern written in the call. `PrintLine("{} and {}", 1)` fails with: ```text error: format string has 2 placeholders, but 1 argument was provided ``` `PrintLine("{}", 1, 2)` fails with: ```text format string has 1 placeholder, but 2 arguments were provided ``` :: ::mistake **A spec the value does not understand.**:br The compiler counts placeholders but does not check what each spec asks for. An integer has no `z` style, so `PrintLine("[{:z}]", 1)` prints only `[`, with no line end, and the rest of the line is lost — `PrintLine` stops at the placeholder it cannot honour and returns an `IoError`, which an ignored result never shows. [Render](https://rux-lang.dev/docs/learn/render) reports such a pattern properly. :: ::mistake **Expecting width to count what you see.**:br Width counts scalars, not [graphemes](https://rux-lang.dev/docs/learn/unicode). A `café` spelled with a combining accent is five scalars, so `{:8}` pads it with three spaces and it looks one column short. Wide characters such as emoji take two columns on most terminals but count as one. :: ## Try it yourself 1. Add a fourth column, `total`, that is `count * price`, right-aligned in 10. 2. Print a title centred in 24 characters between rows of `=`, using a fill character for both. 3. Make the item column dotted — `widgets...` — so the eye can follow each row. 4. Put a name longer than 10 characters in the table. What happens to the columns? ## Learn more - [Console](https://rux-lang.dev/docs/learn/console) — `{}` placeholders from Part 1 - [Format number](https://rux-lang.dev/docs/learn/format-number) — precision, bases, zeros and signs - [Display](https://rux-lang.dev/docs/learn/display) — how your own type receives the spec - [Render](https://rux-lang.dev/docs/learn/render) — the same patterns, formatted into a `String` # Format number ::note **You'll need**: [Format](https://rux-lang.dev/docs/learn/format), [Float](https://rux-lang.dev/docs/learn/float), [Literal](https://rux-lang.dev/docs/learn/literal) :: [Format](https://rux-lang.dev/docs/learn/format) gave a value room and a place in it. Numbers have a few more choices of their own: how many digits after the point, which base, whether to pad with zeros and whether to show a `+`. They are written in the same spec after the colon, and none of them changes the number — they only decide how it is spelled. ## The number spec | Spec | Means | Example | Prints | | ------- | ------------------------------------------------ | --------------- | ---------------- | | `{:.2}` | two digits after the decimal point | `3.14159…` | `3.14` | | `{:e}` | scientific notation; `E` for a capital mark | `6.02214076e23` | `6.02214076e+23` | | `{:x}` | hexadecimal; `X` capitals, `o` octal, `b` binary | `255` | `ff` | | `{:#x}` | … with the prefix that names the base | `255` | `0xff` | | `{:06}` | padded to 6 with zeros instead of spaces | `42` | `000042` | | `{:+}` | a sign even when the number is positive | `7` | `+7` | They combine with the width and alignment from the Format lesson, in a fixed order: fill and alignment, then `+`, then `#`, then `0` and the width, then the precision, then the letter for the base or notation. So `{:>10.2}` is "right-aligned in 10, two digits after the point". ```mermaid flowchart LR a["fill + align
`>`"] --> s["sign
`+`"] --> h["prefix
`#`"] --> z["zeros + width
`08`"] --> p["precision
`.2`"] --> k["kind
`x` `X` `o` `b` `e` `E`"] ``` ## Digits after the point With no precision, a float prints with as few digits as it takes to read back as the same value — which is why `0.1` prints as `0.1` and not as the long binary approximation. A precision fixes the number of digits instead, rounding the rest: ```rux PrintLine("pi {}", pi); PrintLine("pi .2 {:.2}", pi); PrintLine("pi .0 {:.0}", pi); PrintLine("0.1 {}", 0.1); ``` Rounding can carry all the way up: 9.99 to one digit is `10.0`, not `9.10`. And exact halves round to the **even** digit, so `0.125` becomes `0.12` while `0.375` becomes `0.38`: ```rux PrintLine("9.99 .1 {:.1}", 9.99); PrintLine("halves .2 {:.2} {:.2}", 0.125, 0.375); ``` Rounding halves to even, rather than always up, keeps a long column of rounded figures from drifting upwards as a whole. A precision combines with a width, which is how money lines up: ```rux PrintLine("money [{:>10.2}]", 1234.5); ``` ## Scientific notation Scientific notation puts one digit before the point and moves the rest into the exponent. It is the readable way to print very large or very small values, and it takes a precision too: ```rux PrintLine("scientific {:e} {:E} {:.2e}", 6.02214076e23, 0.00025, 1234.5678); ``` `6.02214076e+23` means 6.02214076 × 10²³, and `2.5E-04` means 2.5 × 10⁻⁴. ## Bases, prefixes, zeros and signs The same 255 in four spellings, then with the prefixes that name each base — the same prefixes a [literal](https://rux-lang.dev/docs/learn/literal) uses: ```rux PrintLine("bases {} {:x} {:X} {:o} {:b}", value, value, value, value, value); PrintLine("prefixed {:#x} {:#o} {:#b}", value, value, value); ``` Zeros pad **between** the sign or prefix and the digits, where spaces would look wrong — so `-42` padded to six is `-00042`, not `000-42`: ```rux PrintLine("zeros {:06} {:06} {:#06x}", 42, -42, value); ``` And `+` keeps a column of mixed signs aligned, because every number then starts with a sign: ```rux PrintLine("signs {:+} {:+} {:+.1}", 7, -7, 0.25); ``` Note `0.25` to one digit with `+`: `+0.2`, the even neighbour again. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Text/FormatNumber){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // The Format lesson gave a value room and a place in it. Numbers have a few more choices of // their own, written in the same spec after the colon: // // {:.2} two digits after the decimal point // {:x} hexadecimal; `X` for capitals, `o` octal, `b` binary // {:#x} ... with the prefix that names the base: 0x, 0o, 0b // {:08} padded to 8 with zeros instead of spaces // {:+} a sign even when the number is positive // {:e} scientific notation, 1.5e+03; `E` for a capital mark // // None of this changes the number. It only decides how the number is spelled. import Io::PrintLine; func Main() -> int { let pi = 3.14159265358979; // A float prints with as few digits as it takes to read back as the same value. A // precision fixes the number of digits after the point instead, rounding the rest. PrintLine("pi {}", pi); PrintLine("pi .2 {:.2}", pi); PrintLine("pi .0 {:.0}", pi); PrintLine("0.1 {}", 0.1); // Rounding can carry all the way up: 9.99 to one digit is 10.0, not 9.10. PrintLine("9.99 .1 {:.1}", 9.99); // Exact halves round to the even digit, so 0.125 becomes 0.12 and 0.375 becomes 0.38. PrintLine("halves .2 {:.2} {:.2}", 0.125, 0.375); // Precision combines with the width and alignment from the Format lesson. PrintLine("money [{:>10.2}]", 1234.5); // Scientific notation puts one digit before the point and moves the rest into the exponent. // It is the readable way to print very large or very small values, and takes a precision too. PrintLine("scientific {:e} {:E} {:.2e}", 6.02214076e23, 0.00025, 1234.5678); // Bases. The same 255 in four spellings, then with their prefixes. let value = 255; PrintLine("bases {} {:x} {:X} {:o} {:b}", value, value, value, value, value); PrintLine("prefixed {:#x} {:#o} {:#b}", value, value, value); // Zeros pad between the sign or prefix and the digits, where spaces would look wrong. PrintLine("zeros {:06} {:06} {:#06x}", 42, -42, value); // `+` keeps a column of mixed signs aligned. PrintLine("signs {:+} {:+} {:+.1}", 7, -7, 0.25); return 0; } ``` ## Run it ```sh cd Examples/Text/FormatNumber rux run ``` ```text pi 3.14159265358979 pi .2 3.14 pi .0 3 0.1 0.1 9.99 .1 10.0 halves .2 0.12 0.38 money [ 1234.50] scientific 6.02214076e+23 2.5E-04 1.23e+03 bases 255 ff FF 377 11111111 prefixed 0xff 0o377 0b11111111 zeros 000042 -00042 0x00ff signs +7 -7 +0.2 ``` ## Common mistakes ::mistake **Expecting a decimal half to round up.**:br`{:.2}` of `2.675` prints `2.67`, and `{:.1}` of `0.35` prints `0.3`. A float cannot hold most decimal fractions exactly: the stored value is a hair below the half, so it rounds down. If amounts must round exactly, keep them as whole cents in an integer, as `Money` did in [Display](https://rux-lang.dev/docs/learn/display). :: ::mistake **Expecting hexadecimal to show a negative number's bits.**:br`{:x}` of `-1` prints `-1`: a sign and the magnitude, not two's complement. To see the bits, convert first — `{:x}` of `-1 as uint8` prints `ff`. :: ::mistake **A spec the value cannot honour.**:br`PrintLine("[{:x}]", 2.5)` compiles, but a float has no hexadecimal spelling: it prints only `[`, with no line end, and `PrintLine` returns an `IoError`. [Render](https://rux-lang.dev/docs/learn/render) reports the same request as `FormatError::UnsupportedRequest`. :: ## Try it yourself 1. Print `pi` with 0, 2, 4 and 8 digits after the point, in a right-aligned column of width 12. 2. Print the numbers 0 to 15 as two-digit hexadecimal: `00`, `01`, … `0f`. 3. Print `42` as an 8-bit binary number with its prefix: `0b00101010`. 4. Print the speed of light, `2.998e8`, and the charge of an electron, `1.6e-19`, in scientific notation with two digits after the point. ## Learn more - [Format](https://rux-lang.dev/docs/learn/format) — width, alignment and fill - [Literal](https://rux-lang.dev/docs/learn/literal) — the same bases, written in source - [Float](https://rux-lang.dev/docs/learn/float) — why `0.1 + 0.2` is not `0.3`, and why `2.675` rounds down - [Parse](https://rux-lang.dev/docs/learn/parse) — reading these spellings back into numbers # Render ::note **You'll need**: [Format number](https://rux-lang.dev/docs/learn/format-number), [String](https://rux-lang.dev/docs/learn/string), [Outcome](https://rux-lang.dev/docs/learn/outcome), [Variant match](https://rux-lang.dev/docs/learn/variant-match) :: `PrintLine` formats text and sends it straight to the console. Often you want the formatted text itself — to keep it, measure it, pass it on, or print it later. `Render`, from the Format package, does the same formatting but hands the text back as a [`String`](https://rux-lang.dev/docs/learn/string): ```rux Render(allocator, pattern, values...) -> String ! FormatError ``` Its result is fallible, and the way it fails is the other half of this lesson: a wrong pattern is found **before** anything is written, and the error says exactly what was wrong. ## Text you keep `InvoiceCode` builds a code such as `INV-0042` once, as a value the caller owns: ```rux func InvoiceCode(allocator: Allocator, number: int) -> String ! FormatError { return Render(allocator, "INV-{:04}", number); } ``` The pattern is the same as `PrintLine`'s — `{:04}` is the zero padding from [Format number](https://rux-lang.dev/docs/learn/format-number). Each call produces a `String` that lives on after it, unlike a printed line, so `Main` can print both codes in one line and measure one of them: ```rux let first = InvoiceCode(allocator, 7)?; let second = InvoiceCode(allocator, 42)?; PrintLine("codes {} and {}, {} bytes each", first, second, first.Length()); ``` ## Why it can fail Two kinds of thing can go wrong. The `String` needs memory, and the pattern itself can be wrong. `FormatError` is a variant with a case for each: | Case | When | | -------------------------------------- | ------------------------------------------------------------------ | | `InvalidSpecification(at)` | a spec does not parse; `at` is the byte where it stopped | | `UnsupportedRequest` | a spec parses, but asks for something this value does not support | | `ArgumentCountMismatch(wanted, given)` | placeholders and values do not match in number | | `InsufficientCapacity` | a destination of fixed size cannot take the whole text | | `ValueOutOfRange` | a valid value cannot be shown in the form asked for | | `TextFailure(kind)` | text handling failed — this is where running out of memory arrives | | `WriterFailure` | the destination failed on its own terms | `Show` takes an outcome apart with two nested `match`es. The cases that carry a position or counts are taken apart; everything else prints its own description through `else`: ```rux func Show(outcome: String ! FormatError) { match outcome { .Success(text) => PrintLine("rendered {}", text), .Failure(error) => match error { .InvalidSpecification(at) => PrintLine("refused bad spec at byte {}", at), .ArgumentCountMismatch(wanted, given) => PrintLine("refused {} placeholders but {} values", wanted, given), else => PrintLine("refused {}", error) } } } ``` ## One right pattern and three wrong ones ```rux Show(Render(allocator, "{} of {}", 3, 10)); Show(Render(allocator, "[{:>>>}]", 3)); let pattern = "{}, {} and {}"; Show(Render(allocator, pattern, 3, 4)); Show(Render(allocator, "{:x}", "text")); ``` | Pattern | Values | Result | | ------------ | -------- | --------------------------------------------------------------------------------------- | | `"{} of {}"` | 3, 10 | `3 of 10` | | `"[{:>>>}]"` | 3 | `InvalidSpecification(5)` — `>>` is a fill and an alignment; the third `>` fits nowhere | | `pattern` | 3, 4 | `ArgumentCountMismatch(3, 2)` | | `"{:x}"` | `"text"` | `UnsupportedRequest` — text has no hexadecimal | ```mermaid flowchart LR r["`Render(allocator, pattern, values…)`"] --> m{"Memory for
the `String`?"} m -- "no" --> f2["`Failure`:
`TextFailure(OutOfMemory)`"] m -- "yes" --> c{"Is the pattern right
for these values?"} c -- "no" --> f["`Failure`: the `FormatError` case;
no half rendering is returned"] c -- "yes" --> s["`Success`: the `String`"] ``` ## Counted while compiling, or while running Why is the third pattern in a variable? Because the compiler counts the placeholders of a pattern written in the call itself. `Render(allocator, "{}, {} and {}", 3, 4)` does not build at all. A pattern that arrives as a value — read from a file, chosen at run time — can be counted only when it runs, and that is when `ArgumentCountMismatch` appears. `PrintLine` refuses the same patterns too, but its `IoError` can only say that the request was invalid, not where or why. When a pattern might be wrong, `Render` is the one that tells you. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Text/Render){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // `PrintLine` formats text and sends it straight to the console. `Render`, from the Format // package, does the same formatting but hands the text back as a `String`, to be kept, measured, // passed on or printed later: // // Render(allocator, pattern, values...) -> String ! FormatError // // The result is fallible because two things can go wrong. The String needs memory, and the // pattern itself can be wrong: a spec that does not parse, a spec the value cannot honour, or // a different number of placeholders than values. A wrong pattern is found before anything is // written, so a failure never leaves half a rendering behind. import Allocator::{ Allocator, SystemAllocator }; import Format::Render; import Io::PrintLine; import Text::{ FormatError, String }; // Builds a code such as "INV-0042" once, as a value the caller owns. func InvoiceCode(allocator: Allocator, number: int) -> String ! FormatError { return Render(allocator, "INV-{:04}", number); } // Reports either outcome of a render. `FormatError` is a variant, so the cases that carry a // position or counts can be taken apart; the rest print their own description. func Show(outcome: String ! FormatError) { match outcome { .Success(text) => PrintLine("rendered {}", text), .Failure(error) => match error { .InvalidSpecification(at) => PrintLine("refused bad spec at byte {}", at), .ArgumentCountMismatch(wanted, given) => PrintLine("refused {} placeholders but {} values", wanted, given), else => PrintLine("refused {}", error) } } } func Main() -> ! FormatError { var system = SystemAllocator(); let allocator: Allocator = system; // Each call produces a String that lives on after it, unlike a printed line. let first = InvoiceCode(allocator, 7)?; let second = InvoiceCode(allocator, 42)?; PrintLine("codes {} and {}, {} bytes each", first, second, first.Length()); // A pattern that works, then three ways a pattern can be wrong, each refused with its own // case. `PrintLine` refuses the same patterns too, but its `IoError` can only say the // request was invalid, not where or why. Show(Render(allocator, "{} of {}", 3, 10)); Show(Render(allocator, "[{:>>>}]", 3)); // The compiler counts the placeholders of a pattern written in the call itself, so // `Render(allocator, "{}, {} and {}", 3, 4)` does not build: "format string has 3 // placeholders, but 2 arguments were provided". A pattern that arrives as a value is // counted only when it runs. let pattern = "{}, {} and {}"; Show(Render(allocator, pattern, 3, 4)); Show(Render(allocator, "{:x}", "text")); } ``` Besides `Io`, its `Rux.toml` lists `Allocator`, `Format` and `Text` under `[Dependencies]`. ## Run it ```sh cd Examples/Text/Render rux run ``` ```text codes INV-0007 and INV-0042, 8 bytes each rendered 3 of 10 refused bad spec at byte 5 refused 3 placeholders but 2 values refused unsupported formatting request ``` ## Common mistakes ::mistake **Using the result without `?`.**:br`let first = InvoiceCode(allocator, 7);` leaves `first` a `String ! FormatError`. Its next use fails: ```text error: type 'String ! FormatError' has no field 'Length' ``` :: ::mistake **A literal pattern with the wrong number of values.**:br`Render(allocator, "{}, {} and {}", 3, 4)` fails while compiling: ```text error: format string has 3 placeholders, but 2 arguments were provided ``` :: ::mistake **Matching `FormatError` without `else`.**:br Leave out the `else` arm and the inner `match` fails with: ```text error: match on 'FormatError' is not exhaustive; missing FormatError::UnsupportedRequest, FormatError::InsufficientCapacity, … ``` Handle the cases you care about and let `else` print the rest. :: ## Try it yourself 1. Render a price with two digits after the point, `"{:.2}"`, and print its `Length()`. 2. Write `Label(allocator: Allocator, name: char8[..], score: int) -> String ! FormatError` that produces lines such as `Ada.......17`. 3. Pass `Render(allocator, "{:q}", 5)` to `Show`. Which case is it? 4. Change `"[{:>>>}]"` to `"[{:>>}]"`. What does it render? ## Learn more - [Format](https://rux-lang.dev/docs/api/format) in the API reference - [Format](https://rux-lang.dev/docs/learn/format) and [Format number](https://rux-lang.dev/docs/learn/format-number) — the pattern language - [String](https://rux-lang.dev/docs/learn/string) — what `Render` returns - [Variant match](https://rux-lang.dev/docs/learn/variant-match) — taking `FormatError` apart # Parse ::note **You'll need**: [Format number](https://rux-lang.dev/docs/learn/format-number), [Outcome](https://rux-lang.dev/docs/learn/outcome), [Variant match](https://rux-lang.dev/docs/learn/variant-match), [Catch fallback](https://rux-lang.dev/docs/learn/catch-fallback) :: Parsing is formatting in reverse: text in, value out. Unlike formatting, it fails all the time, because the text usually comes from a person or a file and may not spell a number at all — `"seven"`, `"12abc"`, or nothing. So every parser in the Format package returns a [fallible](https://rux-lang.dev/docs/learn/fallible), and the failure says what was wrong and where: ```rux ParseInt32(text) -> int32 ! ParseError ``` ## What can go wrong `ParseError` is a variant, and every case but the first carries the byte position where the trouble was found: | Case | Means | | ---------------------- | --------------------------------------------------------------- | | `Empty` | there was no text at all | | `InvalidCharacter(at)` | the byte at `at` is not part of a number | | `Overflow(at)` | a well-formed number too large for the type, usually at its end | | `OutOfMemory(at)` | only the very widest number types can hit this one | `Describe` names each case. A `match` on a variant must be [exhaustive](https://rux-lang.dev/docs/learn/exhaustive), so even the case an `int32` can never hit gets an arm: ```rux func Describe(error: ParseError) { match error { .Empty => PrintLine("empty text"), .InvalidCharacter(at) => PrintLine("not a digit at byte {}", at), .Overflow(at) => PrintLine("too large for an int32, at byte {}", at), .OutOfMemory(_) => PrintLine("out of memory") } } ``` `Read` then opens the outcome with `.Success` and `.Failure`, as in [Outcome](https://rux-lang.dev/docs/learn/outcome): ```rux func Read(text: char8[..]) { match ParseInt32(text) { .Success(value) => PrintLine("[{}] {}", text, value), .Failure(error) => { Print("[{}] refused, ", text); Describe(error); } } } ``` ## What counts as a number A sign is understood, and so is a base prefix of the kind `{:#x}` writes, so `"0x1F"` reads as 31. Everything else must be digits. The parser does not skip spaces or stop at the first non-digit: the **whole** text must be a number, or the answer is a failure saying which byte is wrong. | Text | Result | Why | | --------------- | --------------------- | ----------------------------------------- | | `"42"` | `42` | | | `"-17"` | `-17` | a sign | | `"0x1F"` | `31` | a base prefix, as `{:#x}` writes | | `""` | `Empty` | nothing to read | | `" 42"` | `InvalidCharacter(0)` | a space is not a digit, even at the start | | `"12abc"` | `InvalidCharacter(2)` | `a` is the first byte that is not a digit | | `"2147483647"` | `2147483647` | the largest `int32` | | `"2147483648"` | `Overflow(10)` | one more does not fit | | `"-2147483648"` | `-2147483648` | the negative side holds one more | ```mermaid flowchart LR t(["`text`"]) --> e{"empty?"} e -- "yes" --> E["`Empty`"] e -- "no" --> d{"sign, prefix and digits
— and nothing else?"} d -- "no" --> I["`InvalidCharacter(at)`"] d -- "yes" --> f{"fits an `int32`?"} f -- "no" --> O["`Overflow(at)`"] f -- "yes" --> S["`Success(value)`"] ``` An `int32` holds −2147483648 to 2147483647. The negative side holds one more than the positive, so `-2147483648` parses even though `2147483648` does not. ## A fallback in one expression Often a failure just means "use a default". With `catch`, as in [Catch fallback](https://rux-lang.dev/docs/learn/catch-fallback), that takes one expression: ```rux let fallback = ParseInt32("seven") catch { else => 0 }; ``` ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Text/Parse){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // Parsing is formatting in reverse: text in, value out. Unlike formatting, it fails all the time, // because the text usually comes from a person or a file and may not spell a number at all. // So every parser in the Format package returns a fallible: // // ParseInt32(text) -> int32 ! ParseError // // `ParseError` is a variant, and every case says where in the text the trouble was found: // // Empty there was no text at all // InvalidCharacter(at) the byte at `at` is not part of a number // Overflow(at) a well-formed number too large for an `int32`, usually at its end // OutOfMemory(at) only the very widest number types can hit this one import Format::{ ParseError, ParseInt32 }; import Io::{ Print, PrintLine }; func Describe(error: ParseError) { match error { .Empty => PrintLine("empty text"), .InvalidCharacter(at) => PrintLine("not a digit at byte {}", at), .Overflow(at) => PrintLine("too large for an int32, at byte {}", at), .OutOfMemory(_) => PrintLine("out of memory") } } func Read(text: char8[..]) { match ParseInt32(text) { .Success(value) => PrintLine("[{}] {}", text, value), .Failure(error) => { Print("[{}] refused, ", text); Describe(error); } } } func Main() -> int { // A sign, and a base prefix of the kind `{:#x}` writes, are both understood. Read("42"); Read("-17"); Read("0x1F"); // Malformed text. The parser does not skip spaces or stop at the first non-digit: the // whole text must be a number, or the answer is a failure saying which byte is wrong. Read(""); Read(" 42"); Read("12abc"); // Well-formed but too large. An `int32` holds -2147483648 to 2147483647, and the // negative side holds one more than the positive. Read("2147483647"); Read("2147483648"); Read("-2147483648"); // With `catch`, a failure can become a fallback value in one expression. let fallback = ParseInt32("seven") catch { else => 0 }; PrintLine("[seven] with a fallback {}", fallback); return 0; } ``` Besides `Io`, its `Rux.toml` lists `Format` under `[Dependencies]`. ## Run it ```sh cd Examples/Text/Parse rux run ``` ```text [42] 42 [-17] -17 [0x1F] 31 [] refused, empty text [ 42] refused, not a digit at byte 0 [12abc] refused, not a digit at byte 2 [2147483647] 2147483647 [2147483648] refused, too large for an int32, at byte 10 [-2147483648] -2147483648 [seven] with a fallback 0 ``` ## Common mistakes ::mistake **Using the result as a number.**:br`ParseInt32("41") + 1` fails with: ```text error: operator '+' cannot combine left operand 'int32 ! ParseError' with right operand 'int' ``` Open the outcome first — with `match`, `catch`, or `?` in a fallible function. :: ::mistake **Expecting spaces to be ignored.**:br`" 42"` fails at byte 0 and `"42 "` at byte 2. Text read from a person or a file often has spaces or a line end around it: trim it first with a [string view](https://rux-lang.dev/docs/learn/string-view) — `ParseInt32` accepts a `StringView` as well as a `char8[..]`. :: ::mistake **Writing digit separators.**:br`1_000` is a fine [literal](https://rux-lang.dev/docs/learn/literal) in source, but `ParseInt32("1_000")` fails with `InvalidCharacter(1)`. The parser reads numbers as people type them, not as Rux source spells them. :: ## Try it yourself 1. Parse `"0b101"` and `"0o17"`. Which other prefixes does the parser understand? 2. Parse `"300"` and `"-1"` with `ParseUint8`. What does each report? 3. Trim `" 42\n"` with `StringView::FromValidated(…).Trim()` and parse the view. You will need `Text` in `[Dependencies]` and `import Text::StringView;`. 4. Parse `"3.75"` with `ParseFloat64`, then try `"3,75"`. ## Learn more - [Format](https://rux-lang.dev/docs/api/format) in the API reference - [Format number](https://rux-lang.dev/docs/learn/format-number) — the spellings `ParseInt32` reads back - [Outcome](https://rux-lang.dev/docs/learn/outcome) and [Catch fallback](https://rux-lang.dev/docs/learn/catch-fallback) — opening the result - [Input](https://rux-lang.dev/docs/learn/input) — text typed by a person, the usual thing to parse # Input ::note **You'll need**: [String builder](https://rux-lang.dev/docs/learn/string-builder), [Outcome](https://rux-lang.dev/docs/learn/outcome), [Guard](https://rux-lang.dev/docs/learn/guard), [Break](https://rux-lang.dev/docs/learn/break), [Continue](https://rux-lang.dev/docs/learn/continue) :: Every program so far has only talked. This one listens. Reading what a person types needs somewhere to put text that does not exist yet — a job for a [`StringBuilder`](https://rux-lang.dev/docs/learn/string-builder). `ReadLine`, from the Io package, appends the next line of standard input to one: ```rux ReadLine(builder: &var StringBuilder) -> ! IoError ``` A success means a line arrived, without its line ending; an empty line is still a success. And reaching the end of the input is not a special return value. It is a failure like any other, so a reading loop handles it in the same `match` as a real error — and stops. ## One builder for every line `Main` makes one builder and reuses it. `Clear` empties it before each line but keeps its memory, so after the first few lines the builder rarely needs to grow: ```rux var builder = StringBuilder(allocator); var count = 0; PrintLine("Type some lines, then end the input."); while true { builder.Clear(); match ReadLine(builder) { ``` After a successful read, `builder.View()` is the line, as a [string view](https://rux-lang.dev/docs/learn/string-view): ```rux count += 1; let line = builder.View(); if line.IsEmpty() { PrintLine("line {} is empty", count); } else { PrintLine("line {} is \"{}\", {} bytes", count, line, line.Length()); } ``` ## Telling the failures apart An `IoError` carries a `kind`, an `IoErrorKind`. Two kinds matter to a reading loop, and [guards](https://rux-lang.dev/docs/learn/guard) on the `.Failure` arms pick them out: ```rux match ReadLine(builder) { .Success(_) => {}, .Failure(error) if error.kind == IoErrorKind::EndOfStream => break, .Failure(error) if error.kind == IoErrorKind::InvalidText => { count += 1; PrintLine("line {} is not UTF-8 text", count); continue; }, .Failure(_) => { PrintLine("the input could not be read"); return 1; } } ``` | Outcome | Means | The loop | | ----------------- | ------------------------------------------- | ---------- | | `.Success` | a line is in the builder | prints it | | `EndOfStream` | there is no more input | `break` | | `InvalidText` | the line was not UTF-8; it has been skipped | `continue` | | any other failure | the input really could not be read | `return 1` | ```mermaid flowchart LR c["`builder.Clear()`"] --> r["`ReadLine(builder)`"] r -- "`Success`" --> p["print the line"] --> c r -- "`InvalidText`" --> s["report it"] --> c r -- "`EndOfStream`" --> e["`break`: report
how many lines"] r -- "anything else" --> x["`return 1`"] ``` A line that is not valid UTF-8 fails with `InvalidText`, but only after the rest of it has been read. So the next call starts cleanly on the next line, and the loop can carry on as if the bad line had been a comment. ## Ending the input Typing at a terminal, nothing ends the input until you say so: **Ctrl+Z** then **Enter** on Windows, **Ctrl+D** elsewhere. Input piped in from another program or a file ends by itself, and an empty pipe ends at once — the very first `ReadLine` fails with `EndOfStream`, and the program reports 0 lines. The line ending is not part of the line, whether it was a Unix `\n` or a Windows `\r\n`, so `"Ada"` is three bytes on every system. A last line with no line ending at all still arrives as a line. `ReadLine` reads from standard input. `ReadLineFrom` reads the same way from any other source of bytes. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Text/Input){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // Reading what a person types needs somewhere to put text that does not exist yet, and that is // a job for a `StringBuilder`. `ReadLine` from the Io package appends the next line to one: // // ReadLine(builder: &var StringBuilder) -> ! IoError // // A success means a line arrived, without its line ending; an empty line is still a success. // Running out of input is not a special return value. It is a failure like any other, an // `IoError` whose `kind` is `IoErrorKind::EndOfStream`, so a reading loop handles it in the same // `match` as a real error, and stops. // // A line is UTF-8 text, so "héllo" arrives as six bytes. A line that is not valid UTF-8 fails // with the kind `IoErrorKind::InvalidText`, but only after the rest of it has been read, so the // next call starts cleanly on the next line and the loop can carry on. `ReadLineFrom` reads the // same way from any other source of bytes. // // Interactively, end the input with Ctrl+Z and Enter on Windows, or Ctrl+D elsewhere. Piped // input ends by itself. import Allocator::{ Allocator, SystemAllocator }; import Io::{ IoErrorKind, PrintLine, ReadLine }; import Text::StringBuilder; func Main() -> int { var system = SystemAllocator(); let allocator: Allocator = system; // One builder serves every line. `Clear` empties it but keeps its memory for the next one. var builder = StringBuilder(allocator); var count = 0; PrintLine("Type some lines, then end the input."); while true { builder.Clear(); match ReadLine(builder) { .Success(_) => {}, .Failure(error) if error.kind == IoErrorKind::EndOfStream => break, .Failure(error) if error.kind == IoErrorKind::InvalidText => { count += 1; PrintLine("line {} is not UTF-8 text", count); continue; }, .Failure(_) => { PrintLine("the input could not be read"); return 1; } } count += 1; let line = builder.View(); if line.IsEmpty() { PrintLine("line {} is empty", count); } else { PrintLine("line {} is \"{}\", {} bytes", count, line, line.Length()); } } PrintLine("end of input after {} line(s)", count); return 0; } ``` Besides `Io`, its `Rux.toml` lists `Allocator` and `Text` under `[Dependencies]`. ## Run it ```sh cd Examples/Text/Input rux run ``` ```text Type some lines, then end the input. Ada line 1 is "Ada", 3 bytes line 2 is empty Grace Hopper line 3 is "Grace Hopper", 12 bytes ^Z end of input after 3 line(s) ``` Piped input ends by itself, and no input at all ends at once: ```sh "Ada", "", "Grace Hopper" | rux run $null | rux run ``` A line is UTF-8 text, and one that is not is reported and skipped. From a POSIX shell: ```sh printf 'h\xc3\xa9llo\n\xff\nGrace Hopper\n' | rux run ``` ```text Type some lines, then end the input. line 1 is "héllo", 6 bytes line 2 is not UTF-8 text line 3 is "Grace Hopper", 12 bytes end of input after 3 line(s) ``` ## Common mistakes ::mistake **Ignoring the result of `ReadLine`.**:br`ReadLine(builder);` on its own fails with: ```text error: fallible result of type '! IoError' is discarded ``` The end of the input is one of the failures, so a loop that could ignore it would never stop. :: ::mistake **Forgetting to clear the builder.**:br`ReadLine` adds to whatever the builder already holds. Without `builder.Clear()` at the top of the loop, each line is added to the ones before it: type `Ada`, an empty line and `Grace`, and the third line reads `"AdaGrace"`. :: ::mistake **Treating end of input as an error.**:br`EndOfStream` arrives through `.Failure`, but it is how every reading loop is meant to end. Match it first, with its own guard, and `break` — only the failures after it are real problems. :: ## Try it yourself 1. Stop the loop early when the line is `quit`. Make `let quit = StringView::FromValidated("quit");` (import `Text::StringView`) and compare with `line.Equals(quit)`. 2. Add up numbers typed one per line with `ParseInt32(line)`, skipping lines that are not numbers, and print the total at the end. `ParseInt32` comes from the Format package, so add `Format` to `[Dependencies]`. 3. Count the words on each line with `line.Split(…)`. 4. Pipe a file into the program: `Get-Content notes.txt | rux run` in PowerShell, or `rux run < notes.txt` in a POSIX shell. ## Learn more - [Io](https://rux-lang.dev/docs/api/io) in the API reference - [String builder](https://rux-lang.dev/docs/learn/string-builder) — what `ReadLine` appends to - [Guard](https://rux-lang.dev/docs/learn/guard) and [Outcome](https://rux-lang.dev/docs/learn/outcome) — the `match` that tells the failures apart - [Parse](https://rux-lang.dev/docs/learn/parse) — turning a line into a number # Lines and joining ::note **You'll need**: [String](https://rux-lang.dev/docs/learn/string), [Unicode case](https://rux-lang.dev/docs/learn/unicode-case), [Iterator](https://rux-lang.dev/docs/learn/iterator) :: Text rarely arrives one value at a time. A file, a pasted list or a reply from a server is one run of bytes with line breaks in it, and a program that wants the entries has to cut it into lines. Going the other way, a program that has a list of names and wants to show them needs them in one text, with a comma between each two. The Text package does both, and changes the case of whole texts too: ```rux import Text::{ FoldCase, Join, StringView, TextError, ToLower, ToUpper }; ``` ## Walking the lines `Lines` is a method of `StringView`. It returns an [iterator](https://rux-lang.dev/docs/learn/iterator), so a `for` loop walks it: ```rux for line in text.Lines() { count += 1; PrintLine("line {} [{}]", count, line); } ``` Each line is a `StringView` of the original bytes, without its line break, so the walk copies nothing and allocates nothing. The text must therefore outlive the loop, as with every view. Three rules decide where the lines are: | Text | Lines | | ------------ | -------------------------------------------------------------- | | `"a\nb"` | `a`, `b` — the last line needs no break | | `"a\r\nb\n"` | `a`, `b` — `\r\n` is one break, and a final break adds no line | | `"a\n\nb"` | `a`, an empty line, `b` — a blank line is kept | | `""` | none at all | So the program's guest list, with five lines, one of them blank and one ending in `\r\n` as Windows writes it, prints five lines with no break characters left in them. ## Joining pieces `Join` takes a slice of views and a separator, and makes one `String` with the separator between each two parts: ```rux let joined = Join(allocator, names[..kept], StringView::FromValidated(", "))?; ``` ```mermaid flowchart LR p1["`Ada Lovelace`"] --> j["`Join` with `, `"] p2["`grace hopper`"] --> j p3["`Alan Turing`"] --> j p4["`Katherine Johnson`"] --> j j --> s["one `String`:
three separators"] ``` There is always one separator fewer than there are parts: one part comes back on its own, and no parts give empty text. That is the job usually done with a loop and a flag that remembers whether a comma is due, and getting it wrong leaves a stray comma at one end. `Join` works out the final length first and allocates once. Like every call that allocates text, it returns `String ! TextError`, so `?` passes a failure on. ## Changing case `ToUpper`, `ToLower` and `FoldCase` make a new `String` from a view. They apply Unicode's full mappings — the ones [Unicode case](https://rux-lang.dev/docs/learn/unicode-case) wrote out a scalar at a time with `ToUpperFull` — to the whole text in one call: ```rux let upper = ToUpper(allocator, StringView::FromValidated("Straße"))?; let lower = ToLower(allocator, StringView::FromValidated("ÉCOLE"))?; ``` `ß` has no single capital letter, so `Straße`, six characters, becomes `STRASSE`, seven. What the three leave out are the mappings that depend on the language or on the letters around one: a Turkish dotless i, or a Greek capital sigma that should become the final `ς` at the end of a word. `ToLower` always gives `σ`. | Function | `Straße` | `STRASSE` | Use it for | | ---------- | --------- | --------- | ----------------------------- | | `ToUpper` | `STRASSE` | `STRASSE` | showing text in capitals | | `ToLower` | `straße` | `strasse` | showing text in small letters | | `FoldCase` | `strasse` | `strasse` | comparing text, ignoring case | ## Comparing without case The last column is the point of `FoldCase`. Two texts that differ only in case fold to the same bytes, so folding both sides and comparing the folds finds a name however it was typed: ```rux let query = FoldCase(allocator, StringView::FromValidated("GRACE HOPPER"))?; for i in 0..kept { let folded = FoldCase(allocator, names[i])?; if folded.Equals(query) { PrintLine("found {} at position {}", names[i], i + 1); } } ``` The comparison is `Equals`. A `String` carries the allocator it came from, which has no `==`, so `folded == query` does not compile. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Text/JoinLines){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // Text read from a file or typed by a person arrives as one run of bytes with line breaks in it. // `Lines` walks that run one line at a time. Each line is a view of the original bytes, without // its break, so the walk copies nothing and allocates nothing. // // `Join` goes the other way: it takes several pieces and makes one String, with a separator // between each two. It is the tidy answer to "a comma after every item but the last". // // `ToUpper`, `ToLower` and `FoldCase` change the case of a whole text and hand back a new String. // They apply Unicode's full mappings, so a letter may become two and the length may change. // `FoldCase` is the one for comparing: two texts that differ only in case fold to the same bytes. import Allocator::{ Allocator, SystemAllocator }; import Io::PrintLine; import Text::{ FoldCase, Join, StringView, TextError, ToLower, ToUpper }; func Main() -> ! TextError { var system = SystemAllocator(); let allocator: Allocator = system; // A guest list as a file might hold it: one line ends in `\r\n`, as Windows writes it, one is // blank, and the text ends with a break. let text = StringView::FromValidated( "Ada Lovelace\r\ngrace hopper\n\n Alan Turing \nKatherine Johnson\n"); // A line ends at `\n` or `\r\n`, and neither is part of the line. The blank line is kept as an // empty line, but the final break does not start another one: this text has five lines. var count = 0; for line in text.Lines() { count += 1; PrintLine("line {} [{}]", count, line); } // Keep the names, trimmed, in an array of views; the blank line is skipped. var names: StringView[8] = [StringView(); 8]; var kept: uint = 0; for line in text.Lines() { let name = line.Trim(); if !name.IsEmpty() { names[kept] = name; kept += 1; } } // Four names, three separators. `Join` allocates the result once, at its final length. let joined = Join(allocator, names[..kept], StringView::FromValidated(", "))?; PrintLine("joined {}", joined); // The parts and the separator are views, not bare literals. Passing ", " as it is fails: // // error: argument 3 to 'Join' has type 'char8[..]', but parameter 'separator' requires // 'StringView' // Case changes make new text. `ß` has no single capital letter, so in upper case it becomes // "SS": six characters in, seven out. let upper = ToUpper(allocator, StringView::FromValidated("Straße"))?; let lower = ToLower(allocator, StringView::FromValidated("ÉCOLE"))?; PrintLine("upper {} ({} characters)", upper, upper.View().ScalarCount()); PrintLine("lower {}", lower); // To compare without regard to case, fold both sides and compare the folds with `Equals`. // Folding the query once and each name once finds "grace hopper" however it was typed. // `folded == query` is refused, since a String carries its allocator, which has no `==`: // // error: structural equality for 'String' is unavailable because element type // 'Allocator' has no '==' operator let query = FoldCase(allocator, StringView::FromValidated("GRACE HOPPER"))?; for i in 0..kept { let folded = FoldCase(allocator, names[i])?; if folded.Equals(query) { PrintLine("found {} at position {}", names[i], i + 1); } } // `Straße` and `STRASSE` differ in case and in length, and still fold to the same text. let street = FoldCase(allocator, StringView::FromValidated("Straße"))?; let shouted = FoldCase(allocator, StringView::FromValidated("STRASSE"))?; PrintLine("same {}", street.Equals(shouted)); } ``` Besides `Io`, its `Rux.toml` lists `Allocator` and `Text` under `[Dependencies]`. ## Run it ```sh cd Examples/Text/JoinLines rux run ``` ```text line 1 [Ada Lovelace] line 2 [grace hopper] line 3 [] line 4 [ Alan Turing ] line 5 [Katherine Johnson] joined Ada Lovelace, grace hopper, Alan Turing, Katherine Johnson upper STRASSE (7 characters) lower école found grace hopper at position 2 same true ``` ## Common mistakes ::mistake **Calling `Lines` on a literal.**:br`for line in "a\nb".Lines()` fails with: ```text error: slice type 'char8[..]' has no member 'Lines' ``` A literal is a plain `char8[..]`. Make a view of it first, with `StringView::FromValidated`. :: ::mistake **A bare literal as the separator.**:br`Join(allocator, names[..kept], ", ")` fails with: ```text error: argument 3 to 'Join' has type 'char8[..]', but parameter 'separator' requires 'StringView' ``` The parts and the separator are all views. The same goes for the text given to `ToUpper`, `ToLower` and `FoldCase`. :: ::mistake **Comparing with `ToLower`.**:br Lowering both sides looks like a case-insensitive comparison, and mostly works, until it meets a letter whose cases differ in length. `ToLower` turns `Straße` into `straße` and `STRASSE` into `strasse`, and the two are not equal. `FoldCase` gives `strasse` for both. :: ::mistake **Counting line breaks to count lines.**:br`"a\nb"` has one `\n` and two lines; `"a\nb\n"` has two of each. Counting the breaks is off by one whenever the last line is unterminated, which is common. Let `Lines` do the counting. :: ## Try it yourself 1. Join the names with `"\n"` instead of `", "`, then walk the result with `Lines`. Do you get the same four names back? 2. Number the non-blank lines only, so that the blank line does not use up a number. 3. Search for `"KATHERINE JOHNSON"` and `"katherine"`. Which one is found, and why? 4. Print `ToUpper` of `"fix"`, written with the single ligature character `fi`, and count its characters with `ScalarCount`. ## Learn more - [String view](https://rux-lang.dev/docs/learn/string-view) — `Trim`, `Split` and the other borrowing operations - [Unicode case](https://rux-lang.dev/docs/learn/unicode-case) — the per-character mappings these functions apply - [String builder](https://rux-lang.dev/docs/learn/string-builder) — building text a piece at a time when `Join` is not enough - [Regular expressions](https://rux-lang.dev/docs/learn/regex) — splitting and searching by pattern rather than by fixed text - [Text transforms](https://rux-lang.dev/docs/api/text/transform) and [`StringView`](https://rux-lang.dev/docs/api/text/string-view) in the API reference - [String literals](https://rux-lang.dev/docs/lang/types/text) in the Rux Reference — escapes such as `\r` and `\n` # Regular expressions ::note **You'll need**: [String](https://rux-lang.dev/docs/learn/string), [Outcome](https://rux-lang.dev/docs/learn/outcome), [Presence](https://rux-lang.dev/docs/learn/presence), [Coalesce exit](https://rux-lang.dev/docs/learn/coalesce-exit) :: Is this an order code? Where in the log is the first time of day? Questions like these can be answered with `StartsWith`, `IndexOf` and a loop over the bytes — and the loop grows a special case for every rule. A **regular expression** states the rules instead, as a short pattern: `\d{2}:\d{2}` is "two digits, a colon, two digits", and the Regex package does the searching. ```rux import Regex::{ Escape, Regex, RegexError, RegexErrorKind }; ``` ## Writing a pattern Most characters in a pattern match themselves. A few have a meaning of their own: | Pattern | Matches | | ---------------- | ------------------------------------------------- | | `abc` | the text `abc` | | `.` | any one character | | `[A-Z]` | one character from a class: here a capital letter | | `\d`, `\w`, `\s` | a digit, a word character, a space of any kind | | `x*`, `x+`, `x?` | zero or more, one or more, or an optional `x` | | `x{4}`, `x{2,3}` | exactly four, or two to three, of `x` | | `a|b` | `a` or `b` | | `^`, `$` | the start and the end of the text | | `\.`, `\*` | a character with a meaning, taken literally | `\d`, `\w` and `\s` know Unicode, so `\d` matches an Arabic-Indic digit as well as `7`, and `(?i)` at the start of a pattern makes it ignore case. The syntax is RE2's, the one Go and Rust use. A pattern is written in a Rux string, where a backslash starts an escape of its own. So every backslash meant for the pattern is doubled: ```rux let code = Regex::New(allocator, "^[A-Z]{3}-\\d{4}$")?; ``` ## Compiling once `Regex::New` compiles the pattern into a `Regex`, which is then searched as many times as needed. It returns `Regex ! RegexError`: a pattern can be malformed, and that is found here, never in the middle of a search. ```mermaid flowchart LR p(["pattern text"]) --> n["`Regex::New`"] n -- "well formed" --> r["`Regex`"] n -- "malformed" --> e["`RegexError`
kind and byte"] r --> s["`IsMatch`, `Find`, `FindAt`
as often as needed"] ``` A `RegexError` has two fields: `kind`, a `RegexErrorKind` enum saying what went wrong, and `offset`, the byte of the pattern where it went wrong. The program turns a few kinds into words: ```rux func Check(allocator: Allocator, pattern: char8[..]) { match Regex::New(allocator, pattern) { .Success(_) => PrintLine("{:<10} compiles", pattern), .Failure(error) => PrintLine("{:<10} {} at byte {}", pattern, Reason(error.kind), error.offset) } } ``` The last pattern it checks, `(a)\1`, is a **backreference** — "whatever group 1 matched, again". The package refuses it, and lookaround too, as `RegexErrorKind::Unsupported`. Without them a search never needs to go back and try again, so it takes time in proportion to the length of the text, whatever the pattern. A pattern that would make a backtracking matcher run for years, such as `(a*)*b`, is searched here as quickly as any other. ## Testing: `IsMatch` `IsMatch` answers whether the pattern matches anywhere in the text. It returns `bool ! RegexError` — even a search can fail, since it takes working memory from the regex's allocator — so it needs its `?`: ```rux for text in ["ABC-1234", "abc-1234", "ABC-12345", "XY-0001"] { PrintLine("{:<10} {}", text, code.IsMatch(text)?); } ``` The `^` and `$` matter. Without them the pattern only has to match *somewhere*, and `ABC-12345` would pass, since `ABC-1234` is inside it. To check that a whole text has a form, anchor both ends. ## Finding: `Find` and `FindAt` `Find` returns where the leftmost match is, as a `Match?`. A `Match` holds two byte positions, `start` and `end`, and `Slice` cuts the matched text out of the text that was searched: ```rux match time.Find(log)? { found? => PrintLine("first {} at bytes {}..{}", found.Slice(log), found.start, found.end), none => PrintLine("no time") } ``` `FindAt` takes a byte to start from. Starting each search where the previous match ended walks through every match in turn, and [`?? break`](https://rux-lang.dev/docs/learn/coalesce-exit) ends the loop when there are no more: ```rux var at: uint = 0; while true { let found = time.FindAt(log, at)? ?? break; PrintLine("time {}", found.Slice(log)); at = found.end; } ``` The next lesson's `FindAll` does this walk for you, and handles one case this loop does not — see the common mistakes below. ## Searching for plain text: `Escape` Sometimes the thing to find is fixed text that happens to contain `.`, `+` or `(`. Written as a pattern, `v1.2` also matches `v102`, because `.` is any character. `Escape` turns text into the pattern that matches exactly that text — here `v1\.2` — and returns it as a `String`: ```rux let pattern = Escape(allocator, "v1.2")?; let exact = Regex::New(allocator, pattern.Bytes())?; ``` Use it whenever part of a pattern comes from a person or a file, so that their text cannot change what the pattern means. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Text/Regex){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // A regular expression is a small pattern that describes a whole family of texts. `\d{4}` is // "four digits"; `^[A-Z]{3}-\d{4}$` is "three capital letters, a hyphen and four digits, and // nothing else". One pattern can check what a person typed, or find what you are looking for in // a page of text, where the same job by hand would be a loop full of special cases. // // `Regex::New` compiles a pattern once, and the compiled `Regex` is then searched as often as // needed. Compiling can fail — the pattern may be malformed — so it returns `Regex ! RegexError`, // and the error says what went wrong and at which byte of the pattern. // // The package matches in linear time: a search never takes more than a fixed amount of work per // byte of text, whatever the pattern. The price is that it refuses the few features that would // need backtracking, such as backreferences. import Allocator::{ Allocator, SystemAllocator }; import Io::PrintLine; import Regex::{ Escape, Regex, RegexError, RegexErrorKind }; func Reason(kind: RegexErrorKind) -> char8[..] { return match kind { .UnclosedGroup => "a ( with no )", .UnclosedClass => "a [ with no ]", .NothingToRepeat => "nothing before the repetition", .Unsupported => "needs backtracking", else => "another mistake" }; } // Compiles `pattern` only to see whether it is one, and reports why not. func Check(allocator: Allocator, pattern: char8[..]) { match Regex::New(allocator, pattern) { .Success(_) => PrintLine("{:<10} compiles", pattern), .Failure(error) => PrintLine("{:<10} {} at byte {}", pattern, Reason(error.kind), error.offset) } } func Main() -> ! RegexError { var system = SystemAllocator(); let allocator: Allocator = system; // A backslash in a Rux string must itself be escaped, so the pattern `\d` is written "\\d". // Written as "\d", it never reaches the Regex package: the compiler stops at the string. // // error: escape sequence '\d' is not recognized // // `^` and `$` pin the match to the start and end of the text: without them, `IsMatch` would // also accept a code with something before or after it. let code = Regex::New(allocator, "^[A-Z]{3}-\\d{4}$")?; for text in ["ABC-1234", "abc-1234", "ABC-12345", "XY-0001"] { PrintLine("{:<10} {}", text, code.IsMatch(text)?); } // Even `IsMatch` can fail, since a search takes working memory from the allocator, so the `?` // is needed. `if code.IsMatch(text) { … }` is refused with: // // error: condition for 'if' must have type 'bool', but found 'bool8 ! RegexError' // `Find` answers with where the leftmost match is, as a `Match` of byte positions, or `none`. // `Slice` cuts the matched text out of the text that was searched. let log = "disk 91% full at 09:41; retry at 09:45, give up at 10:15"; let time = Regex::New(allocator, "\\d{2}:\\d{2}")?; match time.Find(log)? { found? => PrintLine("first {} at bytes {}..{}", found.Slice(log), found.start, found.end), none => PrintLine("no time") } // `FindAt` searches from a byte position onwards, so starting each search where the last // match ended walks through every match in turn. var at: uint = 0; while true { let found = time.FindAt(log, at)? ?? break; PrintLine("time {}", found.Slice(log)); at = found.end; } // In a pattern `.` means "any character", so the pattern "v1.2" also matches "v102". `Escape` // turns text into a pattern that matches exactly that text, here `v1\.2`. let release = "v102 was replaced by v1.2"; let loose = Regex::New(allocator, "v1.2")?; let pattern = Escape(allocator, "v1.2")?; let exact = Regex::New(allocator, pattern.Bytes())?; PrintLine("loose {}", (loose.Find(release)? ?? return).Slice(release)); PrintLine("exact {} from {}", (exact.Find(release)? ?? return).Slice(release), pattern); // A malformed pattern is refused when it is compiled, never halfway through a search. Check(allocator, "\\d+-\\d+"); Check(allocator, "(\\d+"); Check(allocator, "[a-z"); Check(allocator, "*.txt"); Check(allocator, "(a)\\1"); } ``` Besides `Io`, its `Rux.toml` lists `Allocator` and `Regex` under `[Dependencies]`. ## Run it ```sh cd Examples/Text/Regex rux run ``` ```text ABC-1234 true abc-1234 false ABC-12345 false XY-0001 false first 09:41 at bytes 17..22 time 09:41 time 09:45 time 10:15 loose v102 exact v1.2 from v1\.2 \d+-\d+ compiles (\d+ a ( with no ) at byte 0 [a-z a [ with no ] at byte 0 *.txt nothing before the repetition at byte 0 (a)\1 needs backtracking at byte 3 ``` ## Common mistakes ::mistake **Single backslashes.**:br`Regex::New(allocator, "\d{2}:\d{2}")` never reaches the Regex package. The compiler stops at the string: ```text error: escape sequence '\d' is not recognized ``` Double every backslash meant for the pattern: `"\\d{2}:\\d{2}"`. :: ::mistake **Using a search result as a `bool`.**:br`if code.IsMatch(text) { … }` fails with: ```text error: condition for 'if' must have type 'bool', but found 'bool8 ! RegexError' ``` A search can fail for want of memory. Add `?`, or handle the `RegexError`. :: ::mistake **Forgetting the anchors.**:br Without `^` and `$`, `[A-Z]{3}-\d{4}` matches inside `XABC-12345`, and `IsMatch` says `true`. When the whole text must have the form, anchor both ends. :: ::mistake **A pattern that can match nothing.**:br`\d*` matches the empty text, so `FindAt(log, 0)` on `"at 09:41"` finds an empty match at `0..0`. Its `end` is where it started, so the loop above would search from byte 0 for ever. `FindAll`, in the next lesson, steps past empty matches; a hand-written loop must do it itself, or use a pattern such as `\d+` that always consumes something. :: ::mistake **Copying a `Regex`.**:br A compiled pattern owns its program and is not copied. `let other = code;` fails with: ```text error: move-only value 'code' requires an explicit '<-' in initialization ``` Pass it by reference, `&Regex`, or move it with `<-`. :: ## Try it yourself 1. Change the order-code pattern to accept lower-case letters too, first with `[A-Za-z]`, then with `(?i)` at the start. 2. Search the log for percentages with `\d+%`. Where is the match, in bytes? 3. Use `Escape` on `"1+1=2"` and print the pattern it makes. Which characters gained a backslash? 4. Add `Check(allocator, "[z-a]")` and `Check(allocator, "a{3,2}")` to the program, with a reason for each new kind in `Reason`. ## Learn more - [Regex captures](https://rux-lang.dev/docs/learn/regex-capture) — groups, every match, splitting and replacing - [String view](https://rux-lang.dev/docs/learn/string-view) — `IndexOf` and `StartsWith`, enough when the text is fixed - [Coalesce exit](https://rux-lang.dev/docs/learn/coalesce-exit) — the `?? break` that ends the search loop - [Regex](https://rux-lang.dev/docs/api/regex) in the API reference — the full pattern syntax - [Escape sequences](https://rux-lang.dev/docs/lang/lexical/literals#escape-sequences) in the Rux Reference — why the backslashes are doubled # Regex captures ::note **You'll need**: [Regular expressions](https://rux-lang.dev/docs/learn/regex), [Iterator](https://rux-lang.dev/docs/learn/iterator) :: [Regular expressions](https://rux-lang.dev/docs/learn/regex) answered *where*: `Find` reported the bytes a time of day sat at in a log line. Usually you want more — from a date, the year on its own; every date in a text; or the same text with its dates written another way. This lesson covers the rest of the Regex package: ```rux import Regex::{ Match, Regex, RegexError }; ``` ## Groups Parentheses in a pattern make a **group**, and a group remembers which part of the text it matched. Groups are numbered by their opening `(`, counting from 1; group 0 is always the whole match. A group can also have a name, written `(?...)`: ```rux let date = Regex::New(allocator, "(?\\d{4})-(?\\d{2})-(?\\d{2})")?; ``` ```mermaid flowchart TB m["group 0: `2026-10-15`"] --> y["group 1, `year`:
`2026`"] m --> mo["group 2, `month`:
`10`"] m --> d["group 3, `day`:
`15`"] ``` `GroupCount()` says how many groups a pattern has, not counting group 0: here 3. Parentheses that only group, without capturing, are written `(?:...)`, and get no number. ## Capturing `Capture` searches as `Find` does, and answers with a `Captures?` — `none` when there is no match. `Group` asks for a group by number and `Named` by name, and each returns a `Match?`: ```rux match date.Capture(notes)? { groups? => { PrintLine("match {}", Part(groups.Group(0), notes)); PrintLine("year {}", Part(groups.Named("year"), notes)); PrintLine("month {}", Part(groups.Group(2), notes)); PrintLine("day {}", Part(groups.Named("day"), notes)); }, none => PrintLine("no date") } ``` A group's answer is optional because a group can take no part in a match. In `v(\d+)(?:\.(\d+))?` the minor version is optional, so for `v4` group 2 has nothing to report. The program's `Part` function turns that `none` into a `-`: ```rux func Part(span: Match?, text: char8[..]) -> char8[..] { return match span { found? => found.Slice(text), none => "-" }; } ``` Prefer names to numbers once a pattern has more than one or two groups. `Named("year")` still reads correctly after someone adds a group in front of it; `Group(1)` quietly starts answering with something else. ## Every match: `FindAll` `FindAll` returns an [iterator](https://rux-lang.dev/docs/learn/iterator) over every match, leftmost first and never overlapping, so a `for` loop walks them: ```rux for found in date.FindAll(notes)? { PrintLine("found {} at byte {}", found.Slice(notes), found.start); } ``` Making the iterator can fail for want of memory, so the `?` comes before the loop starts. Unlike the hand-written `FindAt` loop of the last lesson, `FindAll` steps past an empty match, so a pattern such as `\d*` cannot trap it. It walks matches, not groups; for the groups of each match, call `CaptureAt` from where the previous match ended. ## Between the matches: `Split` `Split` returns an iterator over the pieces of text *between* the matches. It is the [string view](https://rux-lang.dev/docs/learn/string-view)'s `Split` with a pattern for a separator, so one call copes with commas or semicolons and any spaces around them: ```rux let list = "apples, pears;plums , figs"; let separator = Regex::New(allocator, "\\s*[,;]\\s*")?; for part in separator.Split(list)? { PrintLine("part [{}]", part); } ``` There is always one more piece than there are matches. So a separator at the very start or end of the text gives an empty piece there: `,` splits `"a,b,"` into `a`, `b` and an empty piece. ## Replacing `Replace` makes a new `String` with every match replaced. In the replacement text, a `$` refers back to the match: | In the replacement | Stands for | | ------------------ | ----------------------------- | | `$0` | the whole match | | `$1`, `${1}` | what group 1 matched | | `$year`, `${year}` | what the group `year` matched | | `$$` | a single `$` | ```rux let dotted = date.Replace(allocator, notes, "${day}.${month}.${year}")?; PrintLine("{}", dotted); let marked = date.ReplaceFirst(allocator, notes, "[$0]")?; PrintLine("{}", marked); ``` `ReplaceFirst` stops after the first match. Both take an allocator for the new text, and the text searched is left as it was. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Text/RegexCapture){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // Finding where a pattern matches is often only the first step: what you want is a piece of the // match. In a date the year, the month and the day are each a part of their own. Wrapping a part // of a pattern in parentheses makes it a group, and `Capture` reports where each group matched as // well as where the whole match is. A group can have a name, `(?...)`, so the code that // reads it says what it wants instead of counting parentheses. // // Three more operations work through a whole text. `FindAll` walks every match in turn, `Split` // walks the parts between the matches, and `Replace` makes a new text with every match replaced, // where `${year}` or `$1` in the replacement stands for what a group matched. import Allocator::{ Allocator, SystemAllocator }; import Io::PrintLine; import Regex::{ Match, Regex, RegexError }; // The text a group matched, or "-" when the group took no part in the match. A group answers // with a `Match?`, so `groups.Named("year").Slice(notes)` is refused until the `none` is dealt // with: // // error: type 'Match?' has no field 'Slice' func Part(span: Match?, text: char8[..]) -> char8[..] { return match span { found? => found.Slice(text), none => "-" }; } func Main() -> ! RegexError { var system = SystemAllocator(); let allocator: Allocator = system; let notes = "Released 2026-10-15, patched 2026-11-02, retired 2027-01-31."; let date = Regex::New(allocator, "(?\\d{4})-(?\\d{2})-(?\\d{2})")?; PrintLine("groups {}", date.GroupCount()); // `Capture` finds the first match, as `Find` does, and answers with its `Captures`, or `none`. // Group 0 is the whole match, and the others count from 1 in the order their `(` appear. A // named group can be asked for either way. match date.Capture(notes)? { groups? => { PrintLine("match {}", Part(groups.Group(0), notes)); PrintLine("year {}", Part(groups.Named("year"), notes)); PrintLine("month {}", Part(groups.Group(2), notes)); PrintLine("day {}", Part(groups.Named("day"), notes)); }, none => PrintLine("no date") } // Each group answers with a `Match?`, because a group may take no part in a match: here the // minor version is optional, so in "v4" group 2 has nothing to report. let version = Regex::New(allocator, "v(\\d+)(?:\\.(\\d+))?")?; for text in ["v3.1", "v4"] { match version.Capture(text)? { groups? => PrintLine("{:<9} major {}, minor {}", text, Part(groups.Group(1), text), Part(groups.Group(2), text)), none => PrintLine("{:<9} no version", text) } } // `FindAll` is an iterator over every match, leftmost first, never overlapping. Making one can // fail for want of memory, so the `?` comes before the loop can start; without it: // // error: cannot iterate over 'MatchIterator ! RegexError' for found in date.FindAll(notes)? { PrintLine("found {} at byte {}", found.Slice(notes), found.start); } // `Split` is an iterator over what lies between the matches. Because the separator is a // pattern, one call copes with commas or semicolons and any spaces around them. let list = "apples, pears;plums , figs"; let separator = Regex::New(allocator, "\\s*[,;]\\s*")?; for part in separator.Split(list)? { PrintLine("part [{}]", part); } // `Replace` builds a new String with every match replaced. In the replacement, `${name}` is // what that group matched, `$1` is group 1 and `$0` the whole match. `ReplaceFirst` stops // after the first match. let dotted = date.Replace(allocator, notes, "${day}.${month}.${year}")?; PrintLine("{}", dotted); let marked = date.ReplaceFirst(allocator, notes, "[$0]")?; PrintLine("{}", marked); } ``` Besides `Io`, its `Rux.toml` lists `Allocator` and `Regex` under `[Dependencies]`. ## Run it ```sh cd Examples/Text/RegexCapture rux run ``` ```text groups 3 match 2026-10-15 year 2026 month 10 day 15 v3.1 major 3, minor 1 v4 major 4, minor - found 2026-10-15 at byte 9 found 2026-11-02 at byte 29 found 2027-01-31 at byte 49 part [apples] part [pears] part [plums] part [figs] Released 15.10.2026, patched 02.11.2026, retired 31.01.2027. Released [2026-10-15], patched 2026-11-02, retired 2027-01-31. ``` ## Common mistakes ::mistake **Treating a group as text.**:br`groups.Named("year").Slice(notes)` fails with: ```text error: type 'Match?' has no field 'Slice' ``` The group may not have taken part in the match. Deal with the `none` first, as `Part` does. :: ::mistake **Misspelling a group name.**:br`groups.Named("yaer")` is not an error. There is no group by that name, so it answers `none`, exactly as a group that did not match would — and the program prints `-` instead of the year. Check the name against the pattern when a group seems to match nothing. :: ::mistake **Iterating the outcome.**:br`for found in date.FindAll(notes)` fails with: ```text error: cannot iterate over 'MatchIterator ! RegexError' ``` `FindAll` and `Split` can fail before the walk starts. Put `?` after the call. :: ::mistake **A group number followed by letters.**:br In `"$3rd of $2"`, `$3rd` refers to a group named `3rd`, which does not exist, so it is replaced by nothing: the result is `Released of 10.`. Put the number in braces — `"${3}rd of $2"` gives `Released 15rd of 10.` :: ## Try it yourself 1. Add a fourth group, `(?[A-Z][a-z]+)?`, before the date, and run the program. Which of the `Group(2)` and `Named("month")` lines still prints the month? 2. Reorder the dates as `month/day/year` with `Replace`, using numbered groups this time. 3. Split `"one two\tthree"` on `\s+` and print each word in brackets. What does splitting `" one two "` give at the ends? 4. Count the dates in `notes` with `FindAll` and a counter, then print the count. ## Learn more - [Regular expressions](https://rux-lang.dev/docs/learn/regex) — compiling, `IsMatch`, `Find` and `Escape` - [Iterator](https://rux-lang.dev/docs/learn/iterator) — the `Next` behind every `for` loop here - [String view](https://rux-lang.dev/docs/learn/string-view) — `Split` on fixed text - [Grep](https://rux-lang.dev/docs/learn/grep) — a checkpoint project that searches files with a pattern - [Regex](https://rux-lang.dev/docs/api/regex) in the API reference - [Iteration](https://rux-lang.dev/docs/lang/interfaces/iteration) in the Rux Reference # Part 15: Memory Until now every value had a size the compiler knew and a home it chose. This part opens the box underneath: pointers that hold addresses, memory you ask for while the program runs, and the layout of the bytes themselves. It starts with the rawest tools, where every rule is yours to keep, and ends with allocators and owning handles that keep most of those rules for you — so by the end you know both what they do and why they exist. ## What you will learn - Taking an address with `@`, reaching through it with `*`, and the difference between `*T` and `*var T`. - Returning extra answers through an out-parameter, and why a fallible is usually better. - Asking for memory with `Alloc`, clearing it with `Zero` and returning it with `Free`. - Pointer arithmetic, and turning a pointer and a count into an ordinary slice with `p[..n]`. - Optional pointers `(*T)?` versus pointers to optionals `*T?`, and why `null` is not `none`. - How big a type is and how it is aligned, and the padding a struct carries. - Unions, which lay several members over the same bytes. - The `Allocator` interface, and four ways to stand behind it: `SystemAllocator`, `Arena`, `FixedBuffer` and `Pool` — plus `Box`, which owns one allocated value. - Wiping a secret with `Zeroize`, a clear the compiler never removes. - Sharing one value between several owners with `Rc`, whose handles count themselves so that the last one frees it. ## The allocator family ```mermaid flowchart LR code["your code,
written against `Allocator`"] --> iface{{"`Allocator`
`Allocate` · `Deallocate` · `Reallocate`"}} box["`Box<T>`
owns one value"] --> iface rc["`Rc<T>`
shares one value, counted"] --> iface iface --- sys["`SystemAllocator`
pages from the system"] iface --- arena["`Arena`
a moving marker; `Reset` frees all"] iface --- fixed["`FixedBuffer`
storage you own; a hard limit"] iface --- pool["`Pool`
fixed-size blocks, reused"] sys -. "backs" .-> arena sys -. "backs" .-> pool ``` Code that takes an `Allocator` works with any of the four. `SystemAllocator` asks the operating system and is usually the one an arena or a pool draws its large blocks from; `FixedBuffer` draws on nothing but the storage you give it. `Box` and `Rc` sit on the other side: they take an allocator and use it, so a boxed or shared value can live in any of the four. ## Lessons | | Lesson | What you will learn | | ----- | ------------------------------------------------------------------------ | ------------------------------------------------------------------------------ | | 15.1 | [Pointer](https://rux-lang.dev/docs/learn/pointer) | the difference between `*T` and `*var T`, and taking an address with `@` | | 15.2 | [Out parameter](https://rux-lang.dev/docs/learn/out-parameter) | return extra information through a pointer parameter | | 15.3 | [Raw memory](https://rux-lang.dev/docs/learn/raw-memory) | allocate, use and free memory by hand (`Alloc`, `Zero`, `Free`) | | 15.4 | [Pointer arithmetic](https://rux-lang.dev/docs/learn/pointer-arithmetic) | step a pointer through memory one element at a time | | 15.5 | [Pointer slice](https://rux-lang.dev/docs/learn/pointer-slice) | turn a pointer and a length into a slice | | 15.6 | [Optional pointer](https://rux-lang.dev/docs/learn/optional-pointer) | `*T?` and `(*T)?`: a pointer to an optional, or an optional pointer | | 15.7 | [Layout](https://rux-lang.dev/docs/learn/layout) | how big a type is and how it is aligned: `sizeof` and `alignof` | | 15.8 | [Union](https://rux-lang.dev/docs/learn/union) | overlay one piece of storage with several types, and why that needs care | | 15.9 | [Allocator](https://rux-lang.dev/docs/learn/allocator) | allocate through the `Allocator` interface instead of straight from the system | | 15.10 | [Box](https://rux-lang.dev/docs/learn/box) | own one value allocated on the heap | | 15.11 | [Arena](https://rux-lang.dev/docs/learn/arena) | allocate many values and free them all at once | | 15.12 | [Fixed buffer](https://rux-lang.dev/docs/learn/fixed-buffer) | allocate from a buffer you provide | | 15.13 | [Pool](https://rux-lang.dev/docs/learn/pool) | reuse fixed-size blocks instead of allocating new ones | | 15.14 | [Zeroize](https://rux-lang.dev/docs/learn/zeroize) | clear sensitive memory explicitly | | 15.15 | [Rc](https://rux-lang.dev/docs/learn/rc) | share one value between several owners with reference counting | ## Before you start This part leans on much of what came before. Pointers build on [Reference](https://rux-lang.dev/docs/learn/reference) from Part 6; allocators report failure with the fallibles of [Part 9: Errors](https://rux-lang.dev/docs/learn/errors); cleaning up relies on [Destructor](https://rux-lang.dev/docs/learn/destructor), [Move](https://rux-lang.dev/docs/learn/move) and [Defer](https://rux-lang.dev/docs/learn/defer) from [Part 11: Ownership](https://rux-lang.dev/docs/learn/ownership); and `Allocator` is used as in [Interface value](https://rux-lang.dev/docs/learn/interface-value) from [Part 12: Interfaces](https://rux-lang.dev/docs/learn/interfaces). Each lesson's package is in the Examples repository's `Memory/` folder: ```sh cd Examples/Memory/Pointer rux run ``` ## After this part [Part 16: Numbers](https://rux-lang.dev/docs/learn/numbers) looks at numbers in depth — wide integers, limits, bit operations, checked and wrapping arithmetic. After Part 16 you are ready for the checkpoint projects [Circle](https://rux-lang.dev/docs/learn/circle) and [Quadratic](https://rux-lang.dev/docs/learn/quadratic). Then [Part 17: Collections](https://rux-lang.dev/docs/learn/collections) puts this part to work: its containers take an `Allocator` and grow by asking it for memory. For the full rules, see [Pointers](https://rux-lang.dev/docs/lang/pointers/overview), [Pointer arithmetic](https://rux-lang.dev/docs/lang/pointers/arithmetic), [Slices and pointers](https://rux-lang.dev/docs/lang/slices/overview#members) and [Unions](https://rux-lang.dev/docs/lang/unions/overview) in the Rux Reference, and the [Memory](https://rux-lang.dev/docs/api/memory) package in the API reference. # Pointer ::note **You'll need**: [Mutable](https://rux-lang.dev/docs/learn/mutable), [Reference](https://rux-lang.dev/docs/learn/reference), [Mutable reference](https://rux-lang.dev/docs/learn/mutable-reference) :: Every value lives somewhere in memory, and that place has an *address*: a number that says where it is. A **pointer** is a value that holds such an address. With one, a part of the program can reach a value that lives somewhere else, read it and — when it is allowed to — change it. You have met a close relative already: the reference, `&T` and `&var T`, from [Reference](https://rux-lang.dev/docs/learn/reference). A pointer does the same job with more freedom and fewer checks. The whole of this part is built on that freedom, so this first lesson takes it slowly. ## Taking an address and reaching through it Two operators do all the work. `@score` takes the address of `score`, and `*pointer` reaches the value at an address: ```rux var score: int = 10; // Two pointers to one variable. Neither is a copy of `score`; both lead back to it. let reader: *int = @score; let writer: *var int = @score; *writer = 25; ``` Neither pointer holds a copy of 10. Both hold the address of `score`, so after `*writer = 25` the variable itself says 25, and reading `*reader` says 25 too. ```mermaid flowchart LR reader["`reader: *int`"] -- "reads" --> score[("`score: int`
`25`")] writer["`writer: *var int`"] -- "reads and writes" --> score ``` | Operator | Read it as | Gives | | ---------- | ------------------------ | -------------------------------------- | | `@value` | "the address of `value`" | a pointer | | `*pointer` | "the value at `pointer`" | the value itself, to read or to assign | ## `*T` reads, `*var T` writes Pointers split the same way bindings do. The `var` after the `*` describes the value pointed at — the *pointee* — not the pointer: | Type | Through it you may | Like a binding made with | | ---------- | ------------------- | ------------------------ | | `*int` | read `*p` | `let` | | `*var int` | read and write `*p` | `var` | The split follows the original binding, too. The address of a `let` binding is always a read-only `*int`, so a pointer can never be used to change something that was declared unchangeable: ```rux let limit: int = 100; let limitPointer: *int = @limit; ``` Asking for a `*var int` there is an error; the exact message is under Common mistakes below. ## Fields through a pointer To reach a field through a pointer, use a plain `.`. There is no need to write `*` first: ```rux var point = Point { x: 1, y: 2 }; let cursor: *var Point = @point; cursor.x = 7; ``` The write lands in `point` itself, which then prints as `(7, 2)`. ## `null`, the pointer to nowhere Unlike a reference, a pointer can be stored, compared and set to `null`, which means "no address at all": ```rux var target: *int = null; PrintLine("target is null {}", target == null); target = @score; if target != null { PrintLine("target now reads {}", *target); } ``` Comparing with `==` and `!=` is always safe. Reaching through `null` with `*` is not, and the compiler will not stop you: the program simply crashes when it gets there. Check before you reach. Two pointers are equal when they hold the same address. That is why the last line prints `true` — `target` and `reader` both lead to `score`. | | Reference `&T` | Pointer `*T` | | ------------------------------------ | ------------------------ | ------------------ | | Checked by the compiler | yes — it is always valid | no | | Can be `null` | no | yes | | Can be stored in a field or returned | no | yes | | Reached with | the name alone | `*p`, or `p.field` | ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Memory/Pointer){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // A pointer is an address: a plain value that says where another value lives. `@score` takes // the address of `score`, and `*pointer` reaches the value at that address, to read it or to // write it. // // Pointers split the same way bindings do. A `*int` may only read what it points at; a // `*var int` may also write. And the address of a `let` binding is always a read-only `*int`, // so a pointer can never be used to change something declared unchangeable. // // A reference (`&T`, from the Types part) also reaches another value, but the compiler checks // that it stays valid. A pointer is not checked: it can be stored, compared, and set to `null`, // which means "no address at all". The rest of this part is built on that freedom, and on the // care it asks for. import Io::PrintLine; struct Point { x: int; y: int; } func Main() -> int { var score: int = 10; // Two pointers to one variable. Neither is a copy of `score`; both lead back to it. let reader: *int = @score; let writer: *var int = @score; *writer = 25; PrintLine("score is now {}", score); PrintLine("read via pointer {}", *reader); // The address of a `let` binding is read-only. Asking for `*var int` here is an error: // "'@limit' yields a read-only '*T'; declare 'limit' with 'var' for a '*var T'". let limit: int = 100; let limitPointer: *int = @limit; PrintLine("limit is {}", *limitPointer); // A field is reached through a pointer with a plain `.`, without writing `*` first. var point = Point { x: 1, y: 2 }; let cursor: *var Point = @point; cursor.x = 7; PrintLine("point is ({}, {})", point.x, point.y); // `null` is the pointer that points nowhere. Comparing with `==` is safe; reaching through // it with `*` is not, and the compiler will not stop you. Check before you reach. var target: *int = null; PrintLine("target is null {}", target == null); target = @score; if target != null { PrintLine("target now reads {}", *target); } // Two pointers are equal when they hold the same address. PrintLine("same address {}", target == reader); return 0; } ``` ## Run it ```sh cd Examples/Memory/Pointer rux run ``` ```text score is now 25 read via pointer 25 limit is 100 point is (7, 2) target is null true target now reads 25 same address true ``` ## Common mistakes ::mistake **A writable pointer to a `let` binding.**:br`let limit: int = 100;` followed by `let w: *var int = @limit;` fails with: ```text error: cannot assign '*int' to '*var int': '@limit' yields a read-only '*T'; declare 'limit' with 'var' for a '*var T' ``` Do what the message says, or settle for a `*int` if you only need to read. :: ::mistake **Writing through a read-only pointer.**:br`*reader = 5;` with `reader: *int` fails with: ```text error: cannot modify data through read-only pointer '*int' ``` The pointee type decides what you may do, whatever the variable it points at was declared with. :: ::mistake **Forgetting the `@`.**:br`let reader: *int = score;` hands over the value 10, not the place it lives, and fails with: ```text error: cannot assign 'int' to '*int' ``` A pointer is made from an address: `@score`. :: ::mistake **Reaching through `null`.**:br`*target` on a `null` pointer compiles without a word and crashes the program when that line runs. Compare with `null` first wherever a pointer might not have been set. :: ## Try it yourself 1. Add a second variable, `var bonus: int = 5;`, point `target` at it, and check that `target == reader` now prints `false`. 2. Write `func Swap(a: *var int, b: *var int)` that exchanges two values, and call it as `Swap(@first, @second)`. 3. A pointer is a value, so it has an address too. Make `var p: *var int = @score;` and `let pp: **var int = @p;`, then write `**pp = 42` and print `score`. ## Learn more - [Pointers](https://rux-lang.dev/docs/lang/pointers/overview), [Pointer types](https://rux-lang.dev/docs/lang/pointers/overview#conversions) and [The `null` pointer](https://rux-lang.dev/docs/lang/pointers/overview#null) in the Rux Reference - [Reference](https://rux-lang.dev/docs/learn/reference) and [Mutable reference](https://rux-lang.dev/docs/learn/mutable-reference) — the checked relatives of `*T` and `*var T` - [Out parameter](https://rux-lang.dev/docs/learn/out-parameter) — the next lesson, where a function writes through a pointer it was given # Out parameter ::note **You'll need**: [Pointer](https://rux-lang.dev/docs/learn/pointer), [Fallible](https://rux-lang.dev/docs/learn/fallible), [Catch fallback](https://rux-lang.dev/docs/learn/catch-fallback) :: A function returns one value. Sometimes you want two things back: the answer, and whether the answer is any good. One long-standing way to get both is the **out-parameter** — the caller hands over a pointer to its own variable, the function writes the answer through it, and the return value is left free to say something else. You will meet out-parameters in older code, in the standard library and in C libraries, so it pays to read them fluently. This lesson also shows their weak spots, and why a fallible `T ! E` is usually the better choice for code you write yourself. ## The shape of an out-parameter The answer travels through `result`, a `*var int`. The `bool` that comes back says whether to trust it: ```rux func PercentOf(part: int, whole: int, result: *var int) -> bool { if whole == 0 { return false; } *result = part * 100 / whole; return true; } ``` The caller prepares a variable first and passes its address with `@`: ```rux var share: int = 0; if PercentOf(3, 4, @share) { PrintLine("3 of 4 is {}%", share); } ``` ```mermaid flowchart LR main["`Main`
`var share = 0`"] -- "`@share`" --> f["`PercentOf(3, 4, result)`"] f -- "`*result = 75`" --> share[("`share`")] f -- "returns `true`" --> check{"`if`"} check --> print["print `share`"] ``` The variable must be a `var`, because the function writes into it through a `*var int`. ## The flag nobody has to read Here is the weak spot. Nothing forces the caller to look at the `bool`: ```rux PercentOf(1, 0, @share); PrintLine("1 of 0, flag ignored: {}%", share); ``` The whole is zero, so `PercentOf` returns `false` and writes nothing. The flag is dropped, and `share` still holds 75 from the call before. The program prints a confident `75%` for a question that has no answer, and the compiler has no reason to object. ## Reading someone else's flag The standard library uses out-parameters too. `ConvertChecked` writes the converted value through its second argument and returns a `bool`: ```rux var narrowed: int8 = 0; let lost = ConvertChecked(300, @narrowed); ``` | Function | `true` means | | ---------------- | -------------------------------------------- | | `PercentOf` | the answer is good | | `ConvertChecked` | something was lost — the answer is not exact | The two read in opposite directions. With a bare `bool`, only the documentation tells you which way round it is. Here 300 does not fit in an `int8`, so `lost` is `true` and `narrowed` holds the wrapped value 44. ## The fallible alternative The same question as a fallible puts the answer and the failure on separate channels: ```rux func Percent(part: int, whole: int) -> int ! ZeroWhole { if whole == 0 { fail ZeroWhole {}; } return part * 100 / whole; } ``` ```rux let good = Percent(3, 4) catch { else => -1 }; let bad = Percent(1, 0) catch { else => -1 }; ``` | | Out-parameter | Fallible `T ! E` | | --------------------------------- | ------------------------------------- | ------------------------------------ | | Where the answer goes | a variable the caller prepared first | the return value | | How a failure is reported | a `bool`, read whichever way it reads | a typed error on the failure channel | | A caller that ignores the failure | compiles, and keeps a stale value | is rejected by the compiler | | An answer on failure | whatever the variable held before | none — there is nothing to misuse | For new code, prefer the fallible. Reach for an out-parameter when an existing API asks for one. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Memory/OutParameter){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // An out-parameter is a pointer the caller hands over so a function can write its answer into // the caller's own variable. The caller passes `@share`; the function writes `*result = ...`. // The return value is then free to say something else, usually whether the answer is good. // // Older code and some of the standard library work this way, so it is worth reading fluently. // But it has two weak spots. The caller must have a variable ready before the call, and nothing // forces anyone to look at the flag: ignore it, and the variable quietly keeps a stale value. // // A fallible `T ! E` closes both gaps. The answer only exists on success, and a result that is // left unhandled is a compile error. For new code, prefer it; reach for an out-parameter when // an existing API asks for one. import Core::ConvertChecked; import Io::PrintLine; // Out-parameter style: the answer goes through `result`, and the `bool` says whether to trust it. func PercentOf(part: int, whole: int, result: *var int) -> bool { if whole == 0 { return false; } *result = part * 100 / whole; return true; } struct ZeroWhole {} // The same question as a fallible. The answer and the failure travel on separate channels. func Percent(part: int, whole: int) -> int ! ZeroWhole { if whole == 0 { fail ZeroWhole {}; } return part * 100 / whole; } func Main() -> int { var share: int = 0; if PercentOf(3, 4, @share) { PrintLine("3 of 4 is {}%", share); } // The mistake the compiler cannot see: the flag is dropped, nothing was written, and `share` // still says 75 from the call before. PercentOf(1, 0, @share); PrintLine("1 of 0, flag ignored: {}%", share); // The standard library uses out-parameters too. `ConvertChecked` writes the converted value // and returns `true` when something was lost, which is the opposite of `PercentOf` above. // With a bare `bool`, only the documentation tells you which way round it reads. var narrowed: int8 = 0; let lost = ConvertChecked(300, @narrowed); PrintLine("300 into int8: lost {}, wrote {}", lost, narrowed); // The fallible needs no variable prepared in advance, and it cannot be ignored: a bare // `Percent(1, 0);` is rejected. The failure has to be dealt with, here by `catch`. let good = Percent(3, 4) catch { else => -1 }; let bad = Percent(1, 0) catch { else => -1 }; PrintLine("fallible: {}% and {}%", good, bad); return 0; } ``` Besides `Io`, its `Rux.toml` lists `Core` under `[Dependencies]`. ## Run it ```sh cd Examples/Memory/OutParameter rux run ``` ```text 3 of 4 is 75% 1 of 0, flag ignored: 75% 300 into int8: lost true, wrote 44 fallible: 75% and -1% ``` ## Common mistakes ::mistake **Passing the value instead of its address.**:br`PercentOf(3, 4, share)` hands over 0, not the variable, and fails with: ```text error: argument 3 to 'PercentOf' has type 'int', but parameter 'result' requires '*var int' ``` Write `@share`. :: ::mistake **An out-parameter declared with `let`.**:br With `let share: int = 0;`, the address `@share` is a read-only `*int`, so the call fails with: ```text error: argument 3 to 'PercentOf' has type '*int', but parameter 'result' requires '*var int' ``` The function has to write into it: declare it with `var`. :: ::mistake **Ignoring the flag.**:br`PercentOf(1, 0, @share);` compiles, and `share` silently keeps the 75 from before. Always test the `bool` — or use a function that reports failure as a fallible. :: ::mistake **Ignoring a fallible instead.**:br The fallible version refuses to be ignored: a bare `Percent(1, 0);` fails with: ```text error: fallible result of type 'int ! ZeroWhole' is discarded ``` The help line suggests `?`, `catch` or a `match`. :: ## Try it yourself 1. Write `func Divide(a: int, b: int, quotient: *var int, remainder: *var int) -> bool` that hands back two answers at once, and call it with `@q` and `@r`. 2. Change `PercentOf` to write `0` into `*result` before it returns `false`. Does that cure the stale `75%`? What does the caller still not know? 3. Convert 100 into an `int8` with `ConvertChecked` and check that `lost` is `false`. ## Learn more - [Fallible](https://rux-lang.dev/docs/learn/fallible) and [Catch fallback](https://rux-lang.dev/docs/learn/catch-fallback) — the alternative this lesson recommends - [Checked convert](https://rux-lang.dev/docs/learn/checked-convert) — `ConvertChecked` and its relatives in full - [Pointer types](https://rux-lang.dev/docs/lang/pointers/overview#conversions) in the Rux Reference # Raw memory ::note **You'll need**: [Pointer](https://rux-lang.dev/docs/learn/pointer), [Defer](https://rux-lang.dev/docs/learn/defer), [For](https://rux-lang.dev/docs/learn/for) :: Every value so far had its size fixed when the program was compiled: a `uint`, an array of four `int64`s, a struct. But often you only learn how much memory you need while the program runs — how many lines are in a file, how many players joined. That memory has to be **asked for**, and this lesson shows the rawest way to do it. Nothing here is checked for you. That is the point: once you have seen every rule you must keep by hand, the tools in the rest of this part will make sense. ## Three functions The `Memory` package gives you three functions, and between them they cover a block's whole life: | Function | Does | | -------------- | ----------------------------------------------------------------------- | | `Alloc(bytes)` | finds a fresh block and returns its address, or `null` if there is none | | `Zero(p, n)` | fills `n` bytes at `p` with zeros | | `Free(p)` | gives the block back | ## Ask in bytes `Alloc` counts in bytes, not in elements, so the request is the element count times the size of one element: ```rux let count: uint = 8; let size = count * sizeof(uint); ``` `sizeof(uint)` is 8 on a 64-bit machine, so eight elements need 64 bytes. [Layout](https://rux-lang.dev/docs/learn/layout) later in this part looks at sizes properly. ## Say what lives there The block arrives as `*var opaque`: "writable memory, contents unknown". An `opaque` pointee has no type, so you cannot read or write through it yet. A cast says what will live there: ```rux var values = Alloc(size) as *var uint; ``` From then on the pointer indexes like an array: `values[i]` is the `i`-th `uint` after the address. ## Check, then register the release Allocation can fail, and the only sign is a `null`. Check before the first use, and register the `Free` straight after the check: ```rux if values == null { PrintLine("out of memory"); return 1; } defer Free(values); ``` The `defer` makes sure that every later path out of `Main` — the normal `return 0`, or any early `return` you add later — frees the block exactly once. ```mermaid flowchart LR alloc["`Alloc(size)`"] --> q{"`null`?"} q -- "yes" --> oom["report it,
`return 1`"] q -- "no" --> d["`defer Free(values)`"] d --> z["`Zero(values, size)`"] z --> use["`values[i] = i * i`"] use --> free["`Free` runs as
`Main` returns"] ``` ## Fresh memory is not empty A new block holds whatever bytes were last left there. `Zero` makes its contents definite before anything reads them: ```rux Zero(values, size); ``` After that, the program fills the block with squares and adds them up — ordinary indexing, on memory that did not exist when the program was compiled. ## After `Free` When the deferred `Free` has run, `values` still holds the old address, but the memory is no longer yours. Reading it, writing it or freeing it a second time are all bugs, and nothing reports them: the program may seem to work, crash later somewhere unrelated, or quietly corrupt other data. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Memory/RawMemory){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // Every value so far had its size fixed when the program was compiled. When the amount of memory // is only known while the program runs, it has to be asked for, and this is the rawest way: // // Alloc(bytes) hands back the address of a fresh block, or `null` if there is none to give // Zero(p, n) fills the block with zero bytes // Free(p) gives the block back // // The block arrives as `*var opaque`: "writable memory, contents unknown". A cast says what will // live there, and from then on the pointer indexes like an array: `values[i]` is the i-th element // after the address. // // Nothing here is checked for you. A `null` must be caught before use, the block must be freed // exactly once, and it must not be touched afterwards. The rest of this part is about tools that // make those rules harder to break. import Io::{ Print, PrintLine }; import Memory::{ Alloc, Free, Zero }; func Main() -> int { // A count decided at run time. `sizeof(uint)` is the size of one element in bytes. let count: uint = 8; let size = count * sizeof(uint); PrintLine("asking for {} elements, {} bytes", count, size); var values = Alloc(size) as *var uint; // Allocation can fail, and the only sign is `null`. Check before the first use. if values == null { PrintLine("out of memory"); return 1; } // Registered right after the check, so every later path out of `Main` frees the block once. defer Free(values); // Fresh memory holds whatever was there before. `Zero` makes its contents definite. Zero(values, size); Print("after Zero:"); for i in 0..count { Print(" {}", values[i]); } PrintLine(); for i in 0..count { values[i] = i * i; } Print("squares: "); var total: uint = 0; for i in 0..count { Print(" {}", values[i]); total += values[i]; } PrintLine(); PrintLine("total: {}", total); // After the deferred `Free` runs, `values` still holds the old address, but the memory is no // longer yours. Reading it, or freeing it again, is a bug that nothing reports. return 0; } ``` Besides `Io`, its `Rux.toml` lists `Memory` under `[Dependencies]`. ## Run it ```sh cd Examples/Memory/RawMemory rux run ``` ```text asking for 8 elements, 64 bytes after Zero: 0 0 0 0 0 0 0 0 squares: 0 1 4 9 16 25 36 49 total: 140 ``` ## Common mistakes ::mistake **Using the block before the cast.**:br Without the cast, `values` is a `*var opaque`, and `values[0] = 1` fails with: ```text error: cannot assign 'int' to 'opaque' ``` Cast once, straight after `Alloc`, to the type the block will hold. :: ::mistake **Casting to a read-only pointer.**:br`Alloc(size) as *uint` gives a pointer you cannot write through: `values[0] = 1` then fails with: ```text error: cannot modify data through read-only pointer '*uint' ``` A block you mean to fill needs `*var`. :: ::mistake **Asking for elements instead of bytes.**:br`Alloc(count)` asks for 8 bytes, not for 8 `uint`s. It compiles and may even appear to work, while every write past the first element lands in memory that belongs to something else. Always multiply by `sizeof`. :: ::mistake **Skipping the `null` check, or freeing twice.**:br None of these are compile errors: forgetting to check for `null`, forgetting to `Free`, freeing the same block twice, or using it after `Free`. Keep the pattern from this lesson — check, then `defer Free` — and the next lessons give you tools that make these mistakes harder to write. :: ## Try it yourself 1. Change `count` to 20 and predict the byte count on the first line before you run. 2. Store `int32` values instead of `uint`s. What must change besides the cast? 3. Add an early `return 2;` inside the loop that adds up `total`, taken once `total` passes 100. The `defer` still frees the block — convince yourself why. ## Learn more - [`Alloc`](https://rux-lang.dev/docs/api/memory/allocation#alloc), [`Zero`](https://rux-lang.dev/docs/api/memory/blocks#zero) and [`Free`](https://rux-lang.dev/docs/api/memory/allocation#free) in the API reference - [Defer](https://rux-lang.dev/docs/learn/defer) — how deferred statements run on every path out - [Pointer slice](https://rux-lang.dev/docs/learn/pointer-slice) — turning this block into an ordinary slice # Pointer arithmetic ::note **You'll need**: [Pointer](https://rux-lang.dev/docs/learn/pointer), [Raw memory](https://rux-lang.dev/docs/learn/raw-memory), [Array](https://rux-lang.dev/docs/learn/array), [While](https://rux-lang.dev/docs/learn/while) :: In [Raw memory](https://rux-lang.dev/docs/learn/raw-memory), a pointer from `Alloc` was indexed like an array: `values[i]`. That works because a pointer can do arithmetic. Adding a number to it gives a new pointer further along in memory — and the step is measured in whole **elements**, not in bytes. ## A step is one element The program takes the address of the first element of three arrays and measures how far `+ 1` moves each pointer. Converting an address to `uint` shows it as a plain number of bytes, so two addresses can be subtracted: ```rux let b = @bytes[0]; let c = @counts[0]; let x = @pixels[0]; PrintLine("+1 on *uint8 moves {} byte", ((b + 1) as uint) - (b as uint)); PrintLine("+1 on *int64 moves {} bytes", ((c + 1) as uint) - (c as uint)); PrintLine("+1 on *Pixel moves {} bytes", ((x + 1) as uint) - (x as uint)); ``` | Pointer | One element is | `+ 1` moves | | -------- | ----------------------- | ----------- | | `*uint8` | one byte | 1 byte | | `*int64` | eight bytes | 8 bytes | | `*Pixel` | three `int32`s together | 12 bytes | The compiler multiplies by the element size for you. You always count in elements, whatever their size. ## Offset and index are one thing Indexing a pointer is just arithmetic followed by a dereference: `p[i]` means exactly `*(p + i)`. ```rux PrintLine("*(c + 2) is {}, c[2] is {}", *(c + 2), c[2]); PrintLine("(x + 1).blue is {}", (x + 1).blue); ``` A field is reached through the moved pointer with a plain `.`, as in [Pointer](https://rux-lang.dev/docs/learn/pointer). ## Walking to an end pointer A pointer can also walk. The loop below keeps a second pointer, `end`, one past the last element: ```rux var cursor = c; let end = c + 4; Print("doubled:"); while cursor < end { *cursor = *cursor * 2; Print(" {}", *cursor); cursor += 1; } ``` ```mermaid flowchart LR c0["`c`
`10`"] --- c1["`c + 1`
`20`"] --- c2["`c + 2`
`30`"] --- c3["`c + 3`
`40`"] --- e["`end = c + 4`
never read"] ``` Pointers compare by address, so `cursor < end` means "not there yet". `end` itself is never read through: it marks the place just past the array. Because `cursor` points into `counts`, the doubled values are written into the array itself, which the last line confirms. ## Nothing is checked The arithmetic is never checked. A pointer moved past the end of its storage is still a pointer, and reaching through it reads or writes memory that belongs to something else — another variable, or nothing at all. Keep an end in view, as the loop does, and never step past it. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Memory/PointerArithmetic){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // Adding a number to a pointer moves it by whole elements, not by bytes. If `p` points at an // `int64`, then `p + 1` points at the next `int64`, eight bytes further on. The compiler // multiplies by the element size for you, so the same `+ 1` steps one byte through `uint8`s // and twelve bytes through a twelve-byte struct. // // That is also what indexing a pointer means: `p[i]` is exactly `*(p + i)`. // // The arithmetic itself is never checked. A pointer moved past the end of its storage is still // a pointer, and reaching through it reads or writes memory that belongs to something else. // Keep an end in view: here, a second pointer one past the last element. import Io::{ Print, PrintLine }; struct Pixel { red: int32; green: int32; blue: int32; } func Main() -> int { var bytes: uint8[4] = [1, 2, 3, 4]; var counts: int64[4] = [10, 20, 30, 40]; var pixels: Pixel[2] = [Pixel { red: 255, green: 0, blue: 0 }, Pixel { red: 0, green: 0, blue: 255 }]; // Converting an address to `uint` shows it as a number of bytes, so the step `+ 1` takes // can be measured. It is the element size each time. let b = @bytes[0]; let c = @counts[0]; let x = @pixels[0]; PrintLine("+1 on *uint8 moves {} byte", ((b + 1) as uint) - (b as uint)); PrintLine("+1 on *int64 moves {} bytes", ((c + 1) as uint) - (c as uint)); PrintLine("+1 on *Pixel moves {} bytes", ((x + 1) as uint) - (x as uint)); // Offset and index are two spellings of one thing. PrintLine("*(c + 2) is {}, c[2] is {}", *(c + 2), c[2]); PrintLine("(x + 1).blue is {}", (x + 1).blue); // Walking with a pointer: `end` is one past the last element and is never read through. // Pointers compare by address, so `cursor < end` means "not there yet". var cursor = c; let end = c + 4; Print("doubled:"); while cursor < end { *cursor = *cursor * 2; Print(" {}", *cursor); cursor += 1; } PrintLine(); // The writes went through to the array itself. PrintLine("counts[3] is now {}", counts[3]); return 0; } ``` ## Run it ```sh cd Examples/Memory/PointerArithmetic rux run ``` ```text +1 on *uint8 moves 1 byte +1 on *int64 moves 8 bytes +1 on *Pixel moves 12 bytes *(c + 2) is 30, c[2] is 30 (x + 1).blue is 255 doubled: 20 40 60 80 counts[3] is now 80 ``` ## Common mistakes ::mistake **Adding bytes instead of elements.**:br To skip one `int64` you add 1, not 8. `c + 8` compiles and moves 64 bytes — far past the end of a four-element array. :: ::mistake **Forgetting the parentheses.**:br`*c + 2` reads the first element and adds 2 to it, giving 12. To reach two elements on, write `*(c + 2)`, or simply `c[2]`. :: ::mistake **Reading the end.**:br`while cursor <= end` runs once too often and reads one element past the array. Nothing reports it. `end` marks the stopping place; compare with `<`. :: ::mistake **Subtracting two pointers.**:br`end - c` is not allowed: it fails with: ```text error: operator '-' cannot combine left operand '*var int64' with right operand '*var int64' ``` To count the elements between them, convert both to `uint`, subtract, and divide by `sizeof(int64)`. :: ## Try it yourself 1. Print the counts in reverse: start a cursor at `end`, and in a `while cursor > c` loop step it back with `cursor -= 1` before each read. 2. Count the elements between `c` and `end` with `((end as uint) - (c as uint)) / sizeof(int64)`. 3. Walk `pixels` with a cursor and print each pixel's `red` and `blue`. ## Learn more - [Pointer arithmetic](https://rux-lang.dev/docs/lang/pointers/arithmetic) in the Rux Reference - [Raw memory](https://rux-lang.dev/docs/learn/raw-memory) — where indexing a pointer first appeared - [Pointer slice](https://rux-lang.dev/docs/learn/pointer-slice) — keeping the length beside the pointer, so the end is checked for you # Pointer slice ::note **You'll need**: [Raw memory](https://rux-lang.dev/docs/learn/raw-memory), [Pointer arithmetic](https://rux-lang.dev/docs/learn/pointer-arithmetic), [Writable slice](https://rux-lang.dev/docs/learn/writable-slice) :: A pointer knows where its storage starts, but not how long it is. A [slice](https://rux-lang.dev/docs/learn/slice) knows both. Indexing a pointer with a **range** joins the two, and that is how raw storage meets the rest of the language: a block from `Alloc` becomes an ordinary `int[..]`, so `for`, `.length` and every function that takes a slice work on it. ## `p[..n]` and `p[a..b]` After the usual allocation, the program builds a view of the whole block: ```rux let all = block[..count]; ``` `block[..count]` is a slice of the `count` elements starting at `block`. With two bounds, `block[a..b]` is the elements from `a` up to, but not including, `b`: | Expression | Elements | Length | | ---------------- | ------------------------------- | ------ | | `block[..count]` | 0 to 5 | 6 | | `block[2..4]` | 2 and 3 | 2 | | `block[4..=5]` | 4 and 5 | 2 | | `block[..]` | rejected — a pointer has no end | — | The last row is the important one. An array or a slice can be sliced with `[..]` because it knows its own length; a pointer does not, so the range must always say where to stop. ## The view goes wherever a slice goes From here on the program works with the view, which carries the count with it. These two functions know nothing about pointers or `Alloc`: ```rux func Fill(values: var int[..]) { for i in 0..values.length { values[i] = (i as int + 1) * 10; } } ``` ```rux Fill(all); Show("all: ", all); PrintLine("length: {}", all.length); ``` A view of a `*var int` is writable, just as a view of a `var` array is, so `all` can be passed where a `var int[..]` is wanted. A view of a read-only `*int` would be a read-only `int[..]`. ## Views share the storage A narrower view of the same block copies nothing. Both views look at the same memory, so a write through one shows up in the other: ```rux let middle = block[2..4]; Show("middle:", middle); middle[0] = 0; Show("after: ", all); ``` ```mermaid flowchart LR ptr["`block: *var int`"] --> s0 subgraph mem["the allocated block"] direction LR s0["`10`"] --- s1["`20`"] --- s2["`30`"] --- s3["`40`"] --- s4["`50`"] --- s5["`60`"] end all["`all = block[..count]`"] -.-> s0 middle["`middle = block[2..4]`"] -.-> s2 ``` `middle[0]` is the third element of the block, so the `30` in `all` becomes `0`. ## Checked index, trusted length Indexing a view is checked against its length, as for any slice. `all[6]` would stop the program with `Panic: index out of range`. But the length itself is yours to get right. A pointer cannot say how big its block is, so `n` in `block[..n]` is taken on trust: a view longer than the block is accepted, and its extra elements are someone else's memory. The rule that follows is simple — build the view once, from the count you allocated, and pass the view around instead of the pointer. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Memory/PointerSlice){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // A pointer knows where its storage starts but not how long it is. A slice knows both. Indexing // a pointer with a range joins the two: `p[..n]` is a slice of the `n` elements starting at `p`, // and `p[a..b]` the elements from `a` up to, not including, `b`. // // That is how raw storage meets the rest of the language. A block from `Alloc` becomes an // ordinary `int[..]`, so `for`, `.length` and every function that takes a slice work on it. // A view of a `*var int` is writable, just as a view of a `var` array is. // // Indexing a view is checked against its length, as for any slice: `all[6]` below would stop the // program with `Panic: index out of range`. But the length itself is yours to get right. A pointer // cannot say how big its block is, so `n` is taken on trust: a view longer than the block is // accepted, and its extra elements are someone else's memory. Build the view once, from the count // you allocated, and pass the view around instead of the pointer. import Io::{ Print, PrintLine }; import Memory::{ Alloc, Free }; func Fill(values: var int[..]) { for i in 0..values.length { values[i] = (i as int + 1) * 10; } } func Show(label: char8[..], values: int[..]) { Print("{}", label); for value in values { Print(" {}", value); } PrintLine(); } func Main() -> int { let count: uint = 6; let block = Alloc(count * sizeof(int)) as *var int; if block == null { PrintLine("out of memory"); return 1; } defer Free(block); // From here on the program works with the view, which carries the count with it. let all = block[..count]; Fill(all); Show("all: ", all); PrintLine("length: {}", all.length); // A narrower view of the same block. Nothing is copied: both views share the storage. let middle = block[2..4]; Show("middle:", middle); middle[0] = 0; Show("after: ", all); return 0; } ``` Besides `Io`, its `Rux.toml` lists `Memory` under `[Dependencies]`. ## Run it ```sh cd Examples/Memory/PointerSlice rux run ``` ```text all: 10 20 30 40 50 60 length: 6 middle: 30 40 after: 10 20 0 40 50 60 ``` ## Common mistakes ::mistake **Slicing a pointer with no end.**:br`block[..]` and `block[2..]` fail with: ```text error: cannot slice pointer '*var int' without an end bound ``` The help line says what to write instead: `p[..n]` or `p[a..b]`. :: ::mistake **Asking a pointer for its length.**:br`block.length` fails with: ```text error: type '*var int' has no field 'length' ``` Only the view knows its length: `all.length`. :: ::mistake **A read-only view for a writing function.**:br Cast the block to `*int` instead of `*var int`, and `Fill(block[..count])` fails with: ```text error: argument 1 to 'Fill' has type 'int[..]', but parameter 'values' requires 'var int[..]' ``` The view inherits the pointer's writability. :: ::mistake **A view longer than the block.**:br`block[..100]` on a six-element block compiles, and its indexes are checked against 100, not 6. Build every view from the count you passed to `Alloc`. :: ## Try it yourself 1. Add `all[6]` to a `PrintLine` and read the panic, including the line it points to. 2. Write `func Sum(values: int[..]) -> int` and call it with `all` and with `middle`. 3. Change `middle[0] = 0` to `middle[1] = 0`. Predict the `after:` line before you run. 4. Print the last two elements with an inclusive range, `block[4..=5]`. ## Learn more - [Slices and pointers](https://rux-lang.dev/docs/lang/slices/overview#members) in the Rux Reference - [Slice](https://rux-lang.dev/docs/learn/slice) and [Writable slice](https://rux-lang.dev/docs/learn/writable-slice) — the views this lesson produces - [Allocator](https://rux-lang.dev/docs/learn/allocator) — where this pattern is used with a better way of asking for memory # Optional pointer ::note **You'll need**: [Pointer](https://rux-lang.dev/docs/learn/pointer), [Presence](https://rux-lang.dev/docs/learn/presence), [Coalesce](https://rux-lang.dev/docs/learn/coalesce), [The is operator](https://rux-lang.dev/docs/learn/is) :: Pointers and [optionals](https://rux-lang.dev/docs/learn/optional) combine in two ways that look almost the same and mean different things. This lesson puts them side by side, gives each its own job, and clears up the difference between `null` and `none`. ## Where the `?` belongs A `?` belongs to the type just before it, as every type suffix does. So in `*var int?` it attaches to `int`, and parentheses are needed to put it on the pointer instead: | Type | Reads as | A value of it is | | ------------- | --------------------------------------- | -------------------------------------------------- | | `(*var int)?` | an optional pointer | either an address, or `none` | | `*var int?` | `*var (int?)`, a pointer to an optional | always an address — of a slot that holds an `int?` | ## An optional pointer: maybe an address `Find` answers "where is `wanted`?" with an address the caller can write through — or with `none`: ```rux func Find(values: var int[..], wanted: int) -> (*var int)? { for i in 0..values.length { if values[i] == wanted { return @values[i]; } } return none; } ``` A function that returned a bare pointer would use `null` for "not found", and leave remembering the check to you. One that returns `(*var int)?` cannot be used until a `match` or `??` has dealt with `none`: ```rux match Find(scores[..], 3) { found? => { *found = 30; PrintLine("found 3, changed it to {}", scores[1]); }, none => { PrintLine("3 is not there"); } } ``` ```mermaid flowchart LR f["`Find(scores, 3)`"] --> q{"present?"} q -- "`found?` — an address" --> w["`*found = 30`
writes into `scores`"] q -- "none" --> n["`3` is not there"] ``` Inside the `found?` arm, `found` is a plain `*var int`, and the write lands in the array: `scores[1]` becomes 30. The second search, for 5, takes the `none` arm. ## A pointer to an optional The other type is just a pointer — one that reaches an optional living somewhere else, the same way a `*var int` reaches an `int`: ```rux func KeepLargest(best: *var int?, value: int) { let current = *best ?? value; *best = value > current ? value : current; } ``` `*best` is the caller's `int?`. While it is still `none`, `?? value` makes the first value the largest so far. The caller passes the address of its own optional, which starts out empty: ```rux var best: int? = none; for score in scores { KeepLargest(@best, score); } ``` ## `null` is not `none` `null` is a pointer value — the address of nowhere. So an optional pointer given `null` is *present*: it holds a pointer, which happens to point nowhere. ```rux let wrapped: (*var int)? = null; PrintLine("null wrapped is present: {}", wrapped is *var int); ``` | You write | The optional is | Safe to reach through? | | ------------------------------ | --------------- | ------------------------- | | `let p: (*var int)? = none;` | absent | there is nothing to reach | | `let p: (*var int)? = null;` | present | no — it points nowhere | | `let p: (*var int)? = @score;` | present | yes | Use `none` to mean "no pointer". Mixing the two brings back exactly the unchecked `null` the optional was meant to remove. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Memory/OptionalPointer){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // Two types that look almost the same, and mean different things: // // (*var int)? an optional pointer: either an address, or `none` // *var int? a pointer to an optional: always an address, of a slot that holds an `int?` // // A `?` belongs to the type just before it, as every suffix does, so `*var int?` reads as // `*var (int?)`. Parentheses put the `?` on the pointer instead. // // An optional pointer is the honest way to say "maybe an address". A function that returns a // bare pointer and uses `null` for "not found" leaves the check to memory; one that returns // `(*var int)?` cannot be used until a `match` or `??` has dealt with `none`. // // A pointer to an optional is just a pointer, used to read or replace an optional that lives // somewhere else, the same way a `*var int` reaches an `int`. import Io::PrintLine; // Where is `wanted`? The answer is an address the caller can write through, or `none`. func Find(values: var int[..], wanted: int) -> (*var int)? { for i in 0..values.length { if values[i] == wanted { return @values[i]; } } return none; } // Keeps the largest value seen so far in the caller's `int?`, which starts out empty. func KeepLargest(best: *var int?, value: int) { let current = *best ?? value; *best = value > current ? value : current; } func Main() -> int { var scores: int[4] = [7, 3, 9, 3]; // Absence has to be handled before the address can be used. match Find(scores[..], 3) { found? => { *found = 30; PrintLine("found 3, changed it to {}", scores[1]); }, none => { PrintLine("3 is not there"); } } match Find(scores[..], 5) { found? => { *found = 50; }, none => { PrintLine("5 is not there"); } } // Writing through a pointer to an optional. var best: int? = none; PrintLine("best before: {}", best ?? -1); for score in scores { KeepLargest(@best, score); } PrintLine("best after: {}", best ?? -1); // `null` and `none` are different. `null` is a pointer value, so an optional pointer given // `null` is present: it holds a pointer, which happens to point nowhere. Use `none` to mean // "no pointer". let wrapped: (*var int)? = null; PrintLine("null wrapped is present: {}", wrapped is *var int); return 0; } ``` ## Run it ```sh cd Examples/Memory/OptionalPointer rux run ``` ```text found 3, changed it to 30 5 is not there best before: -1 best after: 30 null wrapped is present: true ``` ## Common mistakes ::mistake **Reaching through an optional pointer without unwrapping it.**:br`*Find(scores[..], 3) = 30;` fails with: ```text error: operator '*' requires a pointer operand, but found '(*var int)?' ``` Handle `none` first, with a `match` or with `??`. :: ::mistake **Leaving out the parentheses.**:br Declare `Find` as returning `*var int?` and it promises a pointer to an optional instead. `return none;` then fails with: ```text error: 'none' needs an expected optional type, but found '*var (int?)' ``` The message spells out how the compiler read the type. :: ::mistake **Using `null` to mean "no pointer".**:br`(*var int)? = null` is present, so a `match` takes the `found?` arm and the code reaches through `null`. Write `none`. :: ## Try it yourself 1. Give the missing 5 a place to go: `let slot = Find(scores[..], 5) ?? @spare;` with `var spare: int = 0;`, then write `*slot = 50` and print `spare`. 2. Write `KeepSmallest` and check that it finds 3. 3. Change `Find` so that it returns the *last* match rather than the first, and see which element becomes 30. 4. Set `wrapped` to `none` instead of `null`. What does the last line print now? ## Learn more - [Presence](https://rux-lang.dev/docs/learn/presence) and [Coalesce](https://rux-lang.dev/docs/learn/coalesce) — the two ways to deal with `none` - [Is](https://rux-lang.dev/docs/learn/is) — the type test used on the last line - [The `null` pointer](https://rux-lang.dev/docs/lang/pointers/overview#null) in the Rux Reference # Layout ::note **You'll need**: [Struct](https://rux-lang.dev/docs/learn/struct), [Pointer](https://rux-lang.dev/docs/learn/pointer), [Pointer arithmetic](https://rux-lang.dev/docs/learn/pointer-arithmetic) :: You have been multiplying by `sizeof` since [Raw memory](https://rux-lang.dev/docs/learn/raw-memory). This lesson looks at what that number really is, at its partner `alignof`, and at the hidden bytes that make a struct bigger than the sum of its fields. ## Size and alignment Every type has two numbers: - its **size** — how many bytes one value occupies, from `sizeof(T)`; - its **alignment** — every value of the type must sit at an address that is a multiple of this number, from `alignof(T)`. ```rux PrintLine("int64 {} {}", sizeof(int64), alignof(int64)); ``` For the plain number types the two are the same: a `uint8` is one byte and may sit anywhere, an `int64` is eight bytes and must sit at a multiple of eight. The processor reads aligned values fastest, and on some machines can only read them aligned at all. ## Padding inside a struct A struct keeps its fields in the order they are written, and each field must sit at an address that suits its own alignment. Look at `Loose`: ```rux struct Loose { flag: bool; total: int64; mark: uint8; } ``` `flag` takes byte 0. `total` needs a multiple of eight, so it cannot start at byte 1: seven unused bytes of **padding** go in between, and `total` starts at 8. `mark` lands at 16. Then the whole struct is rounded up to a multiple of its largest alignment, 8, so that in an array the next element lines up too. That makes 24 bytes for 10 bytes of data. `Tight` has the same three fields, widest first: ```rux struct Tight { total: int64; flag: bool; mark: uint8; } ``` ```mermaid flowchart TB subgraph loose["`Loose` — 24 bytes"] direction LR l1["`flag`
0"] --- l2["padding
1–7"] --- l3["`total`
8–15"] --- l4["`mark`
16"] --- l5["padding
17–23"] end subgraph tight["`Tight` — 16 bytes"] direction LR t1["`total`
0–7"] --- t2["`flag`
8"] --- t3["`mark`
9"] --- t4["padding
10–15"] end ``` Putting the widest fields first usually leaves the least padding. ## Measuring where a field landed The offsets in the output are not guessed — the program measures them. Converting an address to `uint` turns it into a number, so the distance from the start of the value to a field is a subtraction: ```rux var loose = Loose { flag: true, total: 1, mark: 2 }; let start = @loose as uint; PrintLine("Loose: flag at {}, total at {}, mark at {}", (@loose.flag as uint) - start, (@loose.total as uint) - start, (@loose.mark as uint) - start); ``` ## Arrays have no gaps between elements An array is its elements side by side, each one `sizeof` apart, with nothing in between. The padding already inside each element is what keeps the next one aligned: ```rux PrintLine("Loose[4] takes {} bytes, Tight[4] takes {}", sizeof(Loose[4]), sizeof(Tight[4])); ``` Four `Loose` values cost 96 bytes; four `Tight` ones 64. In a large array, field order is real memory. ## Facts about this build The numbers in the output are for a 64-bit target. Sizes and alignments are decided by the target the program is built for, so treat them as facts about this build, not as constants of the language — and let `sizeof` and `alignof` tell you rather than writing the numbers down. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Memory/Layout){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // Every type has a size, the bytes one value occupies, and an alignment: its address must be a // multiple of that number. `sizeof(T)` and `alignof(T)` ask the compiler for both. // // A struct keeps its fields in the order they are written, and each field must sit at an // address that suits its own alignment. So when a one-byte `bool` is followed by an eight-byte // `int64`, seven unused bytes of padding go between them. The whole struct is then rounded up // to its largest alignment, so that in an array every element lines up too. // // The same three fields can therefore cost different amounts depending on their order. Putting // the widest fields first usually leaves the least padding. // // The numbers below are for a 64-bit target. Sizes and alignments are decided by the target the // program is built for, so treat them as facts about this build, not constants of the language. import Io::PrintLine; struct Loose { flag: bool; total: int64; mark: uint8; } struct Tight { total: int64; flag: bool; mark: uint8; } func Main() -> int { PrintLine("type size align"); PrintLine("uint8 {} {}", sizeof(uint8), alignof(uint8)); PrintLine("int32 {} {}", sizeof(int32), alignof(int32)); PrintLine("int64 {} {}", sizeof(int64), alignof(int64)); PrintLine("int {} {}", sizeof(int), alignof(int)); PrintLine("Loose {} {}", sizeof(Loose), alignof(Loose)); PrintLine("Tight {} {}", sizeof(Tight), alignof(Tight)); // Where each field landed, measured from the start of the value. The gaps are padding. var loose = Loose { flag: true, total: 1, mark: 2 }; let start = @loose as uint; PrintLine("Loose: flag at {}, total at {}, mark at {}", (@loose.flag as uint) - start, (@loose.total as uint) - start, (@loose.mark as uint) - start); var tight = Tight { total: 1, flag: true, mark: 2 }; let base = @tight as uint; PrintLine("Tight: total at {}, flag at {}, mark at {}", (@tight.total as uint) - base, (@tight.flag as uint) - base, (@tight.mark as uint) - base); // An array is its elements side by side, each one `sizeof` apart, with nothing in between. PrintLine("Loose[4] takes {} bytes, Tight[4] takes {}", sizeof(Loose[4]), sizeof(Tight[4])); return 0; } ``` ## Run it ```sh cd Examples/Memory/Layout rux run ``` ```text type size align uint8 1 1 int32 4 4 int64 8 8 int 8 8 Loose 24 8 Tight 16 8 Loose: flag at 0, total at 8, mark at 16 Tight: total at 0, flag at 8, mark at 9 Loose[4] takes 96 bytes, Tight[4] takes 64 ``` This output is from a 64-bit build; sizes and alignments depend on the target. ## Common mistakes ::mistake **Adding up the fields.**:br`Loose` holds 1 + 8 + 1 bytes of data but occupies 24. Allocating "10 bytes per `Loose`" would leave every element short. Ask `sizeof(Loose)`. :: ::mistake **Writing sizes down as numbers.**:br`count * 8` for an array of `int` is right on a 64-bit target and wrong elsewhere. `count * sizeof(int)` is right everywhere. :: ::mistake **Expecting the compiler to reorder fields.**:br Rux keeps fields in the order you write them, padding and all. If size matters, order the fields yourself, widest first. :: ## Try it yourself 1. Declare `struct Mixed { a: uint8; b: int32; c: uint8; d: int16; }`. Predict its size and alignment, check with `sizeof` and `alignof`, then reorder the fields to make it 8 bytes. 2. Print `sizeof(*int)` and `sizeof(char8[..])`. Why is a slice twice the size of a pointer? 3. A struct of three `uint8` fields: what are its size and alignment? Is there any padding? ## Learn more - [Structs](https://rux-lang.dev/docs/lang/structs/overview) in the Rux Reference - [Pointer arithmetic](https://rux-lang.dev/docs/learn/pointer-arithmetic) — why a `+ 1` steps by `sizeof` - [Union](https://rux-lang.dev/docs/learn/union) — a type whose size is its largest member, not the sum # Union ::note **You'll need**: [Layout](https://rux-lang.dev/docs/learn/layout), [Enum](https://rux-lang.dev/docs/learn/enum), [Variant](https://rux-lang.dev/docs/learn/variant), [Match](https://rux-lang.dev/docs/learn/match) :: A struct lays its fields side by side. A **union** lays its members over the *same* bytes: it is as large as its largest member, not the sum of them, because only one member is meant to be in use at a time. That saves space, and it gives exact control over layout. What a union does not do is remember which member is in use. This lesson shows what follows from that, and why a [variant](https://rux-lang.dev/docs/learn/variant) is usually the better tool. ## Declaring a union A union looks like a struct, except that its members are separated by commas rather than ended with semicolons: ```rux union Payload { whole: int64, real: float64, flag: bool } ``` The program compares it with a struct of the same three fields: | Type | Holds | Size on this build | | ---------- | ------------------------ | ------------------ | | `AllThree` | all three values at once | 24 bytes | | `Payload` | one of them at a time | 8 bytes | ```mermaid flowchart LR bytes[("8 bytes of storage")] --> w["read as `whole: int64`"] bytes --> r["read as `real: float64`"] bytes --> f["read as `flag: bool`"] ``` A union literal names exactly one member — the one that becomes active: ```rux Payload { whole: 42 } ``` ## A union does not remember A `variant` keeps a hidden tag and will only hand out the case that was stored. A union keeps nothing. Reading a member other than the one last written is not a conversion: it hands back the same bytes reinterpreted as another type. Write `real = 2.25` and then read `whole`, and on this machine you get 4612248968380809216 — the bit pattern of 2.25 read as an integer. A `bool` read that way may not even be `true` or `false`. The compiler will not stop such a read. | | `struct` | `variant` | `union` | | ------------------------- | ----------------- | ----------------------- | ------------------------ | | Holds | every field | one case | one member | | Size | sum, plus padding | largest case plus a tag | largest member | | Knows which one is in use | — | yes | no | | Reading the wrong one | — | impossible | compiles, gives nonsense | ## Keeping the tag yourself So keeping track is the program's job, usually with an explicit tag beside the union. That is what `Setting` does: ```rux struct Setting { kind: Kind; payload: Payload; } ``` Every reader checks the tag first, and only then touches the member it names: ```rux func Describe(setting: Setting) { match setting.kind { .Whole => PrintLine("whole number {}", setting.payload.whole), .Real => PrintLine("real number {}", setting.payload.real), .Flag => PrintLine("flag {}", setting.payload.flag) } } ``` ## Switching members Switching to another member means writing the new member and the tag together: ```rux var setting = Setting { kind: Kind::Whole, payload: Payload { whole: 7 } }; setting.payload.real = 2.25; setting.kind = Kind::Real; ``` After this, `whole` is no longer meaningful: its bytes now belong to `real`. Forget the tag on the last line, and `Describe` would print 4612248968380809216 as a "whole number". ## When a union is the right tool Prefer a `variant` whenever it will do — it is the tagged union, with the tag kept for you and checked on every read. Reach for a plain union when the exact layout is the point: a fixed format shared with other code, such as a C library, or saving space where the tag is already known from somewhere else. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Memory/Union){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // A union lays several members over the same bytes. It is as large as its largest member, not // the sum of them, because only one member is meant to be in use at a time. // // What a union does not do is remember which one that is. A `variant` keeps a hidden tag and // will only hand out the case that was stored; a union keeps nothing. Keeping track is the // program's job, usually with an explicit tag beside it, as `Setting` does below. // // That job matters because reading a member other than the one last written is not a // conversion. It hands back the same bytes reinterpreted as another type: what comes out depends // on how the target lays out numbers, and it may not even be a valid value of that type, such // as a `bool` that is neither `true` nor `false`. The compiler will not stop such a read. // // So prefer a `variant` whenever it will do. Reach for a union when the exact layout is the // point: a fixed format shared with other code, or saving space where the tag is already known. import Io::PrintLine; // Members are separated by commas, not ended with semicolons as struct fields are. union Payload { whole: int64, real: float64, flag: bool } // For comparison: the same three values side by side. struct AllThree { whole: int64; real: float64; flag: bool; } enum Kind { Whole, Real, Flag } // The tag says which member of `payload` holds a value. Every function that builds a `Setting` // must set both together, and every reader must check the tag first. struct Setting { kind: Kind; payload: Payload; } func Describe(setting: Setting) { match setting.kind { .Whole => PrintLine("whole number {}", setting.payload.whole), .Real => PrintLine("real number {}", setting.payload.real), .Flag => PrintLine("flag {}", setting.payload.flag) } } func Main() -> int { PrintLine("sizeof(Payload) {}", sizeof(Payload)); PrintLine("sizeof(AllThree) {}", sizeof(AllThree)); // A union literal names exactly one member: the one that becomes active. Describe(Setting { kind: Kind::Whole, payload: Payload { whole: 42 } }); Describe(Setting { kind: Kind::Real, payload: Payload { real: 0.5 } }); Describe(Setting { kind: Kind::Flag, payload: Payload { flag: true } }); // Switching members means writing the new member and the tag together. After this, `whole` // is no longer meaningful: its bytes now belong to `real`. var setting = Setting { kind: Kind::Whole, payload: Payload { whole: 7 } }; setting.payload.real = 2.25; setting.kind = Kind::Real; Describe(setting); return 0; } ``` ## Run it ```sh cd Examples/Memory/Union rux run ``` ```text sizeof(Payload) 8 sizeof(AllThree) 24 whole number 42 real number 0.5 flag true real number 2.25 ``` ## Common mistakes ::mistake **Ending union members with semicolons.**:br Struct habits die hard. `whole: int64;` inside a union fails with: ```text error: expected ',' between union fields before ';' ``` The help line says to separate the members with commas. :: ::mistake **Naming more than one member in a literal.**:br`Payload { whole: 1, real: 2.0 }` fails with: ```text error: union initializer for 'Payload' must select exactly one field, but 2 were provided ``` An empty `Payload {}` fails the same way with `but 0 were provided`. :: ::mistake **Changing the member without the tag.**:br`setting.payload.real = 2.25;` on its own compiles, and the next `Describe` reads those bytes as a whole number. Change the member and the tag together, and keep that in one function if you can. :: ## Try it yourself 1. Read `whole` from `Payload { real: 1.0 }` and print it. Can you see why a float and an integer that look alike in source are nothing alike in memory? 2. Add a fourth member, `text: char8[..]`, to `Payload`, with a matching `Kind::Text` and a `Describe` arm. What is `sizeof(Payload)` now? 3. Rewrite `Setting` as a `variant` with `Whole`, `Real` and `Flag` cases, and compare its `sizeof` with `Setting`'s. ## Learn more - [Unions](https://rux-lang.dev/docs/lang/unions/overview) in the Rux Reference - [Variant](https://rux-lang.dev/docs/learn/variant) — the tagged union that keeps the tag for you - [Layout](https://rux-lang.dev/docs/learn/layout) — sizes and alignment, which decide how big a union is # Allocator ::note **You'll need**: [Pointer slice](https://rux-lang.dev/docs/learn/pointer-slice), [Interface value](https://rux-lang.dev/docs/learn/interface-value), [Propagate](https://rux-lang.dev/docs/learn/propagate), [Absence to error](https://rux-lang.dev/docs/learn/absence-to-error), [Defer](https://rux-lang.dev/docs/learn/defer) :: `Alloc` and `Free` always go to the same place, and they report failure with a `null` that is easy to forget. An **allocator** fixes both. It turns "where memory comes from" into a value you can pass around, and it reports failure as a real error that has to be handled before there is any address to misuse. This lesson uses the simplest allocator, `SystemAllocator`. Later lessons in this part swap in others — an arena, a fixed buffer, a pool — without changing how they are called. ## The `Allocator` interface `Allocator`, from the `Allocator` package, is an [interface](https://rux-lang.dev/docs/learn/interface). It promises three operations, and any type that keeps those promises can stand behind it: | Operation | Does | Returns | | ----------------------------------------- | ------------------------------------- | ---------------------------- | | `Allocate(layout)` | takes storage that matches the layout | `(*var opaque) ! AllocError` | | `Deallocate(block, layout)` | gives the storage back | `! AllocError` | | `Reallocate(block, oldLayout, newLayout)` | grows or shrinks a block | `(*var opaque) ! AllocError` | A function written against the interface works with whichever allocator its caller passes in: ```rux func SumOfSquares(allocator: Allocator, count: uint) -> int64 ! AllocError { ``` ```mermaid flowchart LR f["`SumOfSquares`"] -- "`Allocate(layout)`" --> i{{"`Allocator`"}} i --> s["`SystemAllocator`"] s -- "asks for pages" --> os[("the operating
system")] i -- "an address,
or an `AllocError`" --> f ``` ## A request is a `Layout` `Alloc` took a byte count. `Allocate` takes a `Layout`: a size and an alignment together, so the two always travel as a pair. `Layout::ForArray(count)` builds one for `count` values of `T`: ```rux let layout = Layout::ForArray(count) ?? fail AllocError::Unsupported; ``` It returns `Layout?` — `none` when `count` elements could not even be described, because the size would overflow. Here `??` turns that into an `AllocError`, as in [Absence to error](https://rux-lang.dev/docs/learn/absence-to-error). `Layout::ForValue()` describes a single value and cannot fail; you will meet it in the next lessons. ## Failure is an error, not a `null` `Allocate` returns a fallible, so the address only exists once the failure has been dealt with. Here `?` passes a refusal on to the caller: ```rux let block = allocator.Allocate(layout)?; ``` Past this line, `block` is real storage. The release is registered at once, with the same layout the block was asked for with: ```rux defer allocator.Deallocate(block, layout) catch { else => {} }; ``` `Deallocate` is fallible too. A refused release here could only be the allocator's own bug, and there is nobody to report it to, so `catch { else => {} }` discards it on purpose. The failure itself says why it happened: | `AllocError` | Means | | -------------- | -------------------------------------------------------------------------- | | `Unsupported` | this allocator cannot serve the request at all; asking again will not help | | `OutOfMemory` | there is no storage left right now | | `InvalidBlock` | a release named a block or a layout this allocator did not hand out | ## Getting an `Allocator` `Main` builds the concrete allocator, then names it at the interface type: ```rux var system = SystemAllocator(); let allocator: Allocator = system; ``` `SystemAllocator` carries no state of its own: it asks the operating system for whole pages every time. That is fine for a few large requests like these, and wasteful for many small ones — which is what the arena and the pool, later in this part, are for. ## The refused request The last call asks for a billion billion `int64`s. `ForArray` can still describe that many, but no machine can provide them, so the allocator refuses and `Try` prints the reason. Which reason you see depends on how the operating system answers, which is why the output note says it may differ. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Memory/Allocator){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // `Alloc` and `Free` always go to the same place. An allocator turns "where memory comes from" // into a value: the `Allocator` interface promises three operations, and any type that keeps // those promises can stand behind it. A function written against the interface works with // whichever allocator its caller passes in. // // This lesson uses `SystemAllocator`, which asks the operating system. The next lessons swap in // others without changing how they are called. // // Two things differ from `Alloc`. A request is a `Layout`, a size and an alignment together, // built here by `Layout::ForArray(count)`. And failure is a real error, not a `null`: // `Allocate` returns `(*var opaque) ! AllocError`, so there is no address to misuse until the // failure has been handled. A block must go back through `Deallocate` with the same layout it // was asked for with. import Allocator::{ AllocError, Allocator, Layout, SystemAllocator }; import Io::PrintLine; // Borrows `count` numbers' worth of memory, uses it, and gives it back. func SumOfSquares(allocator: Allocator, count: uint) -> int64 ! AllocError { // `ForArray` is `none` when `count` elements could not even be described. let layout = Layout::ForArray(count) ?? fail AllocError::Unsupported; // `?` passes a refusal on to the caller. Past this line, `block` is real storage. let block = allocator.Allocate(layout)?; // Registered at once, so every path out returns the block with its layout. A refused release // here would be the allocator's own bug, and there is nobody to report it to. defer allocator.Deallocate(block, layout) catch { else => {} }; let numbers = (block as *var int64)[..count]; var total: int64 = 0; for i in 0..count { numbers[i] = (i * i) as int64; total += numbers[i]; } return total; } func Reason(error: AllocError) -> char8[..] { return match error { .Unsupported => "the request cannot be served", .OutOfMemory => "there is not enough memory", .InvalidBlock => "the block was not from this allocator" }; } func Try(allocator: Allocator, count: uint) { match SumOfSquares(allocator, count) { .Success(total) => PrintLine("{} squares add up to {}", count, total), .Failure(error) => PrintLine("{} squares: refused, {}", count, Reason(error)) } } func Main() -> int { // Build the concrete allocator, then name it at the interface type to get an `Allocator`. var system = SystemAllocator(); let allocator: Allocator = system; Try(allocator, 10); Try(allocator, 1000); // Eight bytes times this count is far more memory than any machine has. Try(allocator, 1000000000000000000); return 0; } ``` Besides `Io`, its `Rux.toml` lists `Allocator` under `[Dependencies]`. ## Run it ```sh cd Examples/Memory/Allocator rux run ``` ```text 10 squares add up to 285 1000 squares add up to 332833500 1000000000000000000 squares: refused, the request cannot be served ``` The reason given on the last line comes from the operating system's answer, so it can differ between systems. ## Common mistakes ::mistake **Using the block before handling the failure.**:br`let block = allocator.Allocate(layout);` without `?` holds a fallible, not an address, so `block as *var int64` fails with: ```text error: cannot cast value of type '*var opaque ! AllocError' to '*var int64' ``` Unwrap it first: `?`, `catch` or a `match`. :: ::mistake **Passing the optional layout.**:br Leave out the `?? fail …` and `layout` is a `Layout?`. `Allocate(layout)` then fails with: ```text error: argument 1 to 'Allocate' has type 'Layout?', but parameter 'layout' requires 'Layout' ``` :: ::mistake **A bare deferred release.**:br`defer allocator.Deallocate(block, layout);` fails with: ```text error: fallible result of type '! AllocError' is discarded ``` Decide what a refused release means, or discard it on purpose with `catch { else => {} }`. :: ::mistake **Releasing with a different layout.**:br A block must go back with the layout it was asked for with. `SystemAllocator` notices a mismatch and refuses with `AllocError::InvalidBlock`; other allocators may not be able to tell, and quietly go wrong instead. :: ## Try it yourself 1. Add `Try(allocator, 0);`. What does a zero-element request give back, and does it still need releasing? 2. Make `Try` also print `error.IsTransient()`, which is `true` only for `OutOfMemory` — the one failure that might go away if you ask again later. 3. Write `SumOfCubes` against the same interface and call it with the same allocator. ## Learn more - [Interface value](https://rux-lang.dev/docs/learn/interface-value) — how a concrete value stands behind an interface type - [Propagate](https://rux-lang.dev/docs/learn/propagate) and [Absence to error](https://rux-lang.dev/docs/learn/absence-to-error) — the `?` and `?? fail` used here - [Box](https://rux-lang.dev/docs/learn/box) — the next lesson, which stops you from having to call `Deallocate` at all # Box ::note **You'll need**: [Allocator](https://rux-lang.dev/docs/learn/allocator), [Destructor](https://rux-lang.dev/docs/learn/destructor), [Move](https://rux-lang.dev/docs/learn/move), [Fallible main](https://rux-lang.dev/docs/learn/fallible-main) :: The raw lessons kept leaving one job to you: remember to give the memory back, exactly once, and never touch it afterwards. A `Box` takes that job over. It owns one value that lives in allocated memory, and — like any value with a [destructor](https://rux-lang.dev/docs/learn/destructor) — it cleans up after itself when its life ends. ## Creating a box `Box::Create(allocator, value)` asks the allocator for room, moves the value in, and hands back the box: ```rux let boxed = Box::Create(allocator, Tally { name: name, count: 1 })?; ``` Asking can fail, so `Create` returns `Box ! AllocError`, and `?` passes a refusal on. From this line on, the box is the value's one owner. ## Reaching the value `Get()` returns a `*var T` into the box's storage, so fields are reached through it with a plain `.`, as through any pointer: ```rux apples.Get().count += 2; PrintLine(" {} {}", apples.Get().count, apples.Get().name); ``` That pointer does not own anything. It is valid only while the box is alive — the box decides when the storage goes, not the pointer. ## The box cleans up Nobody calls `Deallocate` in this program. When a box's life ends, its destructor destroys the value — which runs `~Tally` and prints a line — and then gives the memory back to the allocator it came from: ```mermaid flowchart LR create["`Box::Create(allocator, value)`"] --> alloc["the allocator gives room,
the value moves in"] alloc --> use["`boxed.Get()` — use it"] use --> end_["the box's life ends"] end_ --> drop["`~Tally` runs"] drop --> back["memory goes back to
the same allocator"] ``` You can see the timing in the output. The box in `Count` dies when `Count` returns, so `destroying the pears tally` is printed before `Main` carries on with `a box in Main:`. ## Moving a box A box cannot be copied: two owners would both release the memory, and the second release would hit memory that was no longer theirs. It can be **moved** with `<-`, which hands the ownership on and retires the old name: ```rux let storage = apples.Get(); let owner <- apples; PrintLine(" moved, same storage: {}", owner.Get() == storage); ``` The value itself stays where it was allocated, so the new owner points at the very same storage — the comparison prints `true`. Only the right to release it has moved. At the end of `Main`, `owner` releases the memory, once, and `apples` releases nothing because it no longer owns anything. | You write | What happens | | ---------------------- | ----------------------------------------------- | | `let owner <- apples;` | ownership moves; `apples` can no longer be used | | `let owner = apples;` | rejected — a box cannot be copied | | `apples.Get()` | a borrowed `*var T`, valid while the box lives | ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Memory/Box){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // A `Box` owns one value that lives in allocated memory. `Box::Create(allocator, value)` // asks the allocator for room, moves the value in, and hands back the box, or an `AllocError` // if there was no room. From then on the box is the value's one owner. // // That ownership is what the raw lessons were missing. Nobody calls `Deallocate`: when the box's // life ends, its destructor destroys the value and gives the memory back to the allocator it // came from. And a box cannot be copied, because two owners would release the memory twice. // Hand it on with `<-`, and the old binding can no longer be used. // // `Get()` returns a `*var T` into the box's storage. That pointer does not own anything: it is // valid only while the box is alive. import Allocator::{ AllocError, Allocator, Box, SystemAllocator }; import Io::PrintLine; struct Tally { name: char8[..]; count: int; } extend Tally { func ~Tally(self: &var Tally) { PrintLine(" destroying the {} tally", self.name); } } // The box is created and dies inside this call, so its memory is returned before `Main` resumes. func Count(allocator: Allocator, name: char8[..]) -> ! AllocError { let boxed = Box::Create(allocator, Tally { name: name, count: 1 })?; PrintLine(" counted {} {}", boxed.Get().count, boxed.Get().name); } func Main() -> ! AllocError { var system = SystemAllocator(); let allocator: Allocator = system; PrintLine("a short-lived box:"); Count(allocator, "pears")?; PrintLine("a box in Main:"); var apples = Box::Create(allocator, Tally { name: "apples", count: 3 })?; apples.Get().count += 2; PrintLine(" {} {}", apples.Get().count, apples.Get().name); // Moving the box moves the ownership. The value itself stays where it was allocated, so the // new owner points at the very same storage. let storage = apples.Get(); let owner <- apples; PrintLine(" moved, same storage: {}", owner.Get() == storage); // Using `apples` from here on is rejected: it was moved out. `owner` releases the memory, once. PrintLine("end of Main:"); } ``` Besides `Io`, its `Rux.toml` lists `Allocator` under `[Dependencies]`. ## Run it ```sh cd Examples/Memory/Box rux run ``` ```text a short-lived box: counted 1 pears destroying the pears tally a box in Main: 5 apples moved, same storage: true end of Main: destroying the apples tally ``` ## Common mistakes ::mistake **Copying a box.**:br`let owner = apples;` fails with: ```text error: move-only value 'apples' requires an explicit '<-' in initialization ``` The help line suggests `let destination <- apples`. Move it, or keep using the one box. :: ::mistake **Using a box after moving it.**:br After `let owner <- apples;`, any use of `apples` fails with: ```text error: value 'apples' is used after it was moved ``` Use `owner` from then on. :: ::mistake **Forgetting the `?`.**:br`let apples = Box::Create(…);` without `?` holds a fallible, so `apples.Get()` fails with: ```text error: type 'Box ! AllocError' has no field 'Get' ``` Handle the `AllocError` first. :: ::mistake **Keeping the pointer from `Get()` longer than the box.**:br A function that creates a box and returns `boxed.Get()` compiles — but the box dies on the way out, and the caller is left holding the address of released memory. Return the box itself, moved with `<-`, instead. :: ## Try it yourself 1. Create a second box, `plums`, in `Main` before `apples`. Predict the order of the two `destroying` lines at the end, then run. 2. Write `func Report(owner: Box)` that prints the tally, and call it as `Report(<-apples)`. Where does `destroying the apples tally` appear now? 3. Change `Count` to return the box, `-> Box ! AllocError`, with `return <-boxed;`, and keep it alive in `Main`. ## Learn more - [Move](https://rux-lang.dev/docs/learn/move) and [Destructor](https://rux-lang.dev/docs/learn/destructor) — the ownership rules a box is built on - [Allocator](https://rux-lang.dev/docs/learn/allocator) — where a box's memory comes from - [Arena](https://rux-lang.dev/docs/learn/arena) — an allocator a box can draw from, with one extra rule # Arena ::note **You'll need**: [Allocator](https://rux-lang.dev/docs/learn/allocator), [Box](https://rux-lang.dev/docs/learn/box), [Pointer slice](https://rux-lang.dev/docs/learn/pointer-slice), [Fallible main](https://rux-lang.dev/docs/learn/fallible-main) :: Plenty of work produces many small pieces of memory whose lives all end together: everything built while handling one request, one frame of a game, one round of a loop. Releasing each piece separately is slow and easy to get wrong. An **arena** takes a different approach — it never takes back a single piece, and instead takes back *everything* at once. ## How an arena hands out memory An arena holds a large block and a marker. Each request is served from the marker onwards, and the marker moves forward past it. That is all an allocation costs: an addition and a check that the block still has room. When a block runs out, the arena takes a bigger one from the allocator behind it, its *backing* allocator. `Reset` moves the marker back to the start, keeping the largest block for next time, and the arena's destructor returns all its blocks when the arena itself dies. ```mermaid flowchart LR sys["`SystemAllocator`"] -- "large blocks" --> arena["`Arena`"] arena -- "`Handle()`" --> h["`Allocator`"] h -- "`Allocate`:
move the marker" --> work["one round
of work"] work -- "`Reset`:
marker back to the start" --> arena arena -- "`~Arena`:
blocks returned" --> sys ``` ## Setting one up The arena is built over a backing allocator, with the size of its first block: ```rux var arena = Arena(backing, 256); var handle = arena.Handle(); let allocator: Allocator = handle; ``` The arena is used through `Handle()`, an `Allocator` that points back at it. Code like `Squares` takes that `Allocator` and has no idea an arena is behind it. ## Nobody releases anything `Squares` asks for storage and never gives it back: ```rux let numbers = (allocator.Allocate(layout)? as *var int64)[..count]; ``` With `SystemAllocator` that would be a leak. With an arena it is the intended use: the memory belongs to the round, and the round ends with one call. ```rux arena.Reset(); ``` ## Watching it grow The three `Squares` calls of a round ask for 10, 20 and 30 numbers of eight bytes — 480 bytes in all. The first round outgrows the 256-byte block and takes a second, larger one, so it ends holding two blocks. `Reset` keeps only the larger block, and every later round fits inside it: the output shows `blocks held 1` from then on, and the arena never asks the system for anything again. `BytesUsed` counts across every block the arena holds. ## The rule the compiler does not check After `Reset`, every address the arena handed out is invalid, even though the pointers holding them still look fine. Finish with them first. That includes any [Box](https://rux-lang.dev/docs/learn/box) built on the arena: destroy the box before the reset, or its destructor will later run on memory the arena has already handed out again. The handle has a rule of its own. It holds a pointer back to the arena, so it must not outlive the arena, and it must not be used after the arena moves. | Shape of the work | Arena? | | --------------------------------------------- | ---------------------------------------------------------------- | | Many pieces that all end together | yes — one `Reset` frees them all | | Pieces that end one by one, in no fixed order | no — see [Pool](https://rux-lang.dev/docs/learn/pool) | | A fixed amount of memory you already have | see [Fixed buffer](https://rux-lang.dev/docs/learn/fixed-buffer) | ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Memory/Arena){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // An arena hands out memory by moving a marker forward through a large block, and never takes // back a single piece. Instead, `Reset` takes everything back at once, and the arena's // destructor returns its blocks to the allocator behind it. // // That fits work whose pieces all end together: one request, one frame, one round of a loop. // Asking is fast, nothing has to be released piece by piece, and nothing can be released twice. // When a block runs out, the arena takes a bigger one from its backing allocator; `Reset` keeps // the largest, so the next round usually needs nothing new. // // The price is one rule the compiler does not check: after `Reset`, every address the arena // handed out is invalid. Finish with them first, and that includes any `Box` built on the // arena, which must be destroyed before the reset. The arena is used through `Handle()`, an // `Allocator` that points back at it, so the handle must not outlive the arena or be used after // the arena moves. import Allocator::{ AllocError, Allocator, Arena, Layout, SystemAllocator }; import Io::PrintLine; // Scratch storage for one round. Nothing here releases it; the arena's reset will. func Squares(allocator: Allocator, count: uint) -> int64 ! AllocError { let layout = Layout::ForArray(count) ?? fail AllocError::Unsupported; let numbers = (allocator.Allocate(layout)? as *var int64)[..count]; var total: int64 = 0; for i in 0..count { numbers[i] = (i * i) as int64; total += numbers[i]; } return total; } func Main() -> ! AllocError { var system = SystemAllocator(); let backing: Allocator = system; // The first block holds 256 bytes; later ones grow as needed. var arena = Arena(backing, 256); var handle = arena.Handle(); let allocator: Allocator = handle; for round in 1..=3 { // 10, 20 and 30 numbers of eight bytes: 480 bytes in all. The first round outgrows the // 256-byte block and takes a second, larger one. The reset keeps that larger block, and // every later round fits inside it. `BytesUsed` counts across every block the arena holds. let total = Squares(allocator, 10)? + Squares(allocator, 20)? + Squares(allocator, 30)?; PrintLine("round {}: total {}, bytes in use {}, blocks held {}", round, total, arena.BytesUsed(), arena.BlockCount()); // The round is over and nothing from it is still in use, so all of it goes at once. arena.Reset(); PrintLine(" reset: bytes in use {}, blocks held {}", arena.BytesUsed(), arena.BlockCount()); } } ``` Besides `Io`, its `Rux.toml` lists `Allocator` under `[Dependencies]`. ## Run it ```sh cd Examples/Memory/Arena rux run ``` ```text round 1: total 11310, bytes in use 480, blocks held 2 reset: bytes in use 0, blocks held 1 round 2: total 11310, bytes in use 480, blocks held 1 reset: bytes in use 0, blocks held 1 round 3: total 11310, bytes in use 480, blocks held 1 reset: bytes in use 0, blocks held 1 ``` ## Common mistakes ::mistake **An arena declared with `let`.**:br`Handle()` needs to point at an arena it can change, so with `let arena = …` the call fails with: ```text error: cannot call 'Handle' on immutable 'arena' ``` The help line suggests declaring it with `var`. :: ::mistake **Copying the arena.**:br`let copy = arena;` fails with: ```text error: move-only value 'arena' requires an explicit '<-' in initialization ``` Two arenas sharing the same blocks would release them twice. And if you do move it with `<-`, every handle taken before the move points at the old place — take a new one. :: ::mistake **Using memory after `Reset`.**:br A pointer or a view from the last round still compiles after `arena.Reset()`, and reads whatever the next round wrote there. Nothing reports it. Let every pointer from a round go out of use before the reset. :: ::mistake **Expecting `Deallocate` to give memory back.**:br An arena accepts `Deallocate`, so code written for any allocator still works, but it only rewinds the most recent allocation. Releasing anything older does nothing until the next `Reset`. :: ## Try it yourself 1. Change the first block size from 256 to 1024. How many blocks does round 1 hold now? 2. Remove `arena.Reset()` and watch `BytesUsed` and `BlockCount` grow from round to round. 3. In `Main`, allocate two blocks in a row through `allocator`. Release the *first* and print `BytesUsed`, then release the second and print it again. Which release made a difference, and why? ## Learn more - [Allocator](https://rux-lang.dev/docs/learn/allocator) — the interface the handle implements - [Fixed buffer](https://rux-lang.dev/docs/learn/fixed-buffer) — the same idea over storage you already have - [Pool](https://rux-lang.dev/docs/learn/pool) — for pieces that come and go in no particular order # Fixed buffer ::note **You'll need**: [Allocator](https://rux-lang.dev/docs/learn/allocator), [Arena](https://rux-lang.dev/docs/learn/arena), [Outcome](https://rux-lang.dev/docs/learn/outcome), [Loop](https://rux-lang.dev/docs/learn/loop) :: Every allocator so far could, in the end, ask the operating system for more. Sometimes that is exactly what you must not do: on a small device with no system allocator at all, in code that has to run within a fixed budget, or when one part of a program must never be able to use up memory the rest needs. A `FixedBuffer` is the allocator for those places. It hands out memory you already have, and when that runs out, it says no. ## Storage you already own Here the storage is a 64-byte array on the stack. The buffer is built over its first byte and its size: ```rux var storage: byte[64]; var buffer = FixedBuffer(@storage[0] as *var opaque, 64); var handle = buffer.Handle(); let allocator: Allocator = handle; ``` Like an arena, the buffer hands that memory out piece by piece from a moving marker, and is used through a `Handle()` that implements `Allocator`. Unlike an arena, it never takes a new block from anyone. The storage belongs to you, not to the buffer. It must outlive the buffer and everything handed out of it — here all three live in `Main`, so that holds. ## Asking until it says no A `Point` is two `int64`s, 16 bytes, so four fit in 64 bytes. The loop keeps asking and stops at the first refusal: ```rux match allocator.Allocate(layout) { .Success(block) => { made += 1; let point = block as *var Point; *point = Point { x: made, y: made * made }; PrintLine("point {} at ({}, {}), {} bytes left", made, point.x, point.y, buffer.BytesRemaining()); }, .Failure(error) => { let full = error == AllocError::OutOfMemory; PrintLine("point {} refused, out of memory: {}", made + 1, full); break; } } ``` This time the failure is not passed on with `?`. It is the expected way out of the loop, so a `match` takes it apart directly, as in [Outcome](https://rux-lang.dev/docs/learn/outcome). Code written against `Allocator` cannot tell a fixed buffer from any other allocator — it just sees a refusal sooner. ## Reset As with an arena, `Reset` makes the whole buffer available again, and invalidates every address it gave out before: ```rux buffer.Reset(); ``` The next request then starts at the front of `storage` again, which the last line of the output confirms. ## Three allocators side by side | | `SystemAllocator` | `Arena` | `FixedBuffer` | | ------------------------- | -------------------- | ------------------------------- | ---------------------------- | | Memory comes from | the operating system | blocks from a backing allocator | storage you pass in | | When it runs out | the system refuses | it takes a bigger block | `OutOfMemory` | | `Deallocate` of one block | gives it back | rewinds only the most recent | rewinds only the most recent | | Everything at once | — | `Reset`, and the destructor | `Reset` | ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Memory/FixedBuffer){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // A `FixedBuffer` is an allocator over memory you already have: here, a 64-byte array on the // stack. It hands that memory out piece by piece, like an arena, but it never asks anyone for // more. When the buffer is full, `Allocate` fails with `AllocError::OutOfMemory`. // // That makes it the allocator for places where real allocation is not allowed or not // available, and a way to put a hard limit on how much some piece of code may use. Code // written against `Allocator` does not know the difference; it just sees a refusal sooner. // // The storage belongs to you, not to the buffer, so it must outlive the buffer and everything // handed out of it. As with an arena, `Reset` makes the whole buffer available again and // invalidates every address it gave out before. import Allocator::{ AllocError, Allocator, FixedBuffer, Layout }; import Io::PrintLine; struct Point { x: int64; y: int64; } func Main() -> ! AllocError { var storage: byte[64]; var buffer = FixedBuffer(@storage[0] as *var opaque, 64); var handle = buffer.Handle(); let allocator: Allocator = handle; // Each point needs 16 bytes, so four fit. let layout = Layout::ForValue(); var made: int64 = 0; loop { match allocator.Allocate(layout) { .Success(block) => { made += 1; let point = block as *var Point; *point = Point { x: made, y: made * made }; PrintLine("point {} at ({}, {}), {} bytes left", made, point.x, point.y, buffer.BytesRemaining()); }, .Failure(error) => { let full = error == AllocError::OutOfMemory; PrintLine("point {} refused, out of memory: {}", made + 1, full); break; } } } // After a reset the next request starts again at the front of `storage`. buffer.Reset(); PrintLine("after reset, {} bytes left", buffer.BytesRemaining()); let again = allocator.Allocate(layout)?; PrintLine("starts at storage[0]: {}", (again as uint) == (@storage[0] as uint)); } ``` Besides `Io`, its `Rux.toml` lists `Allocator` under `[Dependencies]`. ## Run it ```sh cd Examples/Memory/FixedBuffer rux run ``` ```text point 1 at (1, 1), 48 bytes left point 2 at (2, 4), 32 bytes left point 3 at (3, 9), 16 bytes left point 4 at (4, 16), 0 bytes left point 5 refused, out of memory: true after reset, 64 bytes left starts at storage[0]: true ``` ## Common mistakes ::mistake **Storage that dies before the buffer.**:br If the array lives in a function that returns while the buffer, or anything allocated from it, is still in use, every address points into a stack frame that no longer exists. Nothing reports it. Declare the storage where it outlives everything that uses it. :: ::mistake **A capacity that does not match the storage.**:br The buffer believes the number you give it. `FixedBuffer(@storage[0] as *var opaque, 128)` over a 64-byte array compiles, and happily hands out the 64 bytes that come after it. Use `sizeof` of the storage rather than typing the number twice. :: ::mistake **Expecting every byte of `BytesRemaining` to be usable.**:br Each request is aligned first. With 63 bytes remaining after a one-byte request, a 63-byte request at alignment 8 is still refused with `OutOfMemory`: aligning it would push it past the end. :: ## Try it yourself 1. Make `storage` 100 bytes, and pass `sizeof(byte[100])` as the capacity. How many points fit, and how many bytes are left over? 2. Before the loop, allocate one `int32` with `Layout::ForValue()`. How many points fit now, and where did the rest of the bytes go? 3. Move the loop into `func CountPoints(allocator: Allocator) -> int64` and call it with the fixed buffer's handle. The function never learns which allocator it was given. ## Learn more - [Arena](https://rux-lang.dev/docs/learn/arena) — the same marker-based approach, with room to grow - [Outcome](https://rux-lang.dev/docs/learn/outcome) — matching `.Success` and `.Failure` directly - [Allocator](https://rux-lang.dev/docs/learn/allocator) — `AllocError` and what each case means # Pool ::note **You'll need**: [Allocator](https://rux-lang.dev/docs/learn/allocator), [Arena](https://rux-lang.dev/docs/learn/arena), [Absence to error](https://rux-lang.dev/docs/learn/absence-to-error), [Fallible main](https://rux-lang.dev/docs/learn/fallible-main) :: An arena suits values that all end together. A **pool** suits the opposite shape: many small values that come and go in no particular order — the nodes of a list, the entries of a table, the bullets in a game. Each one is released on its own, and the very next request of that size gets the released block straight back. ## Blocks of a few fixed sizes A pool cuts large chunks of memory into equal blocks and keeps the free ones on a list. To keep that fast, it only serves a handful of block sizes, called *classes*, and rounds every request up to the nearest one: ```rux PrintLine("block sizes: {} {} {} {} {}", pool.ClassSize(0), pool.ClassSize(1), pool.ClassSize(2), pool.ClassSize(3), pool.ClassSize(4)); let odd = Layout::New(20, 8) ?? fail AllocError::Unsupported; PrintLine("a 20-byte request uses a {}-byte block", pool.ClassSize(ClassIndexFor(odd))); ``` | Request | Block it takes | Unused bytes | | ------------- | ----------------------------------------------- | ------------ | | 1–16 bytes | 16 | up to 15 | | 17–32 bytes | 32 | up to 15 | | 33–64 bytes | 64 | up to 31 | | 65–128 bytes | 128 | up to 63 | | 129–256 bytes | 256 | up to 127 | | more than 256 | none — passed straight to the backing allocator | — | Rounding is the price of speed. A 20-byte request takes a 32-byte block, and the other 12 bytes sit unused until that block comes back. `Layout::New(size, alignment)`, used for `odd`, builds a layout from two plain numbers; it is `none` when the pair cannot be a layout, such as an alignment that is not a power of two. ## Taking and returning blocks The pool is created over a backing allocator with the number of blocks per chunk, and used through its handle like every allocator in this part: ```rux var pool = Pool(backing, 8); var handle = pool.Handle(); let allocator: Allocator = handle; ``` Three 16-byte points come out of the first chunk, and the middle one goes back first: ```rux let first = allocator.Allocate(layout)?; let second = allocator.Allocate(layout)?; let third = allocator.Allocate(layout)?; PrintLine("three out: {} live blocks, {} chunk", pool.LiveBlocks(), pool.ChunkCount()); allocator.Deallocate(second, layout)?; ``` ```mermaid flowchart LR chunk["a chunk from the
backing allocator"] -- "cut into
8 blocks" --> list[("free list
16-byte class")] list -- "`Allocate`
takes one" --> use["in use"] use -- "`Deallocate`
puts it back" --> list ``` ## The next request reuses the block A released block goes straight back on the free list of its class, so the next request of that size gets that very block: ```rux let fourth = allocator.Allocate(layout)?; PrintLine("fourth reuses the second's block: {}", fourth == second); ``` No search, no new chunk — a handful of instructions. When every block is back, `LiveBlocks` is 0, but the chunk stays: it is ready for the next requests, and goes back to the backing allocator only when the pool is destroyed. ## Arena or pool? | | Arena | Pool | | ------------------- | --------------------------------------- | ----------------------------- | | Values end | all together | one by one, in any order | | Releasing one value | does nothing (unless it was the latest) | puts its block back for reuse | | You must release | nothing — `Reset` takes it all | every block, with its layout | | Wasted space | only padding for alignment | the rounding up to a class | ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Memory/Pool){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // A pool suits many small values that come and go in no particular order: the opposite of an // arena, where everything ends together. It cuts large chunks into equal blocks and keeps the // free ones on a list. Allocating takes a block off the list, and releasing puts it straight // back, ready for the next request of that size. // // Requests are rounded up to a few fixed block sizes, called classes: 16, 32, 64, 128 and 256 // bytes. Rounding is the price of speed. A 20-byte request takes a 32-byte block, and the other // 12 bytes sit unused until that block comes back. // // Unlike an arena, a pool expects each block back: `Deallocate` with the same layout, through // the pool it came from. The chunks themselves go back to the backing allocator when the pool // is destroyed. import Allocator::{ AllocError, Allocator, ClassIndexFor, Layout, Pool, SystemAllocator }; import Io::PrintLine; struct Point { x: int64; y: int64; } func Main() -> ! AllocError { var system = SystemAllocator(); let backing: Allocator = system; // Each chunk is cut into eight blocks. var pool = Pool(backing, 8); var handle = pool.Handle(); let allocator: Allocator = handle; PrintLine("block sizes: {} {} {} {} {}", pool.ClassSize(0), pool.ClassSize(1), pool.ClassSize(2), pool.ClassSize(3), pool.ClassSize(4)); let odd = Layout::New(20, 8) ?? fail AllocError::Unsupported; PrintLine("a 20-byte request uses a {}-byte block", pool.ClassSize(ClassIndexFor(odd))); // Three 16-byte points, all out of the first chunk. let layout = Layout::ForValue(); let first = allocator.Allocate(layout)?; let second = allocator.Allocate(layout)?; let third = allocator.Allocate(layout)?; PrintLine("three out: {} live blocks, {} chunk", pool.LiveBlocks(), pool.ChunkCount()); // Blocks can come back in any order. The middle one goes first. allocator.Deallocate(second, layout)?; PrintLine("one back: {} live blocks", pool.LiveBlocks()); // The next request of the same size gets that very block back. let fourth = allocator.Allocate(layout)?; PrintLine("fourth reuses the second's block: {}", fourth == second); allocator.Deallocate(first, layout)?; allocator.Deallocate(third, layout)?; allocator.Deallocate(fourth, layout)?; // Every block is back, and the chunk stays for the next requests. PrintLine("all back: {} live blocks, {} chunk", pool.LiveBlocks(), pool.ChunkCount()); } ``` Besides `Io`, its `Rux.toml` lists `Allocator` under `[Dependencies]`. ## Run it ```sh cd Examples/Memory/Pool rux run ``` ```text block sizes: 16 32 64 128 256 a 20-byte request uses a 32-byte block three out: 3 live blocks, 1 chunk one back: 2 live blocks fourth reuses the second's block: true all back: 0 live blocks, 1 chunk ``` ## Common mistakes ::mistake **Releasing with a different layout.**:br The pool works out a block's class from the layout alone, so it cannot tell when the layout is wrong. Release a 16-byte point with the 20-byte `odd` layout and the call succeeds — and the block lands on the 32-byte list, where the next 20-byte request receives a block that is only 16 bytes long. Always release with the layout you allocated with. :: ::mistake **Forgetting to release.**:br A pool expects each block back. A block never released stays counted in `LiveBlocks` and cannot be reused; its memory only returns when the whole pool is destroyed. :: ::mistake **Using a block after releasing it.**:br As `fourth == second` shows, a released block is handed out again at the very next request. Anything still writing through the old pointer now writes into someone else's value. :: ## Try it yourself 1. Allocate nine points instead of three, with eight blocks per chunk. What does `ChunkCount` say now? 2. Ask `ClassIndexFor` about a 300-byte layout. It returns 5, one past the last class — what does that mean for where the memory comes from? 3. Release `first` and `third` before allocating `fourth`. Which of the two does `fourth` reuse? ## Learn more - [Arena](https://rux-lang.dev/docs/learn/arena) — the opposite trade: nothing released one by one - [Allocator](https://rux-lang.dev/docs/learn/allocator) — the `Deallocate` contract every allocator shares - [Part 17: Collections](https://rux-lang.dev/docs/learn/collections) — containers that take an `Allocator` and allocate as they grow # Zeroize ::note **You'll need**: [Raw memory](https://rux-lang.dev/docs/learn/raw-memory), [Pointer](https://rux-lang.dev/docs/learn/pointer), [Layout](https://rux-lang.dev/docs/learn/layout), [Copy](https://rux-lang.dev/docs/learn/copy) :: When a program is done with a secret — a password, a key, a PIN — it should wipe the memory that held it. Otherwise the secret can turn up later where nobody expected it: in a crash dump, or in memory that is reused by some other part of the program. This last lesson of the part shows the one tool for the job, and why the obvious tool is not it. ## Why an ordinary clear can vanish An optimizing compiler looks for work whose result nobody uses, and deletes it. Writing zeros into an array that is never read again is exactly such work. So a clear at the end of a function — with `Zero` from [Raw memory](https://rux-lang.dev/docs/learn/raw-memory), or with a loop — may simply not be there in the optimized program, while the secret stays in memory. `Zeroize`, from `Core`, is the version the compiler promises to keep, however unread the bytes are afterwards: | Function | Clears the bytes | May the optimizer remove it? | Use it for | | -------------------------- | ---------------- | ---------------------------- | ---------------------------- | | `Zero(p, n)` | yes | yes, if nothing reads them | making fresh memory definite | | `Zeroize(address, length)` | yes | never | wiping secrets | ## Wiping the PIN `Zeroize` takes a `*var uint8` — the address of the first byte — and how many bytes to clear: ```rux Zeroize(@pin[0], sizeof(uint8[4])); ``` `sizeof(uint8[4])` is the size of the whole array, so all four bytes go. After the call, the PIN prints as zeros. ## A copy is not wiped `Zeroize` clears the bytes it is given and nothing else. The program makes a careless copy before the wipe: ```rux let copy = pin; ``` An array is copied by value, so `copy` is separate storage with its own four bytes, and it still holds `4 7 1 9` after the wipe. The same goes for any copy the program made along the way — passed by value, returned, stored in a struct. So keep a secret in one place from the start, pass it on as a view such as `pin[..]` rather than as a copy, and wipe that one place when you are done. ```mermaid flowchart LR arrive["the secret arrives
in one place"] --> d["`defer Zeroize(…)`"] d --> use["use it through views"] use --> wipe["leaving the function:
the bytes are cleared"] arrive -. "a copy made
along the way" .-> copy["never wiped"] ``` ## Wipe with `defer` A wipe that is skipped on an early `return` does not help, so register it with [defer](https://rux-lang.dev/docs/learn/defer) right after the secret arrives. A secret that is not stored as bytes needs its address cast to `*var uint8`: ```rux var key: uint32[4] = [1, 2, 3, 4]; defer Zeroize(@key[0] as *var uint8, sizeof(uint32[4])); ``` Whatever path the function leaves by, the key is cleared on the way out. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Memory/Zeroize){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // When a program is done with a secret, such as a password, a key or a PIN, it should wipe the // memory that held it, so the secret cannot turn up later in a crash dump or in memory that is // reused by something else. // // The surprise is that an ordinary clear may not happen. Writing zeros that nothing reads // afterwards looks pointless to an optimizing compiler, and it is allowed to delete such writes. // `Zero` from the RawMemory lesson is exactly that kind of write. `Zeroize(address, length)` // is the version the compiler promises to keep, however unread the bytes are afterwards. // // It clears the bytes it is given and nothing else. A copy made earlier still holds the secret, // so keep a secret in one place from the start, and wipe that place when you are done. A // `defer` right after the secret arrives is a good way to make sure the wipe always happens. import Core::Zeroize; import Io::{ Print, PrintLine }; func Show(label: char8[..], bytes: uint8[..]) { Print("{}", label); for value in bytes { Print(" {}", value); } PrintLine(); } func Matches(entered: uint8[..], secret: uint8[..]) -> bool { for i in 0..secret.length { if entered[i] != secret[i] { return false; } } return true; } func Main() -> int { var pin: uint8[4] = [4, 7, 1, 9]; let entered: uint8[4] = [4, 7, 1, 9]; PrintLine("pin accepted: {}", Matches(entered[..], pin[..])); // A careless copy, made before the wipe. It is separate storage with its own bytes. let copy = pin; // Done with the PIN: wipe its four bytes, starting at the address of the first one. Zeroize(@pin[0], sizeof(uint8[4])); Show("pin after Zeroize:", pin[..]); Show("the earlier copy: ", copy[..]); return 0; } ``` Besides `Io`, its `Rux.toml` lists `Core` under `[Dependencies]`. ## Run it ```sh cd Examples/Memory/Zeroize rux run ``` ```text pin accepted: true pin after Zeroize: 0 0 0 0 the earlier copy: 4 7 1 9 ``` ## Common mistakes ::mistake **Wiping a secret with `Zero`.**:br It looks the same in the source, and in an optimized build it may not happen at all. For secrets, always `Zeroize`. :: ::mistake **A secret held in a `let`.**:br`let pin: uint8[4] = …` makes `@pin[0]` a read-only `*uint8`, and `Zeroize(@pin[0], …)` fails with: ```text error: argument 1 to 'Zeroize' has type '*uint8', but parameter 'memory' requires '*var uint8' ``` A secret you will wipe must be a `var`. :: ::mistake **A secret that is not bytes.**:br For `var key: uint32[4]`, `Zeroize(@key[0], …)` fails with: ```text error: argument 1 to 'Zeroize' has type '*var uint32', but parameter 'memory' requires '*var uint8' ``` Cast the address, `@key[0] as *var uint8`, and give the length in bytes. :: ::mistake **The wrong length.**:br`Zeroize(@pin[0], sizeof(uint8))` clears one byte and leaves `7 1 9` behind. Measure the whole storage: `sizeof(uint8[4])`. :: ## Try it yourself 1. Wipe `copy` as well, and check that both lines print zeros. What did you have to change about `copy` first? 2. Replace the `Zeroize` call with a `defer Zeroize(…)` placed right after `pin` is declared. What does the `pin after Zeroize` line print now, and why? 3. Write `func Check(entered: uint8[..]) -> bool` that keeps the stored PIN in its own `var` array, registers a `defer Zeroize(…)` for it straight away, and returns `Matches(entered, pin[..])`. ## Learn more - [Raw memory](https://rux-lang.dev/docs/learn/raw-memory) — `Zero`, and where clearing memory first came up - [Copy](https://rux-lang.dev/docs/learn/copy) — when a value is copied, and so when a secret can multiply - [Defer](https://rux-lang.dev/docs/learn/defer) — making the wipe happen on every path out # Rc ::note **You'll need**: [Box](https://rux-lang.dev/docs/learn/box), [Custom copy](https://rux-lang.dev/docs/learn/custom-copy), [Optional pointer](https://rux-lang.dev/docs/learn/optional-pointer) :: A [`Box`](https://rux-lang.dev/docs/learn/box) knows when to free its value because it is the value's only owner. Some values have no single owner. An editor's colour theme is used by every open window; a loaded image may be shown in three places. The memory should go when the last user is done with it — and no one user knows whether it is the last. `Rc` — a **reference-counted** handle — answers that by counting: ```rux import Allocator::{ AllocError, Allocator, Rc, SystemAllocator }; ``` ## Creating and copying handles `Rc::Create(allocator, value)` moves the value into allocated memory beside a count, which starts at one, and returns the first handle. Like `Box::Create`, it can fail, so it returns `Rc ! AllocError`: ```rux var theme = Rc::Create(allocator, Theme { name: "paper", size: 11 })?; ``` Copying a handle does **not** copy the value. `Rc` has a [custom copy](https://rux-lang.dev/docs/learn/custom-copy) operator that adds one to the count, and the new handle reaches the same value. So every window below holds a handle to the theme, not a theme of its own: ```rux struct Window { title: char8[..]; theme: Rc; } ``` ```mermaid flowchart LR m["`theme` in `Main`"] --> v["the paper theme
count: 4"] p["`theme` parameter"] --> v e["`editor.theme`"] --> v w["`preview.theme`"] --> v ``` `Count()` reads the count. Passing a handle by value — or a struct that holds one — copies it too, which is why `Draw` sees five handles while the call lasts. ## The last handle frees the value When a handle's life ends, the count goes down by one. The handle that takes it to zero destroys the value — running its destructor — and gives the memory back. In the program, every handle made in `OpenWindows` ends with the call, and the count returns to one: | Moment | Handles to the paper theme | | -------------------------------------- | -------------------------- | | after `Rc::Create` | 1 | | inside `OpenWindows`, two windows made | 4 | | inside `Draw` | 5 | | `OpenWindows` returned | 1 | | `Main` ends | 0 — `~Theme` runs | Nothing in the program says when to free the theme. `the paper theme is destroyed` is printed after `end of Main:` because `Main`'s handle was the last. ## Reading and writing `Get()` returns a `*T`, a read-only pointer, valid while any handle exists. A shared value is read by everybody, and a change made through one handle would surprise all the others, so there is no way to write through `Get()`. `GetMutable()` returns `(*var T)?` — a writable pointer while this handle is the only one, and `none` while the value is shared: ```rux match theme.GetMutable() { value? => value.size = 12, none => PrintLine("shared, so read-only") } ``` Right after `Create` there is one handle, so the program may set the size. Inside `OpenWindows` the same call answers `none`. A value that must change while it is shared needs a different design: build a new value and replace the handle, or keep the changing part outside the shared one. ## Same value, or equal value `SameAs` asks whether two handles reach the **same** value, not whether two values are equal: ```rux let lookalike = Rc::Create(allocator, Theme { name: "lookalike", size: 12 })?; PrintLine(" editor and preview share: {}", editor.theme.SameAs(preview.theme)); PrintLine(" lookalike is shared: {}", lookalike.SameAs(theme)); ``` The lookalike is a separate value with its own count of one, so it is destroyed as soon as its only handle goes, at the end of `OpenWindows`. ::note **One thread only.**:br An `Rc` keeps its count with plain arithmetic, which is fast but not safe when two threads change it at once. To share a value between threads, the Allocator package has a twin, `Arc`, which counts atomically. It comes with [Arc](https://rux-lang.dev/docs/learn/arc) in Part 25. :: ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Memory/Rc){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // A `Box` has exactly one owner, which is what lets it know when to free its value. Some values // have no single owner, though: one theme used by every window of an editor, one loaded image // shown in several places. Whichever user goes last should free it, and none of them knows // which one that is. // // `Rc`, a reference-counted handle, settles it by counting. `Rc::Create` moves the value into // allocated memory with a count of one. Copying a handle does not copy the value: it adds one // to the count, and both handles reach the same value. When a handle's life ends the count goes // down by one, and the handle that takes it to zero destroys the value and frees the memory. // // Shared values are read-only. `Get()` returns a `*T` for reading. `GetMutable()` returns a // `*var T` only while a single handle exists, since a change made through one handle would // otherwise surprise the others; while the value is shared it returns `none`. // // An `Rc` counts with plain arithmetic, so its handles must all stay on one thread. Its twin, // `Arc`, counts atomically for values shared between threads; it comes with the Threads part. import Allocator::{ AllocError, Allocator, Rc, SystemAllocator }; import Io::PrintLine; struct Theme { name: char8[..]; size: int32; } extend Theme { func ~Theme(self: &var Theme) { PrintLine(" the {} theme is destroyed", self.name); } } // Every window holds a handle to its theme, not a copy of it. struct Window { title: char8[..]; theme: Rc; } // The window arrives by value, so for the length of the call there is one more handle. func Draw(window: Window) { let theme = window.theme.Get(); PrintLine(" {} in {} at {}pt, {} handles", window.title, theme.name, theme.size, window.theme.Count()); } func OpenWindows(theme: Rc, allocator: Allocator) -> ! AllocError { // Two more handles: the count is now one for `Main`, one for this parameter and one each // for the windows. let editor = Window { title: "editor", theme: theme }; let preview = Window { title: "preview", theme: theme }; PrintLine(" {} handles", theme.Count()); Draw(editor); // `GetMutable` needs a `var` handle, so take one more copy. Even so, the answer is `none`: // while the value is shared, nobody may write to it. var mine = theme; PrintLine(" can write: {}", mine.GetMutable() != none); // `SameAs` asks whether two handles reach one value, not whether two values are equal. A // second theme with the same fields is still a different value, with its own count. let lookalike = Rc::Create(allocator, Theme { name: "lookalike", size: 12 })?; PrintLine(" editor and preview share: {}", editor.theme.SameAs(preview.theme)); PrintLine(" lookalike is shared: {}", lookalike.SameAs(theme)); // Every handle made here ends with the call. The lookalike was the only handle to its // value, so that value is destroyed now; the paper theme still has `Main`'s handle. } func Main() -> ! AllocError { var system = SystemAllocator(); let allocator: Allocator = system; var theme = Rc::Create(allocator, Theme { name: "paper", size: 11 })?; PrintLine("created, {} handle", theme.Count()); // A lone handle may write. `GetMutable` returns `(*var Theme)?`, a pointer or `none`. match theme.GetMutable() { value? => value.size = 12, none => PrintLine("shared, so read-only") } // `Get()` gives only a `*Theme`, so writing through it is refused: // // error: cannot modify data through read-only pointer '*Theme' PrintLine("opening windows:"); OpenWindows(theme, allocator)?; PrintLine("windows closed, {} handle", theme.Count()); // `theme` is the last handle, so the value is destroyed when `Main` ends, and only then. PrintLine("end of Main:"); } ``` Besides `Io`, its `Rux.toml` lists `Allocator` under `[Dependencies]`. ## Run it ```sh cd Examples/Memory/Rc rux run ``` ```text created, 1 handle opening windows: 4 handles editor in paper at 12pt, 5 handles can write: false editor and preview share: true lookalike is shared: false the lookalike theme is destroyed windows closed, 1 handle end of Main: the paper theme is destroyed ``` ## Common mistakes ::mistake **Writing through `Get`.**:br`theme.Get().size = 13;` fails with: ```text error: cannot modify data through read-only pointer '*Theme' ``` Shared values are read-only. Write through `GetMutable()` while the handle is the only one. :: ::mistake **Expecting `GetMutable` to work on a shared value.**:br`GetMutable()` answers `none` whenever another handle exists — including a copy you made a moment ago, or one a struct is holding. Handle the `none`; do not assume the pointer is there. :: ::mistake **Calling `GetMutable` on a `let` handle.**:br`GetMutable` takes the handle as `&var`. With `let t = theme;` the call fails with: ```text error: cannot call 'GetMutable' on immutable 't' ``` Declare the handle with `var`. :: ::mistake **Reaching for the fields directly.**:br`theme.size` fails with: ```text error: struct 'Rc' has no field 'size' ``` The handle is not the value. Go through `theme.Get().size`. :: ::mistake **Forgetting the `?`.**:br`let plain: Rc = Rc::Create(…);` fails with: ```text error: cannot assign 'Rc ! AllocError' to 'Rc' ``` Creating the value can run out of memory. Handle the `AllocError` first. :: ## Try it yourself 1. Print `theme.Count()` inside `Draw` before and after `let copy = window.theme;`. How much does one more `let` add? 2. In `Main`, after `OpenWindows`, try `GetMutable` again and set the size to 14. Does it work now, and why? 3. Make the lookalike a second handle to `theme` instead of a new value. What does `SameAs` say, and what happens to the `the lookalike theme is destroyed` line? 4. Give `Window` a destructor that prints its title, and watch the order in which windows and themes go. ## Learn more - [Box](https://rux-lang.dev/docs/learn/box) — one owner, no counting - [Custom copy](https://rux-lang.dev/docs/learn/custom-copy) — the copy operator that does the counting - [Arc](https://rux-lang.dev/docs/learn/arc) — the same handle, safe to share between threads - [Allocator](https://rux-lang.dev/docs/api/allocator) in the API reference - [Copy and move](https://rux-lang.dev/docs/lang/ownership/copy-and-move) and [Destructors](https://rux-lang.dev/docs/lang/ownership/destructors) in the Rux Reference # Part 16: Numbers Part 1 introduced the number types; this part takes them apart. You will count past 64 bits, ask any type for its limits, meet the float values that are not numbers at all, and work on integers one bit at a time. Above all, you will learn what happens at the edges — when a result does not fit — and how to choose, on purpose, between reporting it, wrapping round and stopping at the limit. ## What you will learn - The wide integers `int128` to `uint512`, and the constants every number type carries: `Min`, `Max`, `Bits`, `Epsilon` and the rest. - Infinity and NaN — where they come from, and why `NaN == NaN` is `false`. - Working with bits: `& | ^ ~`, the shifts `<<`, `>>` and `>>>`, and `Core`'s counting and rotating functions. - Overflow handled on purpose: checked, wrapping and saturating arithmetic, and conversions that report a value that does not fit. - Writing a number's bytes in a chosen order, for files and network protocols. - Roots, powers, logarithms, trigonometry and the four kinds of rounding from the `Math` package. - Complex numbers with `Complex`: their arithmetic, their length and angle, and the roots of a quadratic that has no real ones. ## The part at a glance ```mermaid flowchart LR n(["Numbers"]) --> i["Integers"] n --> f["Floats"] i --> range["How big?
Wide integer, Number limit"] i --> bits["Bit by bit
Bitwise, Shift,
Bit operation, Endian"] i --> edge["When it does not fit
Checked arithmetic,
Wrapping arithmetic,
Checked convert"] f --> flimit["Limits and precision
Number limit"] f --> special["Beyond the limits
Float special"] f --> math["Functions
Math"] f --> complex["Beyond the real line
Complex"] ``` ## Lessons | | Lesson | What you will learn | | ----- | -------------------------------------------------------------------------- | ---------------------------------------------------------------- | | 16.1 | [Wide integer](https://rux-lang.dev/docs/learn/wide-integer) | 128-, 256- and 512-bit integers | | 16.2 | [Number limit](https://rux-lang.dev/docs/learn/number-limit) | the smallest and largest value each number type can hold | | 16.3 | [Float special](https://rux-lang.dev/docs/learn/float-special) | infinity and NaN, and how they compare | | 16.4 | [Bitwise](https://rux-lang.dev/docs/learn/bitwise) | `&`, `|`, `^` and `~`: set, clear, flip and test bits with masks | | 16.5 | [Shift](https://rux-lang.dev/docs/learn/shift) | move bits left and right with `<<`, `>>` and `>>>` | | 16.6 | [Checked arithmetic](https://rux-lang.dev/docs/learn/checked-arithmetic) | detect overflow instead of getting a wrong answer | | 16.7 | [Wrapping arithmetic](https://rux-lang.dev/docs/learn/wrapping-arithmetic) | arithmetic that wraps around or saturates on purpose | | 16.8 | [Checked convert](https://rux-lang.dev/docs/learn/checked-convert) | convert between number types and detect values that do not fit | | 16.9 | [Bit operation](https://rux-lang.dev/docs/learn/bit-operation) | count, find and rotate bits | | 16.10 | [Endian](https://rux-lang.dev/docs/learn/endian) | write a number's bytes in a chosen byte order | | 16.11 | [Math](https://rux-lang.dev/docs/learn/math) | roots, powers, logarithms, trigonometry, and rounding | | 16.12 | [Complex](https://rux-lang.dev/docs/learn/complex) | complex numbers: arithmetic, magnitude and polar form | ## Before you start This part draws on almost everything before it. Lessons hand back answers through [out-parameters](https://rux-lang.dev/docs/learn/out-parameter) and [pointers](https://rux-lang.dev/docs/learn/pointer) from [Part 15: Memory](https://rux-lang.dev/docs/learn/memory), report results as [optionals](https://rux-lang.dev/docs/learn/optionals) from Part 8, and use the [generic](https://rux-lang.dev/docs/learn/generic) functions of `Core`. Each lesson's package is in the Examples repository's `Numbers/` folder: ```sh cd Examples/Numbers/WideInteger rux run ``` ## After this part [Part 17: Collections](https://rux-lang.dev/docs/learn/collections) moves from single values to containers of them — vectors, maps, sets and queues. Before moving on, try the checkpoint projects [Circle](https://rux-lang.dev/docs/learn/circle) and [Quadratic](https://rux-lang.dev/docs/learn/quadratic): both put the `Math` package to work and have to deal with the special values a float calculation can produce. Quadratic works out a complex pair of roots by hand, the job [Complex](https://rux-lang.dev/docs/learn/complex) hands to the `Complex` type. For the rules behind this part, see [Arithmetic](https://rux-lang.dev/docs/lang/expressions/arithmetic), [Bitwise](https://rux-lang.dev/docs/lang/expressions/bitwise) and [Shift](https://rux-lang.dev/docs/lang/expressions/shift) operations, [Type casts](https://rux-lang.dev/docs/lang/expressions/casts) and the [primitive types](https://rux-lang.dev/docs/lang/appendix/primitives) in the Rux Reference, and the [Math API](https://rux-lang.dev/docs/api/math). # Wide integer ::note **You'll need**: [Integer](https://rux-lang.dev/docs/learn/integer), [Literal](https://rux-lang.dev/docs/learn/literal), [Convert](https://rux-lang.dev/docs/learn/convert), [For](https://rux-lang.dev/docs/learn/for) :: Sixty-four bits go a long way — about eighteen quintillion — but not all the way. A factorial outgrows them by 21!, a 128-bit identifier needs twice the room, and the arithmetic inside cryptography works on numbers hundreds of bits long. For those, Rux has integers wider than any machine register: `int128`, `int256` and `int512`, and their unsigned twins `uint128`, `uint256` and `uint512`. The compiler spreads each wide integer over several machine words and carries between them, so a wide integer is slower than an `int64` — but every bit as exact. Everything else you know about integers still holds. ## Six more widths | Type | Bytes | Largest value, roughly | Digits | | --------- | ----- | ---------------------- | ------ | | `int64` | 8 | 9.2 × 10¹⁸ | 19 | | `int128` | 16 | 1.7 × 10³⁸ | 39 | | `uint128` | 16 | 3.4 × 10³⁸ | 39 | | `int256` | 32 | 5.8 × 10⁷⁶ | 77 | | `uint256` | 32 | 1.2 × 10⁷⁷ | 78 | | `int512` | 64 | 6.7 × 10¹⁵³ | 154 | | `uint512` | 64 | 1.3 × 10¹⁵⁴ | 155 | The signed types reach as far below zero as above it, plus one, exactly like `int8` or `int32`. The limits come from `Core`, the same `Min` and `Max` you use for any other integer — the program imports each type it asks about: ```rux import Core::{ int128, int256, int64, uint128, uint256, uint512, uint64 }; ``` ## Wide literals 2⁶⁴ is one more than the largest `uint64`, so it needs a wider home. Give the binding a wide type and the literal takes it: ```rux let next: uint128 = 18446744073709551616; ``` Hex digits and `_` separators work at any width, exactly as they do for narrow integers: ```rux let avogadro: uint128 = 602214076000000000000000; let mask: uint128 = 0xFFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF; ``` Thirty-two `F`s are 128 set bits, so `mask == uint128::Max` prints `true`. ## Counting past 64 bits A `uint64` can hold 20! but not 21!. A `uint128` reaches 34!: ```rux var factorial: uint128 = 1; let first: uint128 = 1; for n in first..=34 { factorial *= n; } ``` The range starts at a `uint128`, so `n` counts in `uint128` as well, and `factorial *= n` multiplies two values of the same type. Had the range been the plain `1..=34`, `n` would be an `int`, and the multiplication would be refused. Every doubling of the width squares the range. The same loop over an `int256` gets as far as 57!, a 77-digit number, and an `int512` would reach 97!: ```rux var big: int256 = 1; let one: int256 = 1; for n in one..=57 { big *= n; } ``` A shift needs the same care. The **left** side of a shift decides its type, so the width goes on the literal there, as a suffix: ```rux let power = 1u256 << 200; ``` A plain `1 << 200` is an `int`, which has no bit 200 — it quietly prints `256` instead of a 61-digit number. ## Widening and narrowing Wide integers follow the conversion rules of [Convert](https://rux-lang.dev/docs/learn/convert). Widening loses nothing, so it needs nothing written; an unsuffixed literal grows to the width of the value beside it: ```rux let balance: int64 = -42; let wide: int128 = balance; let large = wide * 1_000_000_000_000_000_000_000; ``` `1_000_000_000_000_000_000_000` is far too large for an `int64`, but it sits next to `wide`, so it is an `int128` and the product is exact: −42 × 10²¹. Narrowing can lose bits, so it is never silent. You ask for it with `as`, which keeps the low 64 bits — whatever they happen to mean: ```rux PrintLine("narrowed {}", large as int64); ``` −42 × 10²¹ does not fit in 64 bits, and what is left is the unrelated `3236255836649029632`. ```mermaid flowchart LR narrow["`int64`"] -- "silently" --> wide["`int128`"] wide -- "only with `as`:
keeps the low 64 bits" --> narrow ``` ## The edges One past the maximum wraps to the minimum, as it does for every other integer: ```rux PrintLine("max + 1 {}", int128::Max + 1); ``` A wider type moves the edge further away; it does not remove it. [Checked arithmetic](https://rux-lang.dev/docs/learn/checked-arithmetic) shows how to find out when you cross it. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Numbers/WideInteger){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // `int128`, `int256` and `int512`, and their unsigned twins `uint128` to `uint512`, are integers // wider than any machine register. The compiler spreads each one over several machine words and // carries between them, so a wide integer is slower than an `int64` but every bit as exact. Use // one when a number really can outgrow 64 bits: a large factorial, a 128-bit identifier, the // arithmetic inside cryptography. // // Everything you know about integers still applies: the same operators, the same `Min` and `Max`, // the same wrap-around at the edges, and the same widening. An `int64` becomes an `int128` as // silently as an `int32` becomes an `int64`, and an unsuffixed literal takes the type of the other // operand, however wide. Only the way back, from wide to narrow, has to be written with `as`. import Core::{ int128, int256, int64, uint128, uint256, uint512, uint64 }; import Io::PrintLine; func Main() -> int { // 2^64 is one more than the largest `uint64`, so it needs a wider home. PrintLine("uint64 max {}", uint64::Max); let next: uint128 = 18446744073709551616; PrintLine("one more {}", next); // Hex digits and `_` separators work at any width. let avogadro: uint128 = 602214076000000000000000; let mask: uint128 = 0xFFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF; PrintLine("avogadro {}", avogadro); PrintLine("mask is max {}", mask == uint128::Max); // A `uint64` can hold 20! but not 21!. A `uint128` reaches 34!. The range starts at a // `uint128`, so `n` counts in `uint128` as well. var factorial: uint128 = 1; let first: uint128 = 1; for n in first..=34 { factorial *= n; } PrintLine("34! {}", factorial); // Every doubling of the width squares the range: an `int256` goes as far as 57!, and an // `int512` as far as 97!. var big: int256 = 1; let one: int256 = 1; for n in one..=57 { big *= n; } PrintLine("57! {}", big); // The left side of a shift decides its type, so it carries the suffix. A plain `1 << 200` // would be an `int`, which has no bit 200: it prints 256. let power = 1u256 << 200; PrintLine("2^200 {}", power); // Widening needs nothing written, and the literal grows to the width of `wide`. let balance: int64 = -42; let wide: int128 = balance; let large = wide * 1_000_000_000_000_000_000_000; PrintLine("widened {}", large); // Narrowing can lose bits, so it is never silent: `let back: int64 = large;` is refused with // "cannot assign 'int128' to 'int64'". `as` keeps the low 64 bits, whatever they mean. PrintLine("narrowed {}", large as int64); // The edges behave like every other integer's: one past the maximum wraps to the minimum. PrintLine("int128 max {}", int128::Max); PrintLine("max + 1 {}", int128::Max + 1); PrintLine("uint512 max {}", uint512::Max); return 0; } ``` Besides `Io`, its `Rux.toml` lists `Core` under `[Dependencies]`. ## Run it ```sh cd Examples/Numbers/WideInteger rux run ``` ```text uint64 max 18446744073709551615 one more 18446744073709551616 avogadro 602214076000000000000000 mask is max true 34! 295232799039604140847618609643520000000 57! 40526919504877216755680601905432322134980384796226602145184481280000000000000 2^200 1606938044258990275541962092341162602522202993782792835301376 widened -42000000000000000000000 narrowed 3236255836649029632 int128 max 170141183460469231731687303715884105727 max + 1 -170141183460469231731687303715884105728 uint512 max 13407807929942597099574024998205846127479365820592393377723561443721764030073546976801874298166903427690031858186486050853753882811946569946433649006084095 ``` ## Common mistakes ::mistake **A huge literal with no type to take.**:br A literal standing alone is an `int`, and `let x = 18446744073709551616;` fails with: ```text error: integer literal is out of range for type 'int' ``` Annotate the binding — `let x: uint128 = …` — or add a suffix such as `u128`. :: ::mistake **A loop counter of the wrong type.**:br With `for n in 1..=34`, `n` is an `int`, and `factorial *= n` fails with: ```text error: operator '*=' cannot combine left operand 'uint128' with right operand 'int' ``` Start the range at a `uint128`, as the program does with `first`. :: ::mistake **Narrowing without `as`.**:br Because 64 bits cannot hold every `int128`, `let back: int64 = large;` is refused with: ```text error: cannot assign 'int128' to 'int64' ``` Write `large as int64` when losing the high bits is what you want — and check the value first when it is not. :: ::mistake **A shift that stays an `int`.**:br`1 << 200` compiles, but the `1` is an `int`, and the result is `256`, not 2²⁰⁰. Put the width on the left operand: `1u256 << 200`. :: ::mistake **Asking for a limit without importing the type.**:br`Max` and `Min` are declared in `Core`. Without `int128` in the `import Core::{ … }` list, `int128::Max` fails with: ```text error: 'Max' not found in extend for type 'int128' ``` :: ## Try it yourself 1. Change the loop to run to 35. What does `factorial` print now, and why? 2. Compute 21! in a `uint64` and compare it with the `uint128` answer. Does the program warn you? 3. Import `int256` and `uint256` from `Core` and print their `Max`. Count the digits. 4. Write `let x = 18446744073709551616;` and read the error. Then fix it two ways: with a type annotation, and with a suffix. ## Learn more - [int128](https://rux-lang.dev/docs/lang/types/integers), [uint128](https://rux-lang.dev/docs/lang/types/integers) and the [primitive types](https://rux-lang.dev/docs/lang/appendix/primitives) in the Rux Reference - [Integer](https://rux-lang.dev/docs/learn/integer) and [Literal](https://rux-lang.dev/docs/learn/literal) — the narrow integers and how literals get their types - [Number limit](https://rux-lang.dev/docs/learn/number-limit) — the constants every number type carries - [Checked arithmetic](https://rux-lang.dev/docs/learn/checked-arithmetic) — noticing when a result does not fit # Number limit ::note **You'll need**: [Integer](https://rux-lang.dev/docs/learn/integer), [Float](https://rux-lang.dev/docs/learn/float), [Const](https://rux-lang.dev/docs/learn/const), [Generic](https://rux-lang.dev/docs/learn/generic) :: How large can an `int16` get? How many bytes does a `uint8` take? What is the smallest step a `float64` can take away from 1.0? You could look the answers up and type them into your program — or ask the type itself. Every number type carries facts about itself as **associated constants**, written with `::` after the type's name: `int16::Max`, `uint8::Bits`, `float64::Epsilon`. Using them instead of typed-in numbers makes code say what it means, and keeps it right if you later change a type. ## Asking a type about itself The constants are declared in `Core`, so the program imports each type it asks about and lists `Core` as a dependency: ```rux import Core::{ MaximumOf, MinimumOf, float32, float64, int16, uint16, uint8 }; ``` Every integer type answers the same four questions: ```rux PrintLine("int16 {} to {}, {} bits in {} bytes", int16::Min, int16::Max, int16::Bits, int16::Bytes); ``` | Constant | Meaning | `int16` | `uint8` | | -------- | -------------------------- | ------- | ------- | | `Min` | The smallest value | −32768 | 0 | | `Max` | The largest value | 32767 | 255 | | `Bits` | The width in bits | 16 | 8 | | `Bytes` | The storage size, in bytes | 2 | 1 | Because they are constants, they work anywhere a constant does — including inside another `const`: ```rux const LargestPort: uint16 = uint16::Max; ``` A limit also makes a bounds check read like what it means. Will this reading fit in an `int16`? ```rux let reading: int32 = 40000; PrintLine("fits int16 {}", reading <= int16::Max && reading >= int16::Min); ``` It does not: the line prints `false`. ## Limits inside a generic function The constants belong to a concrete type. A generic function cannot reach them through its type parameter — `T::Max` is rejected, because the compiler does not know which type `T` will be. For that case `Core` offers `MaximumOf` and `MinimumOf`, which work the limit out from a sample value of the type: ```rux func Span(sample: T) -> T { return MaximumOf(sample) - MinimumOf(sample); } ``` The sample's value does not matter, only its type. `Span(0)` is 255 − 0 = `255`. ## Float limits Floats have more limits than integers, because "smallest" means two different things for them: ```rux PrintLine("float32 {} to {}", float32::Lowest, float32::Max); PrintLine("float64 {} to {}", float64::Lowest, float64::Max); PrintLine("smallest {}", float64::MinPositive); PrintLine("epsilon {}", float64::Epsilon); ``` | Constant | Meaning | `float64` | | ------------- | ----------------------------------------- | ------------------------ | | `Lowest` | The most negative finite value | −1.7976931348623157e+308 | | `Max` | The largest finite value | 1.7976931348623157e+308 | | `MinPositive` | The smallest normal value above zero | 2.2250738585072014e-308 | | `Epsilon` | The gap between 1.0 and the next float up | 2.220446049250313e-16 | There is no `float64::Min`: instead of one ambiguous name, the two meanings get a name each. ```mermaid flowchart LR %% vertical: BT low["`Lowest`
most negative"] --- neg["…"] --- mp["`−MinPositive`"] --- zero["`0`"] --- pos["`MinPositive`
closest to zero"] --- more["…"] --- max["`Max`
largest"] ``` ## Epsilon, the smallest step `Epsilon` is how finely the numbers near 1.0 are divided. Add it to 1.0 and you get the next float up; add anything smaller and the sum rounds straight back to 1.0: ```rux let one = 1.0; PrintLine("1 + e {}", one + float64::Epsilon); PrintLine("1 + e / 2 {}", one + float64::Epsilon / 2.0); ``` The first prints `1.0000000000000002`, the second `1.0` — half an epsilon was lost. That is why `0.1 + 0.2` is not exactly `0.3`, as you saw in [Float](https://rux-lang.dev/docs/learn/float). ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Numbers/NumberLimit){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // Every number type carries facts about itself as associated constants, written with `::` after // the type's name: `int16::Max`, `uint8::Bits`, `float64::Epsilon`. They are declared in `Core`, // so a lesson that uses them imports each type it asks about and lists `Core` as a dependency. // // Because they are constants, they work anywhere a constant does, including inside another // `const`. And because they belong to a concrete type, a generic function cannot reach them // through its type parameter: `T::Max` is rejected with "'Max' not found in extend for type 'T'". // For that case `Core` offers `MaximumOf` and `MinimumOf`, which work the limit out from a sample // value of the type. // // Floats have more limits than integers, because "smallest" means two different things: `Lowest` // is the most negative finite value, and `MinPositive` the smallest normal value above zero. // `Epsilon` is the gap between 1.0 and the next float up. import Core::{ MaximumOf, MinimumOf, float32, float64, int16, uint16, uint8 }; import Io::PrintLine; // A limit can define another constant. const LargestPort: uint16 = uint16::Max; // A generic function asks `Core` for the limits of its own type parameter. func Span(sample: T) -> T { return MaximumOf(sample) - MinimumOf(sample); } func Main() -> int { // Integers: the range, and the storage behind it. PrintLine("int16 {} to {}, {} bits in {} bytes", int16::Min, int16::Max, int16::Bits, int16::Bytes); PrintLine("port up to {}", LargestPort); PrintLine("uint8 span {}", Span(0)); // Floats: the finite range, and how finely it is divided. PrintLine("float32 {} to {}", float32::Lowest, float32::Max); PrintLine("float64 {} to {}", float64::Lowest, float64::Max); PrintLine("smallest {}", float64::MinPositive); PrintLine("epsilon {}", float64::Epsilon); // Epsilon is the smallest step 1.0 can take. Anything smaller added to 1.0 is lost. let one = 1.0; PrintLine("1 + e {}", one + float64::Epsilon); PrintLine("1 + e / 2 {}", one + float64::Epsilon / 2.0); // A limit makes a bounds check read like what it means. let reading: int32 = 40000; PrintLine("fits int16 {}", reading <= int16::Max && reading >= int16::Min); return 0; } ``` Besides `Io`, its `Rux.toml` lists `Core` under `[Dependencies]`. ## Run it ```sh cd Examples/Numbers/NumberLimit rux run ``` ```text int16 -32768 to 32767, 16 bits in 2 bytes port up to 65535 uint8 span 255 float32 -3.4028235e+38 to 3.4028235e+38 float64 -1.7976931348623157e+308 to 1.7976931348623157e+308 smallest 2.2250738585072014e-308 epsilon 2.220446049250313e-16 1 + e 1.0000000000000002 1 + e / 2 1.0 fits int16 false ``` ## Common mistakes ::mistake **Asking a float for `Min`.**:br`float64::Min` fails with: ```text error: 'Min' not found in extend for type 'float64' ``` Use `Lowest` for the most negative value, or `MinPositive` for the one closest to zero. :: ::mistake **Asking a type parameter for a limit.**:br Inside `func Top(sample: T)`, `T::Max` fails with: ```text error: 'Max' not found in extend for type 'T' ``` Use `MaximumOf(sample)` and `MinimumOf(sample)`. :: ::mistake **Forgetting to import the type.**:br The constants live in `Core`. Without `int16` in the import list, `int16::Max` fails with: ```text error: 'Max' not found in extend for type 'int16' ``` :: ::mistake **Comparing with a limit of the other signedness.**:br`reading <= uint8::Max` with an `int32` called `reading` fails with: ```text error: operator '<=' cannot compare left operand 'int32' with right operand 'uint8' ``` Convert the limit, which always fits: `reading <= uint8::Max as int32`. :: ## Try it yourself 1. Print `Min`, `Max`, `Bits` and `Bytes` for `int8`, `uint32` and `int64`. 2. Call `Span(0)`. Predict the answer first — then explain the one you get. 3. Print `float32::Epsilon` next to `float64::Epsilon`. How many more significant digits does a `float64` keep? 4. Change the bounds check so it asks whether `reading` fits in a `uint16`. ## Learn more - The [primitive types](https://rux-lang.dev/docs/lang/appendix/primitives) and [int16](https://rux-lang.dev/docs/lang/types/integers) in the Rux Reference - [Integer](https://rux-lang.dev/docs/learn/integer) and [Float](https://rux-lang.dev/docs/learn/float) — the types these limits describe - [Float special](https://rux-lang.dev/docs/learn/float-special) — what lies beyond `Max`: infinity and NaN - [Generic](https://rux-lang.dev/docs/learn/generic) — functions with type parameters # Float special ::note **You'll need**: [Float](https://rux-lang.dev/docs/learn/float), [Comparison](https://rux-lang.dev/docs/learn/comparison), [Number limit](https://rux-lang.dev/docs/learn/number-limit), [Format number](https://rux-lang.dev/docs/learn/format-number) :: An integer has nowhere to go past its limits: divide one by zero and the program stops. A float is different. It has a few values that are not ordinary numbers at all, and arithmetic that runs off the edge lands on one of them and carries on: - **Infinity**, `Inf`, when a result is too big to represent — or a non-zero number is divided by zero. - **NaN**, "not a number", when a result has no sensible value at all, such as zero divided by zero. Neither is an error. The special value simply flows into everything computed from it. This lesson shows where they come from, and the one rule about them that catches everybody: how NaN compares. ## Where the special values come from ```rux let zero = 0.0; PrintLine("1 / 0 {}", 1.0 / zero); PrintLine("-1 / 0 {}", -1.0 / zero); PrintLine("0 / 0 {}", zero / zero); PrintLine("Max * 2 {}", float64::Max * 2.0); PrintLine("Inf - Inf {}", float64::Infinity - float64::Infinity); ``` | Expression | Result | Why | | -------------------- | ------ | -------------------------------------------- | | `1.0 / 0.0` | `Inf` | The quotient grows without bound | | `-1.0 / 0.0` | `-Inf` | The same, below zero | | `0.0 / 0.0` | `NaN` | No single answer makes sense | | `float64::Max * 2.0` | `Inf` | Too large to represent: it overflows upwards | | `Inf - Inf` | `NaN` | Again, no single answer | Both values are also available by name, `float64::Infinity` and `float64::NaN`, from `Core`. Formatting with a precision leaves them alone — there are no digits to round — so `{:.3}` still prints `Inf` and `NaN`. Compare an integer: `10 / n` with a zero `n` stops the program with `Panic: division by zero` and the line it happened on. Integers have no special values to fall back on. ## Infinity compares like a number Infinity is larger than every finite number, and equal to itself: ```rux let inf = float64::Infinity; PrintLine("Inf > Max {}", inf > float64::Max); PrintLine("Inf == Inf {}", inf == inf); ``` Both lines print `true`. No surprises there. ## NaN compares false with everything NaN is **unordered**. Every comparison with it is `false` — even with itself — except `!=`, which is `true`: ```rux let nan = float64::NaN; PrintLine("NaN == NaN {}", nan == nan); PrintLine("NaN != NaN {}", nan != nan); PrintLine("NaN < 1 {}", nan < 1.0); PrintLine("NaN > 1 {}", nan > 1.0); ``` NaN is neither less than 1 nor greater than it, nor equal to anything. The rule makes NaN spread instead of hiding: a test such as `if total > limit` cannot be fooled into `true` by a NaN `total`. But it also means a test written as `x == float64::NaN` can **never** succeed. ## Asking what a value is The reliable way to ask is a function from `Core`: ```rux PrintLine("IsNaN {}", IsNaN(nan)); PrintLine("IsInfinite {}", IsInfinite(inf)); PrintLine("IsFinite {}", IsFinite(float64::Max)); ``` ```mermaid flowchart LR x["A `float64` value"] --> n{"`IsNaN`?"} n -- "yes" --> isnan["`NaN`"] n -- "no" --> i{"`IsInfinite`?"} i -- "yes" --> isinf["`Inf` or `-Inf`"] i -- "no" --> fin["An ordinary number:
`IsFinite` is `true`"] ``` `IsFinite` is true exactly when the value is neither NaN nor an infinity — the right check before you use a result as an ordinary number. ## Two zeros Zero has a sign too. `-0.0` and `0.0` compare equal, yet dividing by them gives infinities of opposite signs: ```rux let negativeZero = -0.0; PrintLine("-0 == 0 {}", negativeZero == zero); PrintLine("1 / -0 {}", 1.0 / negativeZero); ``` The first line prints `true`, the second `-Inf`. A negative zero turns up when a tiny negative result rounds to zero; it remembers which side it came from. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Numbers/FloatSpecial){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // A float does not stop at its largest number. When a result is too big to represent, it becomes // infinity, `Inf`; when a result has no sensible value at all, such as zero divided by zero, it // becomes NaN, "not a number". Neither is an error: the arithmetic carries on and the special // value flows into everything computed from it. Integers have neither, which is why an integer // division by zero stops the program with "Panic: division by zero" and the line it happened on, // while a float division by zero carries on. // // The surprise is in comparison. Infinity compares as you would expect, larger than every finite // number. NaN compares false with everything, including itself, so `nan == nan` is `false` and // `nan != nan` is `true`. A test written as `x == float64::NaN` can therefore never succeed; ask // `Core::IsNaN` instead. Zero has a sign too: `-0.0 == 0.0`, yet dividing by them gives // infinities of opposite signs. import Core::{ IsFinite, IsInfinite, IsNaN, float64 }; import Io::PrintLine; func Main() -> int { let zero = 0.0; // Where the special values come from. PrintLine("1 / 0 {}", 1.0 / zero); PrintLine("-1 / 0 {}", -1.0 / zero); PrintLine("0 / 0 {}", zero / zero); PrintLine("Max * 2 {}", float64::Max * 2.0); PrintLine("Inf - Inf {}", float64::Infinity - float64::Infinity); // A precision has no digits to round here, so the words come out unchanged. PrintLine("rounded {:.3} {:.3}", 1.0 / zero, zero / zero); // Infinity is ordered like a number. let inf = float64::Infinity; PrintLine("Inf > Max {}", inf > float64::Max); PrintLine("Inf == Inf {}", inf == inf); // NaN is unordered: every comparison with it is false, except `!=`. let nan = float64::NaN; PrintLine("NaN == NaN {}", nan == nan); PrintLine("NaN != NaN {}", nan != nan); PrintLine("NaN < 1 {}", nan < 1.0); PrintLine("NaN > 1 {}", nan > 1.0); // The reliable way to ask what a value is. PrintLine("IsNaN {}", IsNaN(nan)); PrintLine("IsInfinite {}", IsInfinite(inf)); PrintLine("IsFinite {}", IsFinite(float64::Max)); // Two zeros that are equal and still different. let negativeZero = -0.0; PrintLine("-0 == 0 {}", negativeZero == zero); PrintLine("1 / -0 {}", 1.0 / negativeZero); return 0; } ``` Besides `Io`, its `Rux.toml` lists `Core` under `[Dependencies]`. ## Run it ```sh cd Examples/Numbers/FloatSpecial rux run ``` ```text 1 / 0 Inf -1 / 0 -Inf 0 / 0 NaN Max * 2 Inf Inf - Inf NaN rounded Inf NaN Inf > Max true Inf == Inf true NaN == NaN false NaN != NaN true NaN < 1 false NaN > 1 false IsNaN true IsInfinite true IsFinite true -0 == 0 true 1 / -0 -Inf ``` ## Common mistakes ::mistake **Testing for NaN with `==`.**:br`x == float64::NaN` is always `false`, even when `x` is NaN — the compiler accepts it, and it simply never matches. Use `IsNaN(x)`. :: ::mistake **Expecting an error from a float division by zero.**:br`1.0 / 0.0` is `Inf`, and the program carries on with it. Only an integer division by zero stops the program. Check a divisor that might be zero, or check the result with `IsFinite`. :: ::mistake **Converting a special value to an integer.**:br`as` never fails, so it has to produce something: `NaN as int32` is `0`, and `Inf as int32` saturates to `2147483647`. Neither says anything went wrong. [Checked convert](https://rux-lang.dev/docs/learn/checked-convert) reports it. :: ## Try it yourself 1. Compute `float32::Max * 2.0f32`. Is a `float32` infinity printed any differently? 2. Start from `let nan = zero / zero;` and work out `nan + 1.0`, `nan * 0.0` and `float64::Infinity * 0.0`. Which are NaN? 3. Write `func SafeDivide(a: float64, b: float64) -> float64?` that returns `none` when the result is not finite. 4. Import `IsNegativeZero` from `Core` and use it to tell `-0.0` from `0.0`, which `==` cannot. ## Learn more - [float64](https://rux-lang.dev/docs/lang/types/floating-point) in the Rux Reference - [Float](https://rux-lang.dev/docs/learn/float) — the float types and their precision - [Number limit](https://rux-lang.dev/docs/learn/number-limit) — `Max`, `Lowest` and `Epsilon` - [Math](https://rux-lang.dev/docs/learn/math) — functions whose answers outside their domain are NaN and infinities # Bitwise ::note **You'll need**: [Integer](https://rux-lang.dev/docs/learn/integer), [Literal](https://rux-lang.dev/docs/learn/literal), [Const](https://rux-lang.dev/docs/learn/const), [Assignment](https://rux-lang.dev/docs/learn/assignment) :: Underneath, every integer is a row of bits. Arithmetic treats that row as one number; the **bitwise operators** treat it as a row of separate yes-or-no switches and work on each position on its own. That makes them the tool for packing several small facts into one value — eight permissions in a single byte, a set of options in one argument — and for reading them back out. ## Four operators, one bit at a time | Operator | Name | A result bit is 1 when… | | -------- | ---- | ------------------------------------- | | `a & b` | AND | both bits are 1 | | `a | b` | OR | either bit is 1 | | `a ^ b` | XOR | exactly one of the two bits is 1 | | `~a` | NOT | the bit in `a` is 0 — every bit flips | The program prints them side by side. `{:08b}` formats a number in binary, padded with zeros to eight digits, so the columns line up: ```rux let a: uint8 = 0b1100_1010; let b: uint8 = 0b1010_0110; PrintLine("a {:08b}", a); PrintLine("b {:08b}", b); PrintLine("a & b {:08b}", a & b); PrintLine("a | b {:08b}", a | b); PrintLine("a ^ b {:08b}", a ^ b); PrintLine("~a {:08b}", ~a); ``` ```text a 11001010 b 10100110 a & b 10000010 a | b 11101110 a ^ b 01101100 ~a 00110101 ``` Read any column top to bottom and the rule of the table holds. `~` depends on the width of its operand: `~` of a `uint8` flips eight bits, `~` of a `uint32` flips thirty-two. Unsigned types are the usual choice for bit work, because no bit doubles as a sign. ## Flags and masks A **mask** is a value whose set bits pick out the positions you care about. Give each flag its own bit, and one byte holds eight of them. Written in binary, the constants show which bit each one owns: ```rux const Read: uint8 = 0b001; const Write: uint8 = 0b010; const Execute: uint8 = 0b100; ``` Four idioms cover almost everything done with flags: | Goal | Idiom | Why it works | | ------------ | ---------------------- | -------------------------------------------------- | | Set a flag | `flags |= Write` | OR turns that bit on and leaves the rest alone | | Clear a flag | `flags &= ~Read` | `~Read` has every bit but one set; AND keeps those | | Flip a flag | `flags ^= Execute` | XOR with 1 flips a bit, XOR with 0 keeps it | | Test a flag | `(flags & Write) != 0` | AND keeps only that bit; non-zero means it was set | In the program they run one after another on `flags`: ```rux var flags: uint8 = Read; flags |= Write; flags ^= Execute; flags &= ~Read; ``` The byte goes `001` → `011` → `111` → `110`: it started with Read, gained Write, gained Execute by a flip, and lost Read. ```mermaid flowchart LR s["`001`
`Read`"] -- "set `Write`" --> w["`011`"] w -- "flip `Execute`" --> x["`111`"] x -- "clear `Read`" --> r["`110`
`Write`, `Execute`"] ``` ## Testing flags Testing asks whether a bit survives the mask: ```rux PrintLine("can write? {}", (flags & Write) != 0); PrintLine("can read? {}", (flags & Read) != 0); ``` A mask with several bits tests them together. `!= 0` would mean "any of them"; comparing with the mask itself means "all of them": ```rux let both = Write | Execute; PrintLine("write and run? {}", (flags & both) == both); ``` ## Watch the precedence `&`, `|` and `^` bind more loosely than `==` and `!=`. So `flags & Write == 0` reads as `flags & (Write == 0)` — a byte AND a boolean — and the compiler rejects it. Parenthesise the mask every time: `(flags & Write) == 0`. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Numbers/Bitwise){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // The bitwise operators treat an integer as a row of bits and work on each position separately. // `a & b` keeps a bit only where both have it, `a | b` where either has it, and `a ^ b` where // exactly one has it. `~a` flips every bit, so its result depends on the width: `~` of a `uint8` // flips eight bits, of a `uint32` thirty-two. // // Their everyday use is the mask: a value whose set bits pick out the positions you care about. // One byte can then hold eight yes-or-no flags, and four idioms cover almost everything done with // them: `|` sets a flag, `& ~` clears it, `^` flips it, and `&` tests it. // // Watch the precedence. `&`, `|` and `^` bind more loosely than `==`, so `flags & Write == 0` reads // as `flags & (Write == 0)` and is rejected for mixing a `uint8` with a `bool`. Parenthesize the // mask: `(flags & Write) == 0`. import Io::PrintLine; // One bit per permission. Written in binary, the masks show which bit each one owns. const Read: uint8 = 0b001; const Write: uint8 = 0b010; const Execute: uint8 = 0b100; func Main() -> int { // The four operators, side by side. let a: uint8 = 0b1100_1010; let b: uint8 = 0b1010_0110; PrintLine("a {:08b}", a); PrintLine("b {:08b}", b); PrintLine("a & b {:08b}", a & b); PrintLine("a | b {:08b}", a | b); PrintLine("a ^ b {:08b}", a ^ b); PrintLine("~a {:08b}", ~a); PrintLine(""); // Masks at work on a set of flags. var flags: uint8 = Read; PrintLine("start {:03b}", flags); flags |= Write; PrintLine("set Write {:03b}", flags); flags ^= Execute; PrintLine("flip Execute {:03b}", flags); flags &= ~Read; PrintLine("clear Read {:03b}", flags); PrintLine("can write? {}", (flags & Write) != 0); PrintLine("can read? {}", (flags & Read) != 0); // A mask with several bits tests them together. let both = Write | Execute; PrintLine("write and run? {}", (flags & both) == both); return 0; } ``` ## Run it ```sh cd Examples/Numbers/Bitwise rux run ``` ```text a 11001010 b 10100110 a & b 10000010 a | b 11101110 a ^ b 01101100 ~a 00110101 start 001 set Write 011 flip Execute 111 clear Read 110 can write? true can read? false write and run? true ``` ## Common mistakes ::mistake **Leaving out the parentheses.**:br`flags & Write == 0` groups as `flags & (Write == 0)` and fails with: ```text error: operator '&' cannot combine left operand 'uint8' with right operand 'bool8' ``` Write `(flags & Write) == 0`. :: ::mistake **Using `!` to invert a mask.**:br`!` is logical NOT, for booleans only: `flags & !Write` fails with: ```text error: operator '!' requires a bool operand, but found 'uint8' ``` The bitwise NOT is `~`: `flags & ~Write`. :: ::mistake **Using a masked value as a condition.**:br Rux does not treat a non-zero number as true. `if flags & Write { … }` fails with: ```text error: condition for 'if' must have type 'bool', but found 'uint8' ``` Compare it: `if (flags & Write) != 0 { … }`. :: ## Try it yourself 1. Add a fourth flag, `Delete: uint8 = 0b1000`, set it, and print `flags` with `{:04b}`. 2. Write `func Has(flags: uint8, mask: uint8) -> bool` that returns whether every bit of `mask` is set in `flags`. 3. XOR a value with the same mask twice. What do you get back, and why? 4. Change `a` and `b` to `uint32` and print `~a` with `{:032b}`. How many bits flipped this time? ## Learn more - [Bitwise operations](https://rux-lang.dev/docs/lang/expressions/bitwise) in the Rux Reference - [Shift](https://rux-lang.dev/docs/learn/shift) — moving bits along, and building masks with `1 << n` - [Bit operation](https://rux-lang.dev/docs/learn/bit-operation) — counting and rotating bits - [Format number](https://rux-lang.dev/docs/learn/format-number) — `{:b}`, `{:x}` and padding # Shift ::note **You'll need**: [Bitwise](https://rux-lang.dev/docs/learn/bitwise), [Convert](https://rux-lang.dev/docs/learn/convert) :: A **shift** slides every bit of an integer along by a number of places. Bits that move past the end are dropped, and new bits come in at the other end. Because each place is a power of two, shifting is also a fast way to multiply and divide by 2, 4, 8 and so on — but its everyday use is building masks and packing several small fields into one number. ## Left shifts multiply `x << n` moves the bits towards the high end and brings zeros in at the bottom. As long as nothing falls off the top, that multiplies by 2ⁿ: ```rux let one: uint32 = 1; PrintLine("1 << 4 {}", one << 4); PrintLine("5 << 3 {}", 5 << 3); ``` `1 << 4` is 16, and `5 << 3` is 5 × 8 = 40. `1 << n` is also how a mask for bit `n` is made — the single-bit masks of [Bitwise](https://rux-lang.dev/docs/learn/bitwise) could be written `1 << 0`, `1 << 1` and `1 << 2`. The result has the type of the **left** operand, and bits pushed past its width are gone. A `uint8` holding 200 shifted left by one is not 400 but `144` — the top bit fell off. ## Right shifts divide Shifting the other way divides by 2ⁿ and drops the remainder: ```rux let value: int32 = 100; PrintLine("100 >> 2 {}", value >> 2); ``` 100 / 4 = 25. For a negative number, `>>` rounds **down**, towards minus infinity, where `/` rounds towards zero: `-7 >> 1` is `-4`, while `-7 / 2` is `-3`. ## Two right shifts Shifting right empties the top bits, and something has to fill them. For a signed number there are two sensible answers, so Rux has two operators: | Operator | Name | Fills the top with | On a negative number | | -------- | ---------- | ---------------------- | -------------------- | | `>>` | arithmetic | copies of the sign bit | stays negative | | `>>>` | logical | zeros, always | becomes positive | The program shows both on −16. `{:b}` would print a signed value with a minus sign, so each one is shown through `as uint32` to see the bits themselves: ```rux let negative: int32 = -16; let arithmetic = negative >> 2; let logical = negative >>> 2; PrintLine("-16 {:032b}", negative as uint32); PrintLine("-16 >> 2 {:032b} {}", arithmetic as uint32, arithmetic); PrintLine("-16 >>> 2 {:032b} {}", logical as uint32, logical); ``` ```text -16 11111111111111111111111111110000 -16 >> 2 11111111111111111111111111111100 -4 -16 >>> 2 00111111111111111111111111111100 1073741820 ``` `>>` kept the sign and divided: −16 / 4 = −4. `>>>` treated the value as plain bits, and the two zeros it brought in made a large positive number. An unsigned type has no sign bit to copy, so its `>>` already brings in zeros. That is why `>>>` exists only for signed types: on a `uint8` or `uint32`, use `>>`. ## Packing fields into one integer Shifts and masks together store several small fields in one number. A colour is the classic case: one byte each of red, green and blue. Each channel is shifted into its own byte, then the three are combined with `|`: ```rux let red: uint32 = 0xFF; let green: uint32 = 0x80; let blue: uint32 = 0x20; let color = (red << 16) | (green << 8) | blue; ``` ```mermaid flowchart LR r["red `0xFF`"] -- "shifted left 16" --> c["`0x FF 80 20`"] g["green `0x80`"] -- "shifted left 8" --> c b["blue `0x20`"] -- "as is" --> c ``` Unpacking runs the other way: shift the field down to the bottom, then mask away everything above it with `& 0xFF`: ```rux PrintLine("red {:#x}", (color >> 16) & 0xFF); PrintLine("green {:#x}", (color >> 8) & 0xFF); PrintLine("blue {:#x}", color & 0xFF); ``` `{:#x}` prints hexadecimal with a `0x` in front, so the packed value shows as `0xff8020`. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Numbers/Shift){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // A shift slides every bit of an integer along by a number of places. `x << n` moves them towards // the high end and brings zeros in at the bottom, which multiplies by 2 to the n as long as nothing // falls off the top. Shifting the other way divides, and Rux has two right shifts because a signed // number gives the question of what to bring in at the top two answers: // // >> arithmetic: copies the sign bit, so a negative number stays negative // >>> logical: always brings in zeros, treating the value as plain bits // // On an unsigned type there is no sign to copy, so `>>` already brings in zeros and `>>>` is // refused: it needs a signed left operand. On a signed type, `-16 >> 2` is -4, while `-16 >>> 2` // is a large positive number. // // Shifts and masks together pack several small fields into one integer, the way a color is stored // as one byte each of red, green and blue. import Io::PrintLine; func Main() -> int { // Left shifts multiply by powers of two. let one: uint32 = 1; PrintLine("1 << 4 {}", one << 4); PrintLine("5 << 3 {}", 5 << 3); // Right shifts divide, rounding down. let value: int32 = 100; PrintLine("100 >> 2 {}", value >> 2); // The two right shifts part ways on a negative number. `{:b}` prints a signed value with a // minus sign, so each one is shown through `as uint32` to see the bits themselves. let negative: int32 = -16; let arithmetic = negative >> 2; let logical = negative >>> 2; PrintLine("-16 {:032b}", negative as uint32); PrintLine("-16 >> 2 {:032b} {}", arithmetic as uint32, arithmetic); PrintLine("-16 >>> 2 {:032b} {}", logical as uint32, logical); PrintLine(""); // Packing: each channel shifted into its own byte, then combined with `|`. let red: uint32 = 0xFF; let green: uint32 = 0x80; let blue: uint32 = 0x20; let color = (red << 16) | (green << 8) | blue; PrintLine("packed {:#08x}", color); // Unpacking: shift the field down to the bottom, then mask away everything above it. PrintLine("red {:#x}", (color >> 16) & 0xFF); PrintLine("green {:#x}", (color >> 8) & 0xFF); PrintLine("blue {:#x}", color & 0xFF); return 0; } ``` ## Run it ```sh cd Examples/Numbers/Shift rux run ``` ```text 1 << 4 16 5 << 3 40 100 >> 2 25 -16 11111111111111111111111111110000 -16 >> 2 11111111111111111111111111111100 -4 -16 >>> 2 00111111111111111111111111111100 1073741820 packed 0xff8020 red 0xff green 0x80 blue 0x20 ``` ## Common mistakes ::mistake **Using `>>>` on an unsigned value.**:br`b >>> 1` with a `uint8` called `b` fails with: ```text error: operator '>>>' requires a signed integer left operand, but found 'uint8' ``` Unsigned `>>` already fills with zeros — use it. :: ::mistake **Expecting `>>` to divide exactly like `/`.**:br On a negative odd number they differ: `-7 >> 1` is `-4`, `-7 / 2` is `-3`. Use `/` when you mean division, and `>>` when you mean bits. :: ::mistake **Shifting bits off the top.**:br A left shift multiplies only while the result fits: a `uint8` 200 `<< 1` is `144`, with no warning. Shift a wider type when the result needs the room, and keep every shift count below the width of the left operand. :: ## Try it yourself 1. Build a mask for bit 5 with `1 << 5`, and use it to set, test and clear that bit in a `uint8`. 2. Pack an hour (0–23), a minute and a second into one `uint32`, eight bits each, then unpack them. 3. Add an alpha channel to the colour: four bytes, alpha highest. Print it with `{:#010x}`. 4. Print `-1 >> 1` and `-1 >>> 1` for an `int32`. Explain both answers from the bits. ## Learn more - [Shift operations](https://rux-lang.dev/docs/lang/expressions/shift) in the Rux Reference - [Bitwise](https://rux-lang.dev/docs/learn/bitwise) — the masks shifts are combined with - [Bit operation](https://rux-lang.dev/docs/learn/bit-operation) — rotations, where no bit falls off - [Endian](https://rux-lang.dev/docs/learn/endian) — the order of a number's bytes in memory # Checked arithmetic ::note **You'll need**: [Out parameter](https://rux-lang.dev/docs/learn/out-parameter), [Optional](https://rux-lang.dev/docs/learn/optional), [Presence](https://rux-lang.dev/docs/learn/presence), [Coalesce](https://rux-lang.dev/docs/learn/coalesce), [Number limit](https://rux-lang.dev/docs/learn/number-limit) :: Ordinary `+`, `-` and `*` never complain. A result too big for its type wraps around, and the program carries on with a wrong number: `uint8` 255 + 1 is 0. Often that is harmless — the values are known to be small. But in a size, a price, a count or an index, a silently wrong number is a bug waiting to happen. When it would matter, ask `Core` to **check** instead. `AddChecked`, `SubChecked` and `MulChecked` do the same arithmetic and also tell you whether it overflowed. They work at every integer width, signed or unsigned. ## Two answers from one call A checked operation has two things to hand back: the result, and whether it is trustworthy. So it uses an [out-parameter](https://rux-lang.dev/docs/learn/out-parameter). The result is written through a pointer, and the return value is a `bool`: ```rux var sum: uint8 = 0; let first = AddChecked(uint8::Max - 5, 5, @sum); ``` `@sum` is a pointer to `sum`, and the call writes 255 into it. The returned `bool` answers the question **"did it overflow?"** — so here it is `false`. That reads backwards the first time, since `true` means failure. Name the flag after the problem rather than the success — `overflowed`, `short`, `deep` — and the `if` that follows reads correctly. ```mermaid flowchart LR invoke["`AddChecked(a, b, @result)`"] --> w["writes `a + b`
through `@result`"] invoke --> q{"returns:
did it overflow?"} q -- "`false`" --> ok["`result` is the true answer"] q -- "`true`" --> bad["`result` is the wrapped value:
do not use it"] ``` ## When it overflows One step too far, and the flag is raised: ```rux let second = AddChecked(uint8::Max, 1, @sum); ``` `second` is `true`. The pointer is written either way, with the value `+` would have wrapped to — here 0 — so check the flag before you use the result. An unsigned type has nothing below zero, so subtraction overflows downwards: ```rux var stock: uint32 = 0; let short = SubChecked(3, 5, @stock); ``` `short` is `true` and `stock` holds the wrapped 4294967294. Signed types overflow at both ends — one below the minimum wraps to the maximum: ```rux var level: int32 = 0; let deep = SubChecked(int32::Min, 1, @level); ``` | Call | Overflow | Written to the pointer | | ------------------------------ | -------- | ---------------------- | | `AddChecked(250u8, 5, …)` | `false` | 255 | | `AddChecked(255u8, 1, …)` | `true` | 0 | | `SubChecked(3u32, 5, …)` | `true` | 4294967294 | | `SubChecked(int32::Min, 1, …)` | `true` | 2147483647 | All three arguments share one type, which the compiler works out from the call — from a typed operand, or from the pointer when both operands are plain literals, as in `SubChecked(3, 5, @stock)`. Every argument has to agree with it. ## Reporting overflow in a type A `bool` and an out-parameter are awkward to pass around. The usual move is to hide them inside a function whose return type says what can go wrong — here an [optional](https://rux-lang.dev/docs/learn/optional): ```rux func Area(width: uint32, height: uint32) -> uint32? { var area: uint32 = 0; let overflowed = MulChecked(width, height, @area); if overflowed { return none; } return area; } ``` A caller can no longer use a wrapped area by accident. It gets `none`, and has to decide — with `??`, or with a `match`: ```rux PrintLine("area {}", Area(1920, 1080) ?? 0); match Area(100000, 100000) { area? => PrintLine("area {}", area), none => PrintLine("area too large") } ``` 100 000 × 100 000 is ten billion, more than a `uint32` holds, so the second call prints `too large`. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Numbers/CheckedArithmetic){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // Ordinary `+`, `-` and `*` never complain: a result too big for its type wraps around and the // program carries on with a wrong number. When a wrong number would matter, as in a size, a price // or a count, ask `Core` to check instead. `AddChecked`, `SubChecked` and `MulChecked` work at // every integer width, signed or unsigned. // // Each one hands back two things, so it uses an out-parameter: the result is written through the // pointer, and the return value is a `bool` that answers "did it overflow?". That reads backwards // the first time, since `true` means failure, so name the flag after the problem rather than the // success. The pointer is written either way, with the wrapped value when the answer is `true`. // // A function that does the checking can then report overflow in a type, here as an optional. import Core::{ AddChecked, MulChecked, SubChecked, int32, uint8 }; import Io::PrintLine; // The area of a rectangle, or `none` when it does not fit in 32 bits. func Area(width: uint32, height: uint32) -> uint32? { var area: uint32 = 0; let overflowed = MulChecked(width, height, @area); if overflowed { return none; } return area; } func Main() -> int { var sum: uint8 = 0; // Within range: no overflow, and the result is the true sum. let first = AddChecked(uint8::Max - 5, 5, @sum); PrintLine("250 + 5 overflow {:5} result {}", first, sum); // One step too far: the flag is raised, and the result is what `+` would have wrapped to. let second = AddChecked(uint8::Max, 1, @sum); PrintLine("255 + 1 overflow {:5} result {}", second, sum); // An unsigned type has nothing below zero. var stock: uint32 = 0; let short = SubChecked(3, 5, @stock); PrintLine("3 - 5 overflow {:5} result {}", short, stock); // Signed types overflow at both ends. var level: int32 = 0; let deep = SubChecked(int32::Min, 1, @level); PrintLine("Min - 1 overflow {:5} result {}", deep, level); // The check, hidden behind a function that says what went wrong in its type. PrintLine("area {}", Area(1920, 1080) ?? 0); match Area(100000, 100000) { area? => PrintLine("area {}", area), none => PrintLine("area too large") } return 0; } ``` Besides `Io`, its `Rux.toml` lists `Core` under `[Dependencies]`. ## Run it ```sh cd Examples/Numbers/CheckedArithmetic rux run ``` ```text 250 + 5 overflow false result 255 255 + 1 overflow true result 0 3 - 5 overflow true result 4294967294 Min - 1 overflow true result 2147483647 area 2073600 area too large ``` ## Common mistakes ::mistake **Reading the flag the wrong way round.**:br The `bool` means "overflowed", so `true` is the bad case. `if AddChecked(a, b, @sum) { use(sum) }` uses exactly the results it should reject. Name the flag after the problem — `let overflowed = …` — and test that. :: ::mistake **Ignoring the flag.**:br`AddChecked(a, 5, @sum);` on its own compiles: the `bool` may be dropped. But then the result is no safer than `a + 5`. Keep the flag and act on it. :: ::mistake **Mixing types in one call.**:br Both operands must have one type. With a `uint8` called `a` and an `int32` called `b`, `AddChecked(a, b, @sum)` fails with: ```text error: argument 2 to 'AddChecked' has type 'int32', but parameter 'right' requires 'uint8' ``` Convert one of them first — checking that it fits. :: ::mistake **A result pointer of another type.**:br`AddChecked(a, 5, @sum)` with a `uint8` called `a` and an `int32` called `sum` fails with: ```text error: argument 1 to 'AddChecked' has type 'uint8', but parameter 'left' requires 'T' ``` The message names the first argument, but the fix is the third: the result must have the operands' type. :: ## Try it yourself 1. Write `func Total(prices: uint32[..]) -> uint32?` that adds the prices with `AddChecked` and returns `none` at the first overflow. 2. Use `MulChecked` on two `int8` values, −128 and −1. Does it overflow? Why? 3. Change `Area` to return `uint32 ! AreaError`, with an error variant `TooLarge`, and handle it in `Main` with `catch`. ## Learn more - [Arithmetic operations](https://rux-lang.dev/docs/lang/expressions/arithmetic) in the Rux Reference - [Wrapping arithmetic](https://rux-lang.dev/docs/learn/wrapping-arithmetic) — when overflow is the plan, not the problem - [Checked convert](https://rux-lang.dev/docs/learn/checked-convert) — the same idea for conversions between types - [Out-parameter](https://rux-lang.dev/docs/learn/out-parameter) — returning a second answer through a pointer # Wrapping arithmetic ::note **You'll need**: [Checked arithmetic](https://rux-lang.dev/docs/learn/checked-arithmetic), [String literal](https://rux-lang.dev/docs/learn/string-literal) :: [Checked arithmetic](https://rux-lang.dev/docs/learn/checked-arithmetic) treats overflow as a problem to report. Sometimes it is not a problem but the plan, and the only question is what the result should be. `Core` names the two useful answers, at every integer width: - **Wrapping** — go round, like a car's odometer rolling from 999999 back to 000000. - **Saturating** — stop at the type's limit and stay there, like a volume knob turned all the way up. ## Wrapping, on purpose `AddWrapping`, `SubWrapping` and `MulWrapping` compute exactly what `+`, `-` and `*` already do: ```rux let high: uint8 = 250; let low: uint8 = 5; let middle: uint8 = 200; PrintLine("wrapping 250 + 10 = {}", AddWrapping(high, 10)); PrintLine("wrapping 5 - 10 = {}", SubWrapping(low, 10)); PrintLine("wrapping 200 * 2 = {}", MulWrapping(middle, 2)); ``` A `uint8` counts 0 to 255 and then starts again, so 250 + 10 is 260 − 256 = `4`, and 5 − 10 goes below zero and comes round to `251`. If the answer is the same as `+`, why have the function? For the **reader**. `AddWrapping` says "this wraps on purpose", so nobody mistakes the overflow for a bug — or "fixes" it. Hashes, checksums, random number generators and clock counters all want it. The program ends with one: a tiny multiplicative hash, where overflow is what mixes the bits together: ```rux let text = "Hello, World!"; var hash: uint32 = 17; for i in 0..text.length { hash = AddWrapping(MulWrapping(hash, 31), text[i] as uint32); } ``` Before the text is half done, the product outgrows 32 bits and wraps — as it is meant to. The final value, `1494227876`, is a fingerprint of the text: change a letter and the fingerprint changes. ## Saturating, at the limit `AddSaturating`, `SubSaturating` and `MulSaturating` stop at the nearest limit instead: ```rux PrintLine("saturating 250 + 10 = {}", AddSaturating(high, 10)); PrintLine("saturating 5 - 10 = {}", SubSaturating(low, 10)); PrintLine("saturating 200 * 2 = {}", MulSaturating(middle, 2)); ``` They give `255`, `0` and `255`. That suits a quantity with a natural ceiling and floor — a volume, a brightness, a health bar. Adding to the maximum keeps it at the maximum, and taking from zero leaves zero, instead of jumping to the other end of the range. A signed type saturates at whichever end it ran past: ```rux let cold: int8 = -100; let warm: int8 = 100; ``` | Operation on `int8` | Wrapping | Saturating | | ------------------- | -------- | ---------- | | −100 − 100 | 56 | −128 | | 100 + 100 | −56 | 127 | ## Choosing a policy Every integer operation that might overflow has four ways to go. Pick the one that says what you mean: ```mermaid flowchart LR q{"Can this result
overflow?"} -- "no, the values are small" --> plain["`+ - *`"] q -- "yes, and that is a bug" --> checked["`AddChecked` …
report it"] q -- "yes, it should go round" --> wrap["`AddWrapping` …"] q -- "yes, it should stop
at the limit" --> sat["`AddSaturating` …"] ``` ## Literals take the operand's type The functions are generic: the type comes from the arguments. In `AddWrapping(high, 10)` the `10` takes the type of the `uint8` beside it, so the sum is worked out in eight bits. With two plain literals the call would be made at `int` — and `AddWrapping(250, 10)` is a plain `260`. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Numbers/WrappingArithmetic){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // Sometimes overflow is not a mistake but the plan, and the only question is what it should // produce. `Core` names the two useful answers, at every integer width: // // AddWrapping, SubWrapping, MulWrapping wrap around, like a car's odometer // AddSaturating, SubSaturating, MulSaturating stop at the type's limit and stay there // // Wrapping computes exactly what `+`, `-` and `*` already do. The point of the name is the reader: // `AddWrapping` says "this wraps on purpose", so nobody mistakes it for a bug or "fixes" it. // Hashes, checksums and clock arithmetic all want it. // // Saturating suits quantities with a natural ceiling and floor, such as a volume control, a // brightness or a health bar: adding to the maximum keeps it at the maximum, and taking from zero // leaves zero, instead of jumping to the other end of the range. import Core::{ AddSaturating, AddWrapping, MulSaturating, MulWrapping, SubSaturating, SubWrapping }; import Io::PrintLine; func Main() -> int { // The same three uint8 sums, answered both ways. Unsuffixed literals take the type of the // `uint8` beside them; with two plain literals the call would be made at `int`. let high: uint8 = 250; let low: uint8 = 5; let middle: uint8 = 200; PrintLine("wrapping 250 + 10 = {}", AddWrapping(high, 10)); PrintLine("wrapping 5 - 10 = {}", SubWrapping(low, 10)); PrintLine("wrapping 200 * 2 = {}", MulWrapping(middle, 2)); PrintLine("saturating 250 + 10 = {}", AddSaturating(high, 10)); PrintLine("saturating 5 - 10 = {}", SubSaturating(low, 10)); PrintLine("saturating 200 * 2 = {}", MulSaturating(middle, 2)); PrintLine(""); // A signed type saturates at whichever end it ran past. let cold: int8 = -100; let warm: int8 = 100; PrintLine("int8 -100 - 100 wraps to {}, saturates at {}", SubWrapping(cold, 100), SubSaturating(cold, 100)); PrintLine("int8 100 + 100 wraps to {}, saturates at {}", AddWrapping(warm, 100), AddSaturating(warm, 100)); PrintLine(""); // Wrapping on purpose: a tiny multiplicative hash, where overflow mixes the bits. let text = "Hello, World!"; var hash: uint32 = 17; for i in 0..text.length { hash = AddWrapping(MulWrapping(hash, 31), text[i] as uint32); } PrintLine("hash of {} {}", text, hash); return 0; } ``` Besides `Io`, its `Rux.toml` lists `Core` under `[Dependencies]`. ## Run it ```sh cd Examples/Numbers/WrappingArithmetic rux run ``` ```text wrapping 250 + 10 = 4 wrapping 5 - 10 = 251 wrapping 200 * 2 = 144 saturating 250 + 10 = 255 saturating 5 - 10 = 0 saturating 200 * 2 = 255 int8 -100 - 100 wraps to 56, saturates at -128 int8 100 + 100 wraps to -56, saturates at 127 hash of Hello, World! 1494227876 ``` ## Common mistakes ::mistake **Calling with two plain literals.**:br`AddWrapping(250, 10)` is made at `int`, where nothing wraps, and returns `260`. Give one operand the type you mean, as the program does with `high`, `low` and `middle`. :: ::mistake **Expecting your own limit.**:br Saturation stops at the **type's** limits, not at the range your program has in mind. A `uint8` volume that should stop at 100 still goes up to 255 under `AddSaturating`. Use it for the floor at zero, and compare with your own maximum before adding. :: ::mistake **Wrapping where you meant modulo.**:br Wrapping goes round at the width of the type — 256 for a `uint8`, not 24 or 60. For clock hours, use `%`: `(hours + 5) % 24`. :: ## Try it yourself 1. A health bar is a `uint8`. Take 30 damage from 20 health with `SubWrapping` and then with `SubSaturating`. Which result would a game want? 2. Change the hash to start at 0 instead of 17, and hash `"ab"` and `"ba"`. Do they still differ? 3. Find the first `n` for which `MulWrapping` and `MulSaturating` disagree on `n * n` in a `uint8`. ## Learn more - [Arithmetic operations](https://rux-lang.dev/docs/lang/expressions/arithmetic) in the Rux Reference - [Checked arithmetic](https://rux-lang.dev/docs/learn/checked-arithmetic) — when overflow must be noticed - [Checked convert](https://rux-lang.dev/docs/learn/checked-convert) — `ConvertWrapping` and `ConvertSaturating` for conversions - [Hash](https://rux-lang.dev/docs/learn/hash) — real hash functions from the standard packages # Checked convert ::note **You'll need**: [Convert](https://rux-lang.dev/docs/learn/convert), [Checked arithmetic](https://rux-lang.dev/docs/learn/checked-arithmetic), [Optional](https://rux-lang.dev/docs/learn/optional), [Presence](https://rux-lang.dev/docs/learn/presence) :: `as` always produces a value of the new type, and says nothing when the old value did not fit: 300 as a `uint8` is quietly 44, and −1 is quietly 255. That is fine where the value is known to fit — and a hidden bug everywhere else. A count read from a file, a size passed in by a caller, a result of float arithmetic: none of these is known to fit. `Core::ConvertChecked` converts the same way **and** tells you whether anything was lost. ## Converting and checking It follows the out-parameter shape of [checked arithmetic](https://rux-lang.dev/docs/learn/checked-arithmetic). The converted value is written through a pointer — which also names the destination type — and the `bool` it returns is `true` when the value did not survive: ```rux var small: uint8 = 0; let fits = ConvertChecked(200, @small); let tooLarge = ConvertChecked(300, @small); let negative = ConvertChecked(-1, @small); ``` There is no type argument to write: the source type comes from the value, the destination type from the pointer. `@small` points at a `uint8`, so each call converts to `uint8`. | Source | Destination | Lost | Written | | ------ | ----------- | ------- | ------- | | `200` | `uint8` | `false` | 200 | | `300` | `uint8` | `true` | 44 | | `-1` | `uint8` | `true` | 255 | | `42.0` | `int32` | `false` | 42 | | `42.7` | `int32` | `true` | 42 | | `NaN` | `int32` | `true` | 0 | As with checked arithmetic, the pointer is written either way: the value written is what `as` would have produced. Check the flag before you trust it. ## Every way a value can be lost "Did not survive" covers every way a conversion can go wrong: - **Too large** for the destination: 300 into a `uint8`. - **Negative** into an unsigned type: −1 into a `uint8`. - **A fraction cut off**: 42.7 into an `int32` becomes 42, and the 0.7 counts as lost. 42.0 has no fraction, so it converts cleanly. - **NaN or an infinity**, which no integer can represent. ```rux var whole: int32 = 0; let exact = ConvertChecked(42.0, @whole); let fraction = ConvertChecked(42.7, @whole); let nan = ConvertChecked(float64::NaN, @whole); ``` ## Two relatives that decide for you Sometimes the right response to a value that does not fit is not to report it but to pick something. Two functions with the same shape do that, without returning a flag: - `ConvertWrapping` is `as` with a name that says the loss is intended — the counterpart of [wrapping arithmetic](https://rux-lang.dev/docs/learn/wrapping-arithmetic). - `ConvertSaturating` clamps to the nearest value the destination can hold. ```rux ConvertSaturating(300, @small); ConvertSaturating(-1, @small); ``` 300 becomes `255`, the largest `uint8`, and −1 becomes `0`, the smallest. ```mermaid flowchart LR v["A value that might
not fit the destination"] --> q{"What should happen
if it does not?"} q -- "it always fits" --> as["`as`"] q -- "tell me" --> c["`ConvertChecked`"] q -- "keep the low bits,
on purpose" --> w["`ConvertWrapping`"] q -- "use the nearest
value that fits" --> s["`ConvertSaturating`"] ``` ## Reporting it in a type As with `Area` in checked arithmetic, the flag and the pointer are best kept inside a function whose return type tells the caller what can happen: ```rux func ToByte(count: int32) -> uint8? { var result: uint8 = 0; let lost = ConvertChecked(count, @result); if lost { return none; } return result; } ``` `ToByte(99)` is `99`; `ToByte(999)` is `none`, and the caller cannot use a wrong byte without first deciding what `none` means. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Numbers/CheckedConvert){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // `as` always produces a value of the new type, and says nothing when the old value did not fit: // 300 as a `uint8` is quietly 44, and -1 is quietly 255. That is fine where the value is known to // fit, and a hidden bug everywhere else. `Core::ConvertChecked` converts the same way and also // tells you whether anything was lost. // // It follows the out-parameter shape of the checked arithmetic: the converted value is written // through a pointer, which also names the destination type, and the `bool` it returns is `true` // when the value did not survive. "Did not survive" covers every way a conversion can go wrong: // too large, negative into an unsigned type, a fraction cut off a float, and a NaN or infinity. // // Two relatives decide what to do with a value that does not fit, without reporting it. // `ConvertWrapping` is `as` with a name that says the loss is intended, and `ConvertSaturating` // clamps to the nearest value the destination can hold. import Core::{ ConvertChecked, ConvertSaturating, float64 }; import Io::PrintLine; // Turns a count into a byte, or `none` when it does not fit in one. func ToByte(count: int32) -> uint8? { var result: uint8 = 0; let lost = ConvertChecked(count, @result); if lost { return none; } return result; } func Main() -> int { var small: uint8 = 0; // Each source value, converted to `uint8` and checked. let fits = ConvertChecked(200, @small); PrintLine("200 -> uint8 lost {:5} value {}", fits, small); let tooLarge = ConvertChecked(300, @small); PrintLine("300 -> uint8 lost {:5} value {}", tooLarge, small); let negative = ConvertChecked(-1, @small); PrintLine("-1 -> uint8 lost {:5} value {}", negative, small); // From a float, the fraction counts as part of the value. var whole: int32 = 0; let exact = ConvertChecked(42.0, @whole); PrintLine("42.0 -> int32 lost {:5} value {}", exact, whole); let fraction = ConvertChecked(42.7, @whole); PrintLine("42.7 -> int32 lost {:5} value {}", fraction, whole); let nan = ConvertChecked(float64::NaN, @whole); PrintLine("NaN -> int32 lost {}", nan); PrintLine(""); // Saturating keeps the nearest value instead. ConvertSaturating(300, @small); PrintLine("300 saturated {}", small); ConvertSaturating(-1, @small); PrintLine("-1 saturated {}", small); PrintLine(""); // A checking function turns the report into a type. PrintLine("ToByte(99) {}", ToByte(99) ?? 0); match ToByte(999) { value? => PrintLine("ToByte(999) {}", value), none => PrintLine("ToByte(999) does not fit") } return 0; } ``` Besides `Io`, its `Rux.toml` lists `Core` under `[Dependencies]`. ## Run it ```sh cd Examples/Numbers/CheckedConvert rux run ``` ```text 200 -> uint8 lost false value 200 300 -> uint8 lost true value 44 -1 -> uint8 lost true value 255 42.0 -> int32 lost false value 42 42.7 -> int32 lost true value 42 NaN -> int32 lost true 300 saturated 255 -1 saturated 0 ToByte(99) 99 ToByte(999) does not fit ``` ## Common mistakes ::mistake **Reading the flag the wrong way round.**:br`true` means the value was **lost**. Name it after the problem — `lost`, `tooLarge` — so that `if lost { … }` reads correctly. :: ::mistake **A destination you cannot write.**:br The pointer must be writable. With `let small: uint8 = 0;`, `ConvertChecked(300, @small)` fails with: ```text error: argument 1 to 'ConvertChecked' has type 'int', but parameter 'value' requires 'From' ``` The message names the value, but the fix is to declare the destination with `var`. :: ::mistake **Expecting a float to round.**:br`ConvertChecked(42.7, @whole)` writes `42` and reports the value lost — it truncates, like `as`. If rounding is what you want, round first with `Round` from [Math](https://rux-lang.dev/docs/learn/math), then convert. :: ## Try it yourself 1. Convert `float64::Infinity` to an `int32` with `ConvertChecked`, and then with `ConvertSaturating`. What does each give? 2. Compare `ConvertWrapping(300, @small)` with `300 as uint8`. 3. Convert the integer 16777217 to a `float32` with `ConvertChecked`. Is anything lost? Look up why in [Float](https://rux-lang.dev/docs/learn/float). 4. Write `func ToPercent(ratio: float64) -> uint8?` that multiplies by 100 and returns `none` unless the result is a whole number from 0 to 100. ## Learn more - [Type casts](https://rux-lang.dev/docs/lang/expressions/casts) in the Rux Reference - [Convert](https://rux-lang.dev/docs/learn/convert) — what `as` does with a value that does not fit - [Checked arithmetic](https://rux-lang.dev/docs/learn/checked-arithmetic) — the same out-parameter shape for `+`, `-` and `*` - [Float special](https://rux-lang.dev/docs/learn/float-special) — NaN and infinity # Bit operation ::note **You'll need**: [Bitwise](https://rux-lang.dev/docs/learn/bitwise), [Shift](https://rux-lang.dev/docs/learn/shift) :: The bitwise operators **change** bits. A second family of functions, in `Core`, **answers questions** about them: how many are set, where the first and last set bit are, and what the value looks like turned around. They sound like curiosities and turn up everywhere — counting the flags set in a mask, finding how many bits a number needs, choosing the lowest free slot, mixing bits in a hash function. ## Counting bits | Function | Answers | | --------------- | --------------------------------------- | | `CountOnes` | How many bits are 1 | | `CountZeros` | How many bits are 0 | | `LeadingZeros` | How many 0 bits sit above the highest 1 | | `TrailingZeros` | How many 0 bits sit below the lowest 1 | | `IsPowerOfTwo` | Whether exactly one bit is set | The program asks all four counting questions about one byte: ```rux let value: uint8 = 0b0010_1100; PrintLine("CountOnes {}", CountOnes(value)); PrintLine("CountZeros {}", CountZeros(value)); PrintLine("LeadingZeros {}", LeadingZeros(value)); PrintLine("TrailingZeros {}", TrailingZeros(value)); ``` ```text bit: 7 6 5 4 3 2 1 0 0 0 1 0 1 1 0 0 └┬┘ └┬┘ 2 leading zeros 2 trailing zeros ``` Three ones, five zeros, two zeros above the highest one and two below the lowest. Counting from bit 0, `TrailingZeros` is also the **position** of the lowest 1 — here bit 2. ## The width matters Each function works across the full width of its argument's type, so the same number gives different answers in different types: ```rux let wide: uint32 = 44; PrintLine("as uint32 LeadingZeros {}", LeadingZeros(wide)); ``` 44 is the same `101100` either way, but a `uint32` has 24 more bits above it, so `LeadingZeros` is `26`, not `2`. `CountOnes` would not change; the zeros-counting functions do. That gives a neat way to ask how many bits a number really needs — its width minus the zeros above it: ```rux PrintLine("bits needed {}", uint8::Bits - LeadingZeros(value) as uint); ``` 44 needs `6` bits: 101100. ## Powers of two A power of two has exactly one bit set — 4096 is `1` followed by twelve zeros. `IsPowerOfTwo` checks that: ```rux let block: uint32 = 4096; PrintLine("4096 is power {}", IsPowerOfTwo(block)); PrintLine("44 is power {}", IsPowerOfTwo(wide)); ``` It matters because memory sizes, alignments and hash-table capacities are usually powers of two, and code that relies on one should check it. ## Rotating instead of shifting A shift drops the bits it pushes off the end. A **rotation** brings them round to the other side, so nothing is lost: ```rux let pattern: uint8 = 0b1001_0110; PrintLine("<< 3 {:08b}", pattern << 3); PrintLine("RotateLeft 3 {:08b}", RotateLeft(pattern, 3)); PrintLine("RotateRight 3 {:08b}", RotateRight(pattern, 3)); ``` ```mermaid flowchart LR p["`10010110`"] -- "shift left 3:
top 3 bits dropped" --> s["`10110000`"] p -- "rotate left 3:
top 3 bits wrap round" --> r["`10110100`"] ``` The shift lost the top three bits, `100`, and brought in zeros. The rotation moved those same three bits to the bottom. Every bit survives a rotation, so `CountOnes` is `4` before and after — which is what makes rotations useful for mixing bits in hashes without throwing any away. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Numbers/BitOperation){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // The bitwise operators change bits. A second family, in `Core`, answers questions about them: // how many are set, where the first and last set bit are, and what the value looks like turned // around. Each takes any integer type and works across its full width, so the same call gives a // different answer on a `uint8` than on a `uint32` holding the same number. // // CountOnes, CountZeros how many bits are 1, or 0 // LeadingZeros, TrailingZeros how many 0 bits sit above the highest 1, or below the // lowest 1 // RotateLeft, RotateRight a shift where the bits that fall off one end come back at // the other, so nothing is lost // // These sound like curiosities and turn up everywhere: counting the flags set in a mask, finding // how many bits a number needs, choosing the lowest free slot, and mixing bits in hash functions. import Core::{ CountOnes, CountZeros, IsPowerOfTwo, LeadingZeros, RotateLeft, RotateRight, TrailingZeros, uint8 }; import Io::PrintLine; func Main() -> int { let value: uint8 = 0b0010_1100; PrintLine("value {:08b} ({})", value, value); PrintLine("CountOnes {}", CountOnes(value)); PrintLine("CountZeros {}", CountZeros(value)); PrintLine("LeadingZeros {}", LeadingZeros(value)); // Counting from bit 0, TrailingZeros is also the position of the lowest 1. PrintLine("TrailingZeros {}", TrailingZeros(value)); PrintLine(""); // The width matters: the same number in 32 bits has 24 more leading zeros. let wide: uint32 = 44; PrintLine("as uint32 LeadingZeros {}", LeadingZeros(wide)); // How many bits a number needs: its width minus the zeros above it. PrintLine("bits needed {}", uint8::Bits - LeadingZeros(value) as uint); // A power of two has exactly one bit set. let block: uint32 = 4096; PrintLine("4096 is power {}", IsPowerOfTwo(block)); PrintLine("44 is power {}", IsPowerOfTwo(wide)); PrintLine(""); // A shift drops the bits it pushes off the end; a rotation brings them round to the other side. let pattern: uint8 = 0b1001_0110; PrintLine("pattern {:08b}", pattern); PrintLine("<< 3 {:08b}", pattern << 3); PrintLine("RotateLeft 3 {:08b}", RotateLeft(pattern, 3)); PrintLine("RotateRight 3 {:08b}", RotateRight(pattern, 3)); PrintLine("ones survive {} and {}", CountOnes(pattern), CountOnes(RotateLeft(pattern, 3))); return 0; } ``` Besides `Io`, its `Rux.toml` lists `Core` under `[Dependencies]`. ## Run it ```sh cd Examples/Numbers/BitOperation rux run ``` ```text value 00101100 (44) CountOnes 3 CountZeros 5 LeadingZeros 2 TrailingZeros 2 as uint32 LeadingZeros 26 bits needed 6 4096 is power true 44 is power false pattern 10010110 << 3 10110000 RotateLeft 3 10110100 RotateRight 3 11010010 ones survive 4 and 4 ``` ## Common mistakes ::mistake **Passing a plain literal.**:br An unsuffixed literal is an `int`, 64 bits wide. `LeadingZeros(44)` is therefore `58`, not `2`. Give the value the type whose width you mean: `let value: uint8 = 44;`. :: ::mistake **Forgetting zero.**:br Zero has no 1 bit, so it has no "lowest 1" to find. `TrailingZeros` and `LeadingZeros` of a `uint8` zero are both `8`, the full width, and `IsPowerOfTwo` of zero is `false`. Check for zero first when the answer is used as a position. :: ## Try it yourself 1. A `uint8` mask records which of eight seats are taken. Find the lowest free seat with `TrailingZeros(~taken)`. What happens when every seat is taken? 2. How many bits does 1000 need? Work it out with a `uint16` and `LeadingZeros`. 3. Rotate a `uint8` left by 8. Why is the result the value you started with? 4. Import `ReverseBits` from `Core` and print `0b0010_1100` reversed. ## Learn more - [Bitwise operations](https://rux-lang.dev/docs/lang/expressions/bitwise) and [shift operations](https://rux-lang.dev/docs/lang/expressions/shift) in the Rux Reference - [Bitwise](https://rux-lang.dev/docs/learn/bitwise) and [Shift](https://rux-lang.dev/docs/learn/shift) — the operators these functions complement - [Number limit](https://rux-lang.dev/docs/learn/number-limit) — `Bits` and the other constants every type carries - [Hash](https://rux-lang.dev/docs/learn/hash) — where rotations earn their keep # Endian ::note **You'll need**: [Pointer](https://rux-lang.dev/docs/learn/pointer), [Out parameter](https://rux-lang.dev/docs/learn/out-parameter), [Slice](https://rux-lang.dev/docs/learn/slice), [Shift](https://rux-lang.dev/docs/learn/shift) :: An integer wider than one byte is stored as several bytes, and something has to decide their order. There are two conventions: - **Little endian** puts the least significant byte first. - **Big endian** puts the most significant byte first — the order the number is written in. Today's desktop processors are little endian, while network protocols and many file formats are big endian. So a program that reads or writes bytes — to a file, a socket, a packet — has to say which order it means, rather than take whatever the machine happens to do. Otherwise the same file means different numbers on different machines. ## One value, two orders The program picks a value whose four bytes are all different, so the order is easy to see: ```rux let value: uint32 = 0x12345678; ``` | Order | Byte 0 | Byte 1 | Byte 2 | Byte 3 | | ------------- | ------ | ------ | ------ | ------ | | Big endian | `12` | `34` | `56` | `78` | | Little endian | `78` | `56` | `34` | `12` | Big endian reads like the hexadecimal you wrote; little endian starts at the small end. ## Writing bytes in a chosen order `Core` has a function for each direction and each order: | Function | Does | | ------------------- | ------------------------------------------------------ | | `StoreBigEndian` | Write a value into bytes, most significant first | | `StoreLittleEndian` | Write a value into bytes, least significant first | | `LoadBigEndian` | Read a value back out of big-endian bytes | | `LoadLittleEndian` | Read a value back out of little-endian bytes | | `ReverseBytes` | Swap a value's bytes, turning one order into the other | They work through [pointers](https://rux-lang.dev/docs/learn/pointer). A store writes from a pointer to the **first byte** onwards, as many bytes as the value's type has: ```rux var little: uint8[4]; var big: uint8[4]; StoreLittleEndian(value, @little[0]); StoreBigEndian(value, @big[0]); ``` `@little[0]` is a pointer to the first element. A `uint32` is four bytes, so each store fills the whole array. ```mermaid flowchart LR v["`uint32` `0x12345678`"] -- "`StoreBigEndian`" --> b["`12 34 56 78`"] v -- "`StoreLittleEndian`" --> l["`78 56 34 12`"] ``` `TargetIsLittleEndian()` tells you which order this machine uses itself — the program prints `true` on an ordinary desktop. You rarely need it: the store and load functions give the same bytes on every machine, which is the point. ## Reading bytes back A load reads from a pointer to the first byte and hands the value back through an [out-parameter](https://rux-lang.dev/docs/learn/out-parameter). Here are two bytes from a network packet, where a port number is big endian: ```rux let packet: uint8[2] = [0x01, 0xBB]; var port: uint16 = 0; LoadBigEndian(@packet[0], @port); ``` `0x01BB` is `443`, the HTTPS port. The type of `port` decides how many bytes are read — two for a `uint16`. ## The order is part of the data Bytes written big endian must be read big endian, on every machine. Read the same two bytes in the wrong order and you get a different number entirely: ```rux PrintLine("wrong order {}", ReverseBytes(port)); ``` `0xBB01` is `47873`. Nothing fails — the bytes are just misread. That is why a file format or protocol always says which order it uses, and why code that reads one should name that order explicitly. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Numbers/Endian){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // An integer wider than one byte is stored as several bytes, and something has to decide their // order. Little endian puts the least significant byte first; big endian puts the most significant // first, the order the number is written in. Today's desktop processors are little endian, while // network protocols and many file formats are big endian, so a program that reads or writes bytes // has to say which order it means rather than take whatever the machine does. // // `Core` provides both directions for any integer type: // // StoreBigEndian, StoreLittleEndian write a value into bytes, in the order named // LoadBigEndian, LoadLittleEndian read a value back out of bytes // ReverseBytes swap a value's bytes, turning one order into the other // // They work through pointers, as in the Memory part: a store writes from a pointer to the first // byte onwards, and a load reads from one and hands the value back through an out-parameter. // The order is part of the data: bytes written big endian must be read big endian, on every // machine. import Core::{ LoadBigEndian, ReverseBytes, StoreBigEndian, StoreLittleEndian, TargetIsLittleEndian }; import Io::{ Print, PrintLine }; func ShowBytes(label: char8[..], bytes: uint8[..]) { Print("{}", label); for i in 0..bytes.length { Print(" {:02x}", bytes[i]); } PrintLine(); } func Main() -> int { PrintLine("this machine is little endian: {}", TargetIsLittleEndian()); // One value with four distinct bytes, so the order is easy to see. let value: uint32 = 0x12345678; PrintLine("value {:#x}", value); var little: uint8[4]; var big: uint8[4]; StoreLittleEndian(value, @little[0]); StoreBigEndian(value, @big[0]); ShowBytes("little endian ", little[..]); ShowBytes("big endian ", big[..]); // Reversing the bytes turns one order into the other. PrintLine("ReverseBytes {:#x}", ReverseBytes(value)); PrintLine(""); // Reading: two bytes from a network packet, where a port number is big endian. let packet: uint8[2] = [0x01, 0xBB]; var port: uint16 = 0; LoadBigEndian(@packet[0], @port); PrintLine("port {}", port); // The same bytes read in the wrong order give a different number entirely. PrintLine("wrong order {}", ReverseBytes(port)); return 0; } ``` Besides `Io`, its `Rux.toml` lists `Core` under `[Dependencies]`. ## Run it ```sh cd Examples/Numbers/Endian rux run ``` ```text this machine is little endian: true value 0x12345678 little endian 78 56 34 12 big endian 12 34 56 78 ReverseBytes 0x78563412 port 443 wrong order 47873 ``` ## Common mistakes ::mistake **Pointing at the whole array.**:br The functions want a pointer to the first byte, not to the array. `StoreBigEndian(value, @big)` fails with: ```text error: argument 1 to 'StoreBigEndian' has type 'uint32', but parameter 'value' requires 'T' ``` The message names the value, but the fix is the pointer: `@big[0]`. :: ::mistake **Storing an untyped literal.**:br The value's type decides how many bytes are written. `StoreBigEndian(0x12345678, @x[0])` stores an `int` — eight bytes, not four — and a four-byte array has no room for them. Store a typed value, such as the program's `let value: uint32`. :: ::mistake **Relying on the machine's order.**:br Writing a number's memory straight to a file works until the file is read on a machine of the other order. Choose an order for the data and use the matching `Store…` and `Load…` functions, whatever `TargetIsLittleEndian()` says. :: ## Try it yourself 1. Store the `uint16` `0xBEEF` both ways and print the bytes with `ShowBytes`. 2. Store `value` big endian, then read it back with `LoadLittleEndian`. Which number do you get — and which function gives the same answer without any bytes? 3. Store the `uint64` `1` big endian into a `uint8[8]` and print the bytes. Where did the `01` go? ## Learn more - [Pointer](https://rux-lang.dev/docs/learn/pointer) and [Out-parameter](https://rux-lang.dev/docs/learn/out-parameter) — the pointers these functions work through - [Shift](https://rux-lang.dev/docs/learn/shift) — taking a number apart byte by byte by hand - [Binary](https://rux-lang.dev/docs/learn/binary) — reading and writing binary files - [Pointers](https://rux-lang.dev/docs/lang/pointers/overview) in the Rux Reference # Math ::note **You'll need**: [Float](https://rux-lang.dev/docs/learn/float), [Float special](https://rux-lang.dev/docs/learn/float-special), [Function](https://rux-lang.dev/docs/learn/function) :: The arithmetic operators stop at the four operations. Square roots, powers, logarithms, angles and rounding live in the `Math` package, as functions on `float64` — with `float32` versions of each, chosen by the type of the argument. Two things are true of all of them, and both matter more than any single function. Every one has a **domain** — the inputs it has an answer for — and outside it the answer is a special value, not an error. And every answer is a float: the nearest float to the true answer, not the answer itself. The program imports what it uses, and lists `Math` as a dependency: ```rux import Math::{ Abs, Cbrt, Ceil, Cos, DegToRad, Exp, Floor, Log, Log10, Log2, Pi, Pow, Round, Sin, Sqrt, Trunc }; ``` ## Roots and powers ```rux PrintLine("Sqrt(2) {}", Sqrt(2.0)); PrintLine("Cbrt(-8) {}", Cbrt(-8.0)); PrintLine("Pow(2, 10) {}", Pow(2.0, 10.0)); PrintLine("Sqrt(-1) {}", Sqrt(-1.0)); ``` `Sqrt` wants a number that is not negative; `Cbrt`, the cube root, takes any sign, so `Cbrt(-8.0)` is `-2.0`. `Pow(x, y)` is x to the power y. And `Sqrt(-1.0)` is outside the square root's domain: the answer is `NaN`, as in [Float special](https://rux-lang.dev/docs/learn/float-special), and the program carries on. Notice the arguments are written `2.0`, not `2`. The functions take floats, and an integer is not converted on its own. ## Logarithms ```rux PrintLine("Log(Exp(1)) {}", Log(Exp(1.0))); PrintLine("Log2(1024) {}", Log2(1024.0)); PrintLine("Log10(0.001) {}", Log10(0.001)); PrintLine("Log(0) {}", Log(0.0)); ``` `Log` is the natural logarithm, base *e*, and the inverse of `Exp`; the others say their base in their name. `Log2(1024.0)` is `10.0` because 2¹⁰ = 1024. Logarithms want a number greater than zero, and `Log(0.0)` is `-Inf`. | Function | Wants | Outside the domain | | ---------------------- | ----- | ------------------------ | | `Sqrt` | x ≥ 0 | `NaN` | | `Cbrt` | any x | — | | `Log`, `Log2`, `Log10` | x > 0 | `-Inf` at 0, `NaN` below | Check the input first when it might fall outside — a `NaN` produced deep inside a calculation is much harder to trace than an `if` before it. ## Angles Trigonometry works in **radians**, where a half turn is `Pi`. `DegToRad` converts from degrees: ```rux PrintLine("Sin(30 deg) {}", Sin(DegToRad(30.0))); PrintLine("Cos(60 deg) {}", Cos(DegToRad(60.0))); PrintLine("Sin(Pi) {}", Sin(Pi)); ``` On paper, sin 30° and cos 60° are both exactly ½, and sin π is exactly 0. The program prints `0.49999999999999994`, `0.5000000000000001` and `1.2246467991473532e-16`. Nothing is wrong: `Pi` is the nearest `float64` to π, not π itself, and every step rounds to the nearest float. So a float result is compared **within a tolerance**, never with `==`: ```rux let tolerance = 1e-9; PrintLine("Sin(Pi) is 0? {}", Abs(Sin(Pi)) < tolerance); ``` ## Rounding, in four senses "Round" can mean four different things. They agree on most positive numbers and part ways on negative ones — which is where a program usually finds out it chose the wrong one: ```rux let value = -2.5; PrintLine("Floor(-2.5) {} towards minus infinity", Floor(value)); PrintLine("Ceil(-2.5) {} towards plus infinity", Ceil(value)); PrintLine("Trunc(-2.5) {} towards zero", Trunc(value)); PrintLine("Round(-2.5) {} to nearest, halves away from zero", Round(value)); ``` | Function | Rounds | 2.5 | −2.5 | | -------- | --------------------------------- | --- | ---- | | `Floor` | down, towards minus infinity | 2.0 | −3.0 | | `Ceil` | up, towards plus infinity | 3.0 | −2.0 | | `Trunc` | towards zero | 2.0 | −2.0 | | `Round` | to nearest, halves away from zero | 3.0 | −3.0 | All four return a float. `Trunc` is what `as` does when it converts a float to an integer; to round to the nearest whole number, `Round` first and convert after. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Numbers/Math){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // The arithmetic operators stop at the four operations. Roots, powers, logarithms, angles and // rounding live in the `Math` package, as functions on `float64` (with `float32` versions too). // // Every one of them has a domain, the inputs it has an answer for, and outside it the answer is // one of the special values from FloatSpecial rather than an error: `Sqrt(-1)` is NaN, `Log(0)` is // minus infinity. Check the input first when it might fall outside. // // And every answer is a float, so it is the nearest float to the true answer, not the answer // itself. `Sin(Pi)` is not 0, because `Pi` is not exactly pi. Compare results with a tolerance, // never with `==`. import Io::PrintLine; import Math::{ Abs, Cbrt, Ceil, Cos, DegToRad, Exp, Floor, Log, Log10, Log2, Pi, Pow, Round, Sin, Sqrt, Trunc }; func Main() -> int { // Roots and powers. Sqrt wants x >= 0; Cbrt takes any sign. PrintLine("Sqrt(2) {}", Sqrt(2.0)); PrintLine("Cbrt(-8) {}", Cbrt(-8.0)); PrintLine("Pow(2, 10) {}", Pow(2.0, 10.0)); PrintLine("Sqrt(-1) {}", Sqrt(-1.0)); PrintLine(""); // Logarithms want x > 0. `Log` is the natural one; the others say their base. PrintLine("Log(Exp(1)) {}", Log(Exp(1.0))); PrintLine("Log2(1024) {}", Log2(1024.0)); PrintLine("Log10(0.001) {}", Log10(0.001)); PrintLine("Log(0) {}", Log(0.0)); PrintLine(""); // Trigonometry works in radians, where a half turn is Pi. DegToRad converts from degrees. PrintLine("Sin(30 deg) {}", Sin(DegToRad(30.0))); PrintLine("Cos(60 deg) {}", Cos(DegToRad(60.0))); PrintLine("Sin(Pi) {}", Sin(Pi)); // So a float result is compared within a tolerance. let tolerance = 1e-9; PrintLine("Sin(Pi) is 0? {}", Abs(Sin(Pi)) < tolerance); PrintLine(""); // Rounding, in its four senses. They differ on negative numbers, which is where a program // usually finds out it chose the wrong one. let value = -2.5; PrintLine("Floor(-2.5) {} towards minus infinity", Floor(value)); PrintLine("Ceil(-2.5) {} towards plus infinity", Ceil(value)); PrintLine("Trunc(-2.5) {} towards zero", Trunc(value)); PrintLine("Round(-2.5) {} to nearest, halves away from zero", Round(value)); return 0; } ``` Besides `Io`, its `Rux.toml` lists `Math` under `[Dependencies]`. ## Run it ```sh cd Examples/Numbers/Math rux run ``` ```text Sqrt(2) 1.4142135623730951 Cbrt(-8) -2.0 Pow(2, 10) 1024.0 Sqrt(-1) NaN Log(Exp(1)) 1.0 Log2(1024) 10.0 Log10(0.001) -3.0 Log(0) -Inf Sin(30 deg) 0.49999999999999994 Cos(60 deg) 0.5000000000000001 Sin(Pi) 1.2246467991473532e-16 Sin(Pi) is 0? true Floor(-2.5) -3.0 towards minus infinity Ceil(-2.5) -2.0 towards plus infinity Trunc(-2.5) -2.0 towards zero Round(-2.5) -3.0 to nearest, halves away from zero ``` ## Common mistakes ::mistake **Passing an integer.**:br`Sqrt(2)` fails with: ```text error: no matching overload for 'Sqrt' with argument types (int) ``` The notes list the two candidates, `Sqrt(x: float32)` and `Sqrt(x: float64)`. Write `2.0`, or convert a variable with `as float64`. :: ::mistake **Giving degrees to a function that wants radians.**:br`Sin(30.0)` is the sine of 30 radians, about `-0.988`, not ½. Convert first: `Sin(DegToRad(30.0))`. :: ::mistake **Comparing a result with `==`.**:br`Cos(DegToRad(60.0)) == 0.5` is `false`, because the result is `0.5000000000000001`. Compare the difference with a tolerance: `Abs(result - 0.5) < 1e-9`. :: ## Try it yourself 1. Import `Hypot` and work out the hypotenuse of a 3–4–5 triangle. 2. Convert `Pi` back to degrees with `RadToDeg`. 3. Round −2.4 and −2.6 to the nearest whole number and convert them to `int32`. Then do the same with `as` alone and compare. 4. Call `Sqrt(2.0f32)`. How many digits does the `float32` version print? ## Learn more - The [Math API](https://rux-lang.dev/docs/api/math) — every function, including [Sqrt](https://rux-lang.dev/docs/api/math/powers#sqrt), [Pow](https://rux-lang.dev/docs/api/math/powers#pow) and [Round](https://rux-lang.dev/docs/api/math/rounding#round) - [Float special](https://rux-lang.dev/docs/learn/float-special) — the NaN and infinities these functions return outside their domain - [Convert](https://rux-lang.dev/docs/learn/convert) — why `as` truncates instead of rounding - [Circle](https://rux-lang.dev/docs/learn/circle) and [Quadratic](https://rux-lang.dev/docs/learn/quadratic) — checkpoint projects that put these functions to work # Complex ::note **You'll need**: [Math](https://rux-lang.dev/docs/learn/math), [Operator overload](https://rux-lang.dev/docs/learn/operator-overload), [Format number](https://rux-lang.dev/docs/learn/format-number) :: [Math](https://rux-lang.dev/docs/learn/math) ended with `Sqrt(-1)` giving NaN: no real number squares to a negative one. That is why `x * x + 2 * x + 5 = 0` has no real solution, and why a program that solves quadratics has to stop there, or work the answer out by hand. **Complex numbers** add the missing square root, `i`, with `i * i = -1`, and with it every quadratic has its two roots. They are more than a trick for quadratics. A complex number is also a point in the plane, and multiplying by one turns and stretches — which is why electrical engineering, signal processing and graphics use them all the time. ```rux import Math::{ Complex, DegToRad, Pi, RadToDeg }; ``` ## A pair of floats A `Complex` is `real + imaginary·i`, held as two public `float64` fields, `real` and `imaginary`. `Complex::New` makes one, and `Complex32` is the same over `float32`. The type defines the four [operators](https://rux-lang.dev/docs/learn/operator-overload), so complex arithmetic reads like any other: ```rux let a = Complex::New(3.0, 4.0); let b = Complex::New(1.0, -2.0); Show("a + b", a + b); Show("a * b", a * b); Show("a / b", a / b); ``` Multiplying works out the brackets and uses `i * i = -1`: `(3 + 4i)(1 - 2i) = 3 - 6i + 4i + 8 = 11 - 2i`. Both sides of an operator must be `Complex`; to multiply by a plain float, use `Scale`. | Method | Gives | For `3 + 4i` | | ------------- | --------------------------------------- | ------------ | | `Conjugate()` | the imaginary part's sign flipped | `3 - 4i` | | `Negate()` | both signs flipped | `-3 - 4i` | | `Scale(2.0)` | both parts times a float | `6 + 8i` | | `Abs()` | the magnitude: the length of the arrow | `5` | | `Norm()` | the magnitude squared | `25` | | `Arg()` | the angle, in radians, between −π and π | `0.927…` | A `Complex` does not implement [Display](https://rux-lang.dev/docs/learn/display), so the program has a `Show` function that prints `a + bi` or `a - bi` with three decimals. ## Length and angle Draw `3 + 4i` as an arrow from the origin to the point `(3, 4)`. Its length is `Abs()`, and its direction is `Arg()`, the angle from the positive real axis, in radians: ```rux PrintLine("{:<14} {:.3}", "magnitude", a.Abs()); PrintLine("{:<14} {:.3} degrees", "angle", RadToDeg(a.Arg())); ``` That is the **polar form**: 5 long, at about 53.13°. `FromPolar(length, angle)` goes the other way, so `FromPolar(2.0, DegToRad(60.0))` is `1 + 1.732i`. The polar form explains multiplication. Multiplying two complex numbers multiplies their lengths and **adds their angles**. `i` is 1 long at 90°, so multiplying by `i` turns a number a quarter turn anticlockwise and leaves its length alone: ```mermaid flowchart LR a["`3 + 4i`
length 5, 53.13°"] -- "times `i`
length 1, 90°" --> t["`-4 + 3i`
length 5, 143.13°"] ``` ## Solving a quadratic The quadratic formula needs the square root of the discriminant, `q * q - 4 * p * r`. For `x² + 2x + 5` that is `-16`, and the real `Sqrt` gives NaN. Made complex, `-16` has the square root `4i`: ```rux let root = Complex::New(q * q - 4.0 * p * r, 0.0).Sqrt(); let first = (Complex::New(-q, 0.0) + root).Scale(1.0 / (2.0 * p)); let second = (Complex::New(-q, 0.0) - root).Scale(1.0 / (2.0 * p)); ``` The roots are `-1 + 2i` and `-1 - 2i`. They come as a **conjugate pair**, as the roots of every quadratic with real coefficients do. Putting one back into the equation gives zero. `Sqrt`, like `Exp`, `Log` and `Pow`, returns the **principal** value: of the two square roots of `-16`, `4i` and `-4i`, it picks the one with a positive real part, or on the imaginary axis the one above zero. That is why the formula adds and subtracts it. ## Rounding still applies Euler's identity says `e^(iπ) = -1`, and `Exp` agrees — almost. The imaginary part comes out as about `1.22e-16`, because `Pi` is only the nearest `float64` to π. Every float caveat from [Math](https://rux-lang.dev/docs/learn/math) carries over: compare complex results part by part, within a tolerance. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Numbers/Complex){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // No real number squares to -1, so `x * x + 1 = 0` has no real solution. Complex numbers add // one: `i`, with `i * i = -1`. A complex number is a pair, `real + imaginary·i`, and with it // every quadratic has its two roots, and a rotation in the plane becomes a multiplication. // // The Math package's `Complex` holds the pair as two `float64` fields, `real` and `imaginary`, // and gives it the four operators, so complex arithmetic is written as ordinary arithmetic. // (`Complex32` is the same over `float32`.) // // The pair can also be read as a point in the plane, or as an arrow from the origin to it. The // arrow's length is the magnitude, `Abs()`, and its direction is the angle, `Arg()`, measured in // radians from the positive real axis. `FromPolar` builds a number from those two instead. import Io::PrintLine; import Math::{ Complex, DegToRad, Pi, RadToDeg }; // A Complex does not implement Display, so `PrintLine("{}", a)` is refused: // // error: no matching overload for 'PrintLine' with argument types (char8[..], Complex) // // This writes it as `a + bi` or `a - bi` instead. func Show(label: char8[..], z: Complex) { if z.imaginary < 0.0 { PrintLine("{:<14} {:.3} - {:.3}i", label, z.real, -z.imaginary); } else { PrintLine("{:<14} {:.3} + {:.3}i", label, z.real, z.imaginary); } } func Main() -> int { // Arithmetic. Multiplying uses i·i = -1: (3 + 4i)(1 - 2i) = 3 - 6i + 4i + 8 = 11 - 2i. let a = Complex::New(3.0, 4.0); let b = Complex::New(1.0, -2.0); Show("a + b", a + b); Show("a * b", a * b); Show("a / b", a / b); Show("conjugate a", a.Conjugate()); // The operators take a Complex on both sides; a plain float is refused: // // error: operator '*' cannot combine left operand 'Complex' with right operand 'float64' // // `Scale` multiplies by a real number instead. Show("a scaled by 2", a.Scale(2.0)); // Polar form: 3 + 4i is 5 long and points about 53 degrees above the real axis. PrintLine("{:<14} {:.3}", "magnitude", a.Abs()); PrintLine("{:<14} {:.3} degrees", "angle", RadToDeg(a.Arg())); // Multiplying by i turns a number a quarter turn anticlockwise, keeping its length. let i = Complex::New(0.0, 1.0); let turned = a * i; Show("a * i", turned); PrintLine("{:<14} {:.3}, {:.3} degrees", "turned polar", turned.Abs(), RadToDeg(turned.Arg())); // `FromPolar` goes the other way: length 2 at 60 degrees. Show("polar 2, 60", Complex::FromPolar(2.0, DegToRad(60.0))); // x^2 + 2x + 5 = 0. The discriminant, 4 - 20, is negative, so the real square root would be // NaN; the complex one is 4i, and the two roots are -1 + 2i and -1 - 2i. let p = 1.0; let q = 2.0; let r = 5.0; let root = Complex::New(q * q - 4.0 * p * r, 0.0).Sqrt(); let first = (Complex::New(-q, 0.0) + root).Scale(1.0 / (2.0 * p)); let second = (Complex::New(-q, 0.0) - root).Scale(1.0 / (2.0 * p)); Show("first root", first); Show("second root", second); // Putting a root back in gives zero, as far as floats allow. let check = first * first + first.Scale(q) + Complex::New(r, 0.0); Show("check", check); // Euler's identity, e^(i·pi) = -1. The imaginary part comes out as about 1.2e-16, not 0, // because `Pi` is only the nearest float to pi; at three places it shows as 0.000. let euler = Complex::New(0.0, Pi).Exp(); Show("e^(i pi)", euler); PrintLine("{:<14} {}", "imaginary part", euler.imaginary); return 0; } ``` Besides `Io`, its `Rux.toml` lists `Math` under `[Dependencies]`. ## Run it ```sh cd Examples/Numbers/Complex rux run ``` ```text a + b 4.000 + 2.000i a * b 11.000 - 2.000i a / b -1.000 + 2.000i conjugate a 3.000 - 4.000i a scaled by 2 6.000 + 8.000i magnitude 5.000 angle 53.130 degrees a * i -4.000 + 3.000i turned polar 5.000, 143.130 degrees polar 2, 60 1.000 + 1.732i first root -1.000 + 2.000i second root -1.000 - 2.000i check 0.000 + 0.000i e^(i pi) -1.000 + 0.000i imaginary part 1.2246467991473532e-16 ``` ## Common mistakes ::mistake **Mixing a `Complex` and a float in one operator.**:br`a * 2.0` fails with: ```text error: operator '*' cannot combine left operand 'Complex' with right operand 'float64' ``` Use `a.Scale(2.0)`, or make the float complex: `a * Complex::New(2.0, 0.0)`. :: ::mistake **Integers for the parts.**:br`Complex::New(3, 4)` fails with: ```text error: argument 1 to 'Complex::New' has type 'int', but parameter 'real' requires 'float64' ``` Write the parts as floats: `Complex::New(3.0, 4.0)`. :: ::mistake **Printing with `{}`.**:br`PrintLine("{}", a)` fails with: ```text error: no matching overload for 'PrintLine' with argument types (char8[..], Complex) ``` Print the `real` and `imaginary` fields, as `Show` does. :: ::mistake **Comparing results with `==`.**:br`euler == Complex::New(-1.0, 0.0)` compiles, and is `false`: the imaginary part is `1.22e-16`, not zero. Compare each part within a tolerance, as for any float. :: ::mistake **Degrees for `FromPolar` and `Arg`.**:br Both work in radians. `FromPolar(2.0, 60.0)` is 60 radians, nearly ten turns. Convert with `DegToRad` and `RadToDeg`. :: ## Try it yourself 1. Solve `x² - 2x + 5 = 0` and `x² - 5x + 6 = 0`. What does the second give for the imaginary parts? 2. Multiply `a` by `i` four times in a loop, printing each result. Where does it end up? 3. Print the twelve points `FromPolar(1.0, DegToRad(30.0 * k))` for `k` from 0 to 11 — the twelve hours of a clock face. 4. Write `Close(left: Complex, right: Complex) -> bool`, true when both parts differ by less than `1e-9`, and use it to check that `euler` is `-1`. ## Learn more - [Math](https://rux-lang.dev/docs/learn/math) — the real functions, and their domains - [Operator overload](https://rux-lang.dev/docs/learn/operator-overload) — how a type gets its own `+` and `*` - [Float special](https://rux-lang.dev/docs/learn/float-special) — the NaN that a real square root of a negative number gives - [Quadratic](https://rux-lang.dev/docs/learn/quadratic) — a checkpoint project that reads a quadratic and works out its complex roots by hand - [Math](https://rux-lang.dev/docs/api/math) in the API reference - [Floating-point types](https://rux-lang.dev/docs/lang/types/floating-point) and [Operators](https://rux-lang.dev/docs/lang/interfaces/operators) in the Rux Reference # Part 17: Collections Until now every sequence had a length fixed while compiling. Real data rarely does: lines read from a file, orders placed today, words in a text. This part introduces the containers of the `Collections` package, which hold as many values as arrive and manage their own memory through an allocator. By the end you will know eleven of them, what each is quick and slow at, and which to reach for. ## What you will learn - `Vector`, the growable sequence, and the difference between its length and its capacity. - `Array`, a sequence whose length is chosen at run time and then fixed. - `Deque`, quick at both ends — the natural queue. - `HashMap` and `HashSet`: lookup by key and membership tests in about constant time, with no order. - `TreeMap` and `TreeSet`: the same, kept sorted, with ordered questions such as `Floor`, `Ceiling` and `Range`. - `PriorityQueue`, which always hands out its largest element next, by the element's own `<`. - `BitSet`, a set of small integers at one bit each, with union, intersection and difference a word at a time. - `SmallVector`, a vector that keeps its first few elements inside itself and allocates only past them. - `LruCache`, a map of bounded size that forgets the entry used least recently. - The pattern every collection shares: made from an allocator, fallible where it needs memory, optional where a value may be missing, and freed by its destructor. ## Which collection? ```mermaid flowchart LR q{"How do you find
a value again?"} -- "by position" --> pos{"How does the
length change?"} pos -- "never — known
while compiling" --> inline["Inline array
`T[n]`"] pos -- "never — known
only at run time" --> arr["`Array`"] pos -- "values come and go
at the end" --> vec["`Vector`"] pos -- "values come and go
at both ends" --> dq["`Deque`"] q -- "by key" --> korder{"Do the keys need
to stay in order?"} korder -- "no" --> hm["`HashMap`"] korder -- "yes" --> tm["`TreeMap`"] q -- "only: is it here?" --> sorder{"Do the members need
to stay in order?"} sorder -- "no" --> hs["`HashSet`"] sorder -- "yes" --> ts["`TreeSet`"] ``` When in doubt, start with a `Vector` for a list and a `HashMap` for lookups. Switch to a `Deque` when values join at the front, and to a tree when the order of the keys is part of the answer. The last four lessons are specialists, each the better choice for one particular job: | When you need… | Reach for | Instead of | | ------------------------------------------------ | --------------- | ---------------------------- | | always the most urgent item next | `PriorityQueue` | sorting a `Vector` each time | | a set of small integers, and fast set operations | `BitSet` | a `HashSet` of numbers | | many short lists, without an allocation each | `SmallVector` | a `Vector` | | a lookup table that must not grow without limit | `LruCache` | a `HashMap` | ## Lessons | | Lesson | What you will learn | | ----- | ---------------------------------------------------------------- | -------------------------------------------------------------- | | 17.1 | [Vector](https://rux-lang.dev/docs/learn/vector) | a growable array that manages its own memory and capacity | | 17.2 | [Dynamic array](https://rux-lang.dev/docs/learn/dynamic-array) | `Collections::Array`, and how it differs from an inline array | | 17.3 | [Deque](https://rux-lang.dev/docs/learn/deque) | add and remove at both ends, and see where that beats a vector | | 17.4 | [Hash map](https://rux-lang.dev/docs/learn/hash-map) | look values up by key | | 17.5 | [Hash set](https://rux-lang.dev/docs/learn/hash-set) | test membership with a hash set | | 17.6 | [Tree map](https://rux-lang.dev/docs/learn/tree-map) | keep keys in order, and walk them in order | | 17.7 | [Tree set](https://rux-lang.dev/docs/learn/tree-set) | keep a set of values in order | | 17.8 | [Priority queue](https://rux-lang.dev/docs/learn/priority-queue) | always take the most urgent item next | | 17.9 | [Bit set](https://rux-lang.dev/docs/learn/bit-set) | a set of small integers kept as bits | | 17.10 | [Small vector](https://rux-lang.dev/docs/learn/small-vector) | a vector that keeps its first few items without allocating | | 17.11 | [LRU cache](https://rux-lang.dev/docs/learn/lru-cache) | a bounded cache that forgets the least recently used entry | ## Before you start Every collection takes an [allocator](https://rux-lang.dev/docs/learn/allocator), so finish [Part 15: Memory](https://rux-lang.dev/docs/learn/memory) first. The lessons also lean on [generic types](https://rux-lang.dev/docs/learn/generic-type) from Part 13, a [fallible `Main`](https://rux-lang.dev/docs/learn/fallible-main) and [`?`](https://rux-lang.dev/docs/learn/propagate) from Part 9, [optionals](https://rux-lang.dev/docs/learn/optionals) from Part 8, [moves](https://rux-lang.dev/docs/learn/move) from Part 11, [Comparable](https://rux-lang.dev/docs/learn/comparable) and [Operator overload](https://rux-lang.dev/docs/learn/operator-overload) from Part 12, and [Bitwise](https://rux-lang.dev/docs/learn/bitwise) from Part 16. Each lesson's package is in the Examples repository's `Collections/` folder: ```sh cd Examples/Collections/Vector rux run ``` ## After this part [Part 18: Algorithms](https://rux-lang.dev/docs/learn/algorithms) sorts, searches and folds the values you can now collect. Parts 18 to 26 tour the standard packages and can be read in any order. Before moving on, try the checkpoint projects [Word count](https://rux-lang.dev/docs/learn/word-count), which counts words in a hash map and prints them in order through a tree map, and [Inventory](https://rux-lang.dev/docs/learn/inventory), a shop's stock kept as structs in a vector. For the rules behind the inline sequences these containers are compared with, see [Arrays](https://rux-lang.dev/docs/lang/arrays/overview) and [Slices](https://rux-lang.dev/docs/lang/slices/overview) in the Rux Reference. # Vector ::note **You'll need**: [Allocator](https://rux-lang.dev/docs/learn/allocator), [Generic type](https://rux-lang.dev/docs/learn/generic-type), [Fallible main](https://rux-lang.dev/docs/learn/fallible-main), [Coalesce](https://rux-lang.dev/docs/learn/coalesce) :: An inline array has the length its type says, fixed while compiling. Most real data is not like that: lines read from a file, results that pass a test, orders placed today. You do not know how many there will be until they arrive. The Memory lessons solved that by hand — ask an allocator for a block, keep count, ask for a larger block when it is full. A `Vector`, from the `Collections` package, does that bookkeeping for you. It owns a block, hands out room as values are pushed, and moves to a larger block when the current one is full. It is the container you will reach for most often. ## Making a vector A vector keeps its values somewhere, so it is given an [allocator](https://rux-lang.dev/docs/learn/allocator) when it is made: ```rux var system = SystemAllocator(); let allocator: Allocator = system; var numbers = Vector(allocator); ``` `Vector` is a [generic type](https://rux-lang.dev/docs/learn/generic-type): a vector of `int`. Making one asks the allocator for nothing yet — an empty vector has no block, and a capacity of zero. The binding is a `var`, because pushing changes the vector. ## Length and capacity Two numbers describe a vector, and they are worth keeping apart: | Number | Method | Meaning | | -------- | ------------ | ------------------------------------------------- | | Length | `Length()` | How many values it holds | | Capacity | `Capacity()` | How many would fit before it needs a larger block | Pushing raises the length by one every time; the capacity only jumps now and then. The program pushes nine values and prints a line whenever the capacity changes: ```rux for i in 1..=9 { let before = numbers.Capacity(); numbers.Push(i * 10)?; if numbers.Capacity() != before { PrintLine("push {} length {} capacity {} (grew)", i, numbers.Length(), numbers.Capacity()); } } ``` ```text push 1 length 1 capacity 4 (grew) push 5 length 5 capacity 8 (grew) push 9 length 9 capacity 16 (grew) ``` Nine pushes, three moves. The capacity grows **ahead** of the length on purpose: each time the vector moves it takes twice the room, so the pushes that follow cost nothing. The vector moves house a handful of times, not once per value. ```mermaid flowchart LR push["`Push(value)`"] --> room{"Is length below
capacity?"} room -- "yes" --> write["Write the value
into the next slot"] room -- "no" --> grow["Ask the allocator
for a larger block"] grow --> copy["Move the values across,
give the old block back"] copy --> write grow -- "no memory" --> fail["`Push` fails with
`CollectionError`"] ``` ## Pushing can fail That last arrow is why `Push` returns `! CollectionError`: a push may need a larger block, and the allocator may have none to give. The `?` hands that failure on to `Main`, which is declared [fallible](https://rux-lang.dev/docs/learn/fallible-main) for exactly this reason: ```rux func Main() -> ! CollectionError { ``` A failed push leaves the vector exactly as it was — no value half-added. ## Reserving room up front When the final size is known, `Reserve` makes the room in one step: ```rux numbers.Reserve(100)?; ``` At least 100 more values will now fit, so the pushes that follow never need to grow. The program prints a capacity of `128`: the vector rounded the request up. ## Reading the values A vector is a container a `for` loop can walk, in the order the values went in: ```rux for value in numbers { Print(" {}", value); } ``` To read one value, use `Get`. It is bounds-checked: it returns `int?`, an [optional](https://rux-lang.dev/docs/learn/optional), with `none` past the end: ```rux PrintLine("index 2 {}", numbers.Get(2) ?? -1); PrintLine("index 50 {}", numbers.Get(50) ?? -1); ``` Index 2 is `30`; index 50 does not exist, and the [`??`](https://rux-lang.dev/docs/learn/coalesce) fallback gives `-1`. Nothing in the program frees anything. The vector's destructor gives its block back to the allocator when `numbers` goes out of scope. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Collections/Vector){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // The Memory lessons asked for a block of a fixed size and kept count by hand. A `Vector` does // that bookkeeping for you: it owns a block, hands out room as values are pushed, and moves to a // larger block when the current one is full. // // Two numbers describe a vector, and they are worth keeping apart. Its length is how many values // it holds. Its capacity is how many would fit before it needs a larger block. Pushing raises the // length by one every time; the capacity only jumps now and then. import Allocator::{ Allocator, SystemAllocator }; import Collections::{ CollectionError, Vector }; import Io::{ Print, PrintLine }; func Main() -> ! CollectionError { var system = SystemAllocator(); let allocator: Allocator = system; // A vector keeps its storage somewhere, so it is given an allocator. Making one asks for // nothing yet: an empty vector has a capacity of zero. var numbers = Vector(allocator); PrintLine("empty length {} capacity {}", numbers.Length(), numbers.Capacity()); // A push may need a larger block, and the allocator may have none to give, so `Push` // returns `! CollectionError`. The `?` hands that failure to `Main`. for i in 1..=9 { let before = numbers.Capacity(); numbers.Push(i * 10)?; if numbers.Capacity() != before { PrintLine("push {} length {} capacity {} (grew)", i, numbers.Length(), numbers.Capacity()); } } PrintLine("after 9 length {} capacity {}", numbers.Length(), numbers.Capacity()); // The capacity grows ahead of the length on purpose. Taking more room than needed means the // next pushes cost nothing, so the vector moves house a handful of times, not once a value. // When the final size is known up front, `Reserve` makes the room in one step: at least 100 // more values will now fit, so the pushes that follow never need to grow. numbers.Reserve(100)?; PrintLine("reserved length {} capacity {}", numbers.Length(), numbers.Capacity()); // A vector is a container a `for` loop can walk, in the order the values went in. Print("contents "); for value in numbers { Print(" {}", value); } PrintLine(); // `Get` is bounds-checked: it returns `int?`, and `none` past the end. PrintLine("index 2 {}", numbers.Get(2) ?? -1); PrintLine("index 50 {}", numbers.Get(50) ?? -1); // Nothing here frees anything. The vector's destructor gives its block back to the allocator // when `numbers` goes out of scope. } ``` Besides `Io`, its `Rux.toml` lists `Allocator` and `Collections` under `[Dependencies]`. ## Run it ```sh cd Examples/Collections/Vector rux run ``` ```text empty length 0 capacity 0 push 1 length 1 capacity 4 (grew) push 5 length 5 capacity 8 (grew) push 9 length 9 capacity 16 (grew) after 9 length 9 capacity 16 reserved length 9 capacity 128 contents 10 20 30 40 50 60 70 80 90 index 2 30 index 50 -1 ``` ## Common mistakes ::mistake **Leaving out the `?`.**:br`numbers.Push(10);` fails with: ```text error: fallible result of type '! CollectionError' is discarded ``` The help suggests `?`, `catch` or a `match`. A push that ran out of memory must be handled somehow. :: ::mistake **Using `?` in a `Main` that returns `int`.**:br`?` hands the failure to the enclosing function, so that function has to be able to fail. In `func Main() -> int`, `numbers.Push(10)?` fails with: ```text error: '?' propagates native fallible '! CollectionError', but the enclosing function returns 'int' ``` Declare `func Main() -> ! CollectionError`. :: ::mistake **A vector bound with `let`.**:br`Push` changes the vector. With `let numbers = …`, it fails with: ```text error: cannot call 'Push' on immutable 'numbers' ``` Bind it with `var`. :: ::mistake **Indexing with square brackets.**:br`numbers[0]` fails with: ```text error: type 'Vector' cannot be indexed ``` Use `numbers.Get(0)`, which returns an optional — or `numbers.AsSlice()` to get a slice you can index. :: ## Try it yourself 1. Push 1000 values and count how many times the capacity grew. 2. Make the vector with `Vector::WithCapacity(allocator, 100)?` instead. What are its length and capacity before the first push? 3. Remove the first value with `RemoveAt(0)`, which returns an optional, and print what is left. 4. Add up the values with a `for` loop, then again by indexing `numbers.AsSlice()`. ## Learn more - [Allocator](https://rux-lang.dev/docs/learn/allocator) — where a vector's block comes from - [Dynamic array](https://rux-lang.dev/docs/learn/dynamic-array) — a run whose length is set at run time and never changes - [Deque](https://rux-lang.dev/docs/learn/deque) — a vector that is quick at both ends - [Slices](https://rux-lang.dev/docs/lang/slices/overview) in the Rux Reference # Dynamic array ::note **You'll need**: [Array](https://rux-lang.dev/docs/learn/array), [Slice](https://rux-lang.dev/docs/learn/slice), [Move](https://rux-lang.dev/docs/learn/move), [Catch](https://rux-lang.dev/docs/learn/catch), [Allocator](https://rux-lang.dev/docs/learn/allocator), [Vector](https://rux-lang.dev/docs/learn/vector) :: An inline array, `int32[4]`, carries its length in its type. The compiler fixes it, and the elements live wherever the array itself lives — inside a local, a struct, another array. That is fast and simple, and it needs the length while compiling. Sometimes the length is only known once the program runs: a count read from a file, a size passed in by a caller. `Collections::Array` is for that case. It asks an allocator for a block of the length you choose at run time, and once made, that length never changes. It is **not** a vector: there is no `Push`. A fixed run whose size is decided late is the whole idea. ## A length chosen at run time The length arrives as an ordinary parameter: ```rux func Squares(allocator: Allocator, count: uint) -> Array ! CollectionError { var squares = Array::Filled(allocator, count, 0)?; for i in 0..count { squares.Set(i, (i * i) as int32)?; } return <-squares; } ``` `Array::Filled` makes `count` copies of one value — here `count` zeros — and `Set` replaces them one by one. Asking for memory can fail, so `Filled` returns a fallible and needs `?`; so does `Set`, for a reason you will see below. An inline array could not do this. `int32[count]` is rejected, because an inline array's length must be a constant. The array owns its block, so returning it **moves** the block out to the caller — the `<-` of [Move](https://rux-lang.dev/docs/learn/move). `Main` receives it and walks it like any container: ```rux var squares = Squares(allocator, 6)?; for value in squares { Print(" {}", value); } ``` ## Copying an inline array onto the heap `Array::FromSlice` copies existing values into a new dynamic array: ```rux let primes: int32[4] = [2, 3, 5, 7]; var copy = Array::FromSlice(allocator, primes)?; copy.Set(0, 99)?; ``` The copy is independent: changing it leaves the original alone, so the copy starts with `99` while `primes[0]` is still `2`. ## What a wrong index costs Both kinds of array check every index. They differ in **what happens** when one is wrong: | Wrong index on… | What happens | | ---------------------- | ---------------------------------------------- | | inline array, constant | does not build: `index 7 is out of range…` | | inline array, computed | the program stops: `Panic: index out of range` | | dynamic array, `Get` | returns `none` | | dynamic array, `Set` | fails with `IndexOutOfRange` | A dynamic array reports the mistake in its types, so the program decides what to do with it: ```rux PrintLine("copy[9] {}", copy.Get(9) ?? -1); copy.Set(9, 1) catch { e => { PrintLine("copy.Set(9) failed: {}", e); } }; ``` `Get(9)` is `none`, and the `??` turns it into `-1`. `Set(9, 1)` fails, and the [`catch`](https://rux-lang.dev/docs/learn/catch) prints the error: `index the collection does not have`. ## Owned, not copied One more difference. An inline array is a plain value, copied by `=`. A dynamic array owns its block, and two arrays must never think they own the same one — so it cannot be copied. You move it with `<-` instead, and the old name can no longer be used. When `squares` and `copy` go out of scope, each gives its block back to the allocator. | | Inline `int32[4]` | `Array` | `Vector` | | -------------- | -------------------- | ---------------------------- | ---------------------------- | | Length decided | while compiling | at run time | at run time | | Length changes | never | never | with every push | | Elements live | in the array itself | in a block from an allocator | in a block from an allocator | | `=` | copies | refused — move with `<-` | refused — move with `<-` | | Wrong index | build error or panic | `none` or a failure | `none` or a failure | ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Collections/DynamicArray){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // An inline array, `int32[4]`, carries its length in its type. The compiler fixes it, and the // elements live wherever the array itself lives — inside a local, a struct, another array. // // Sometimes the length is only known once the program runs: a count read from a file, a size // passed in by a caller. `Collections::Array` is for that case. It asks an allocator for a // block of the length you choose at run time, and once made, that length never changes. It is // not a vector: there is no `Push`. A fixed run whose size is decided late is the whole idea. import Allocator::{ Allocator, SystemAllocator }; import Collections::{ Array, CollectionError }; import Io::{ Print, PrintLine }; // The length arrives as an ordinary parameter. `int32[count]` would be rejected, because an // inline array's length must be known while compiling; a dynamic array has no such limit. func Squares(allocator: Allocator, count: uint) -> Array ! CollectionError { // `Filled` makes `count` copies of one value. Asking for memory can fail, hence `?`. var squares = Array::Filled(allocator, count, 0)?; for i in 0..count { squares.Set(i, (i * i) as int32)?; } // The array owns its block, so returning it moves the block out to the caller. return <-squares; } func Main() -> ! CollectionError { var system = SystemAllocator(); let allocator: Allocator = system; let primes: int32[4] = [2, 3, 5, 7]; PrintLine("inline length {}", primes.length); var squares = Squares(allocator, 6)?; Print("squares "); for value in squares { Print(" {}", value); } PrintLine(" (length {})", squares.Length()); // `FromSlice` copies an inline array onto the heap. The copy is independent: changing it // leaves the original alone. var copy = Array::FromSlice(allocator, primes)?; copy.Set(0, 99)?; PrintLine("copy[0] {}, primes[0] still {}", copy.Get(0) ?? -1, primes[0]); // Both kinds check an index, but they differ in what a wrong one costs. On an inline array, // a constant index past the end does not build, `primes[7]` being "index 7 is out of range // for an array of 4 elements", and a computed one stops the program with "Panic: index out // of range". A dynamic array's `Get` and `Set` report it in their types instead: `Get` // returns `none`, and `Set` fails with `IndexOutOfRange`, so the program decides what to do. PrintLine("copy[9] {}", copy.Get(9) ?? -1); copy.Set(9, 1) catch { e => { PrintLine("copy.Set(9) failed: {}", e); } }; // One more difference: an inline array is copied by `=`, but a dynamic array owns its block // and cannot be copied. Writing `let other = copy;` is rejected; `let other <- copy;` moves it. // When `squares` and `copy` go out of scope, each gives its block back to the allocator. } ``` Besides `Io`, its `Rux.toml` lists `Allocator` and `Collections` under `[Dependencies]`. ## Run it ```sh cd Examples/Collections/DynamicArray rux run ``` ```text inline length 4 squares 0 1 4 9 16 25 (length 6) copy[0] 99, primes[0] still 2 copy[9] -1 copy.Set(9) failed: index the collection does not have ``` ## Common mistakes ::mistake **An inline array with a run-time length.**:br`var a: int32[count];` with a parameter `count` fails with: ```text error: array length must be a non-negative compile-time integer ``` Use `Array::Filled(allocator, count, 0)?`. :: ::mistake **Copying with `=`.**:br`let other = copy;` fails, and a note explains why: ```text error: move-only value 'copy' requires an explicit '<-' in initialization 'Array' prohibits copying ``` Write `let other <- copy;` to move it — or `copy.Clone()?` when you really want two arrays. :: ::mistake **Using the array after moving it.**:br After `let other <- copy;`, the name `copy` is empty: `copy.Length()` fails with: ```text error: value 'copy' is used after it was moved ``` :: ::mistake **Expecting a dynamic array to grow.**:br`copy.Push(1)?` fails with: ```text error: struct 'Array' has no field 'Push' ``` The length is fixed once the array is made — use a [Vector](https://rux-lang.dev/docs/learn/vector) for a sequence that grows. :: ## Try it yourself 1. Change `Squares` to `Cubes`, returning an `Array`. 2. Make an array of 10 copies of `-1` with `Filled`, and set every third element to its index. 3. Write `let other = copy;`, read the error, then fix it with `<-`. What happens if you use `copy` afterwards? 4. Push a few values into a `Vector`, then freeze them into an `Array` with `ToArray()?`. ## Learn more - [Array](https://rux-lang.dev/docs/learn/array) — inline arrays, whose length is part of the type - [Vector](https://rux-lang.dev/docs/learn/vector) — the growable sequence - [Move](https://rux-lang.dev/docs/learn/move) — handing ownership on with `<-` - [Arrays](https://rux-lang.dev/docs/lang/arrays/overview) in the Rux Reference # Deque ::note **You'll need**: [Vector](https://rux-lang.dev/docs/learn/vector), [Presence](https://rux-lang.dev/docs/learn/presence), [Coalesce](https://rux-lang.dev/docs/learn/coalesce) :: A [vector](https://rux-lang.dev/docs/learn/vector) is quick at its end and slow at its front. Pushing at the end writes into the next free slot; putting a value at position zero means shifting every other value along by one to make room — a thousand moves for a thousand values. A `Deque` — a **d**ouble-**e**nded **que**ue, said "deck" — is quick at both ends. It remembers where its contents start as well as where they end, so adding at the front moves a marker, not the values. Its everyday use is a queue: work joins at the back and is served from the front, which is exactly the pair of operations a vector is bad at. ## Four operations, two ends ```mermaid flowchart LR f["`PushFront`
`PopFront`"] <--> front["front"] front --- mid["…"] mid --- back["back"] back <--> b["`PushBack`
`PopBack`"] ``` | Operation | Vector | Deque | | ------------------- | ------------------------ | ------------------- | | Add at the end | quick (`Push`) | quick (`PushBack`) | | Remove at the end | quick | quick (`PopBack`) | | Add at the front | slow: shifts every value | quick (`PushFront`) | | Remove at the front | slow: shifts every value | quick (`PopFront`) | | Read by position | quick (`Get`) | quick (`Get`) | A deque is made like a vector, from an allocator: ```rux var queue = Deque(allocator); ``` ## A queue of tickets Tickets join at the back, in the order they arrive. Each push may need more room, and so can fail; `?` hands that failure to `Main`: ```rux queue.PushBack(101)?; queue.PushBack(102)?; queue.PushBack(103)?; ``` An urgent ticket jumps the line by going in at the front: ```rux queue.PushFront(900)?; ``` The queue is now `900 101 102 103`. Serving takes from the front: ```rux PrintLine("served {}", queue.PopFront() ?? -1); PrintLine("served {}", queue.PopFront() ?? -1); ``` The urgent ticket, `900`, is served first, then `101` — first in, first out. Both pops return an optional, `int?`, since an empty deque has nothing to give; `?? -1` supplies a stand-in that never prints here. The newest arrival changes their mind and leaves from the back: ```rux PrintLine("left {}", queue.PopBack() ?? -1); ``` That is `103`, leaving only `102` waiting. ## When the queue runs dry After one more pop the deque is empty, and the next `PopFront` returns `none`. A `match` says so properly rather than printing a stand-in: ```rux match queue.PopFront() { ticket? => PrintLine("served {}", ticket), none => PrintLine("empty nobody is waiting") } ``` ## Looking without taking `Show` prints the queue without changing it. It borrows the deque as `&Deque` and reads each position with `Get`, which, like a vector's, returns an optional: ```rux func Show(label: char8[..], queue: &Deque) { Print("{:8}", label); for i in 0..queue.Length() { Print(" {}", queue.Get(i) ?? -1); } PrintLine(); } ``` Position 0 is always the front, whichever end the values came in by. ## Which to reach for A vector when values only come and go at the end — a list you build and then read. A deque when both ends are in play — a queue, a window of the latest readings, a list of jobs where some jump the line. The deque's bookkeeping costs a little on every operation, which is why it is not simply the default. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Collections/Deque){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // A vector is quick at its end and slow at its front: putting a value at position zero means // shifting every other value along to make room. // // A `Deque` — a double-ended queue, said "deck" — is quick at both ends. It remembers where its // contents start as well as where they end, so adding at the front moves a marker, not the // values. The everyday use is a queue: work joins at the back and is served from the front, // which is exactly the pair of operations a vector is bad at. import Allocator::{ Allocator, SystemAllocator }; import Collections::{ CollectionError, Deque }; import Io::{ Print, PrintLine }; func Show(label: char8[..], queue: &Deque) { Print("{:8}", label); for i in 0..queue.Length() { Print(" {}", queue.Get(i) ?? -1); } PrintLine(); } func Main() -> ! CollectionError { var system = SystemAllocator(); let allocator: Allocator = system; var queue = Deque(allocator); // Tickets join at the back, in the order they arrive. Each push may need more room, and so // can fail; `?` hands that failure to `Main`. queue.PushBack(101)?; queue.PushBack(102)?; queue.PushBack(103)?; Show("arrived", queue); // An urgent ticket jumps the line by going in at the front. queue.PushFront(900)?; Show("urgent", queue); // Serving takes from the front. Both pops return an optional, `int?`, since an empty deque // has nothing to give. PrintLine("served {}", queue.PopFront() ?? -1); PrintLine("served {}", queue.PopFront() ?? -1); // The newest arrival changes their mind and leaves from the back. PrintLine("left {}", queue.PopBack() ?? -1); Show("waiting", queue); PrintLine("served {}", queue.PopFront() ?? -1); match queue.PopFront() { ticket? => PrintLine("served {}", ticket), none => PrintLine("empty nobody is waiting") } // Which to reach for: a vector when values only come and go at the end, a deque when both // ends are in play. The deque's bookkeeping costs a little per operation, which is why it // is not simply the default. } ``` Besides `Io`, its `Rux.toml` lists `Allocator` and `Collections` under `[Dependencies]`. ## Run it ```sh cd Examples/Collections/Deque rux run ``` ```text arrived 101 102 103 urgent 900 101 102 103 served 900 served 101 left 103 waiting 102 served 102 empty nobody is waiting ``` ## Common mistakes ::mistake **Treating a pop as a value.**:br A pop may find nothing, so its type is `int?`. `let t: int = queue.PopFront();` fails with: ```text error: cannot assign 'int?' to 'int' ``` Unwrap it with `??`, a `match`, or [`?? return`](https://rux-lang.dev/docs/learn/coalesce-exit). :: ::mistake **Printing the optional directly.**:br`PrintLine("{}", queue.PopFront())` fails with: ```text error: no matching overload for 'PrintLine' with argument types (char8[..], int?) ``` An optional cannot be printed as it is — decide what `none` should look like first. :: ::mistake **Serving from the wrong end.**:br`PushBack` with `PopBack` is last in, first out — a stack, not a queue. A queue pairs `PushBack` with `PopFront`. :: ## Try it yourself 1. Use the deque as a stack: push three values with `PushBack` and pop them with `PopBack`. In which order do they come out? 2. Make a round robin: pop a ticket from the front, print it, and push it on the back, six times over three tickets. 3. Keep only the latest three readings: push each new reading at the back, and pop from the front whenever the length passes three. ## Learn more - [Vector](https://rux-lang.dev/docs/learn/vector) — the container a deque is compared with - [Presence](https://rux-lang.dev/docs/learn/presence) and [Coalesce](https://rux-lang.dev/docs/learn/coalesce) — unwrapping the optional a pop returns - [Reference](https://rux-lang.dev/docs/learn/reference) — borrowing the deque in `Show` - [Hash map](https://rux-lang.dev/docs/learn/hash-map) — finding values by key instead of by position # Hash map ::note **You'll need**: [Callback](https://rux-lang.dev/docs/learn/callback), [Presence](https://rux-lang.dev/docs/learn/presence), [Coalesce](https://rux-lang.dev/docs/learn/coalesce), [String literal](https://rux-lang.dev/docs/learn/string-literal), [Vector](https://rux-lang.dev/docs/learn/vector) :: A vector answers "what is at position 3?". Often that is the wrong question. A shop wants to know how many pears are in stock; a phone book, which number belongs to a name; a cache, whether this request was answered before. Each looks a value up by a **key** — whatever suits: a number, an id, a name. A `HashMap` stores values under keys of type `K` and finds them again fast. It works out a number from the key — its **hash** — and goes straight to the slot that number points at. So a lookup costs about the same whether the map holds ten entries or ten million. ## Making a map Along with the allocator, a hash map is given two functions: ```rux var stock = HashMap(allocator, HashSlice, EqualsSlice); ``` | Argument | Does | | ------------- | ------------------------------------------------------ | | `allocator` | Provides the memory for the entries | | `HashSlice` | Turns a key into a number, which picks the likely slot | | `EqualsSlice` | Tells whether two keys are equal | Hashing finds the likely slot; equality confirms that the key found there really is the one wanted. Both are needed because two different keys can hash to the same number. The `Collections` package provides the pair for text keys, and others — `HashInt32` and `EqualsInt32`, `HashChar8` and `EqualsChar8` and more — for the common key types. They are passed as [callbacks](https://rux-lang.dev/docs/learn/callback): plain function names, not calls. ```mermaid flowchart LR k["key: `pears`"] --> h["`HashSlice`"] h --> slot["the slot that
hash points at"] slot --> eq{"`EqualsSlice`:
is it this key?"} eq -- "yes" --> v["its value: `4`"] eq -- "no entry there" --> none["`none`"] ``` ## Inserting and looking up `Insert` adds an entry. It may need more room, and so can fail; `?` hands that failure to `Main`: ```rux stock.Insert("apples", 12)?; stock.Insert("pears", 4)?; stock.Insert("plums", 30)?; ``` `Get` returns an optional, `int32?`, because the key may not be there. A `match` handles both answers: ```rux match stock.Get("pears") { count? => PrintLine("pears {}", count), none => PrintLine("pears not stocked") } ``` Pears are in stock, so this prints `4`; the same `match` on `"kiwis"` prints `not stocked`. ## One entry per key A key appears at most once. Inserting it again **replaces** its value, and the map does not grow. `Replace` does the same and also hands back the value it displaced: ```rux stock.Insert("apples", 15)?; let previous = stock.Replace("apples", 20)?; ``` Apples are now `20`, `previous` holds the `15` they replaced, and the map still has three entries. `previous` is an optional — a key that was not there yet displaced nothing. ## Removing and checking `Remove` takes the entry out and returns its value, or `none` if there was no such key. `ContainsKey` asks without changing anything: ```rux PrintLine("removed plums {}", stock.Remove("plums") ?? 0); PrintLine("has plums {}", stock.ContainsKey("plums")); ``` | Method | Returns | Changes the map | | ------------- | ---------------------- | ---------------- | | `Insert` | `! CollectionError` | adds or replaces | | `Replace` | `V? ! CollectionError` | adds or replaces | | `Get` | `V?` | no | | `ContainsKey` | `bool` | no | | `Remove` | `V?` | removes | | `Length` | `uint` | no | ## No order What a hash map does **not** keep is order. A `for` loop over it visits the entries in whatever arrangement the hashing produced, which may differ from one run to the next. When order matters — an alphabetical listing, the earliest entry — the [tree map](https://rux-lang.dev/docs/learn/tree-map) keeps it. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Collections/HashMap){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // A vector answers "what is at position 3". A hash map answers "what is stored under this key", // where the key is whatever suits — a number, an id, a name. // // It finds an entry by computing a number from the key, its hash, and going straight to the slot // that number points at. So a lookup costs about the same whether the map holds ten entries or // ten million. import Allocator::{ Allocator, SystemAllocator }; import Collections::{ CollectionError, EqualsSlice, HashMap, HashSlice }; import Io::PrintLine; func Main() -> ! CollectionError { var system = SystemAllocator(); let allocator: Allocator = system; // Along with the allocator come two functions: one to hash a key, one to tell whether two // keys are equal. Hashing finds the likely slot; equality confirms that the key found there // really is the one wanted, since two different keys can hash to the same number. The // package provides both for text keys. var stock = HashMap(allocator, HashSlice, EqualsSlice); // Inserting may need more room, and so can fail; `?` hands that failure to `Main`. stock.Insert("apples", 12)?; stock.Insert("pears", 4)?; stock.Insert("plums", 30)?; PrintLine("entries {}", stock.Length()); // `Get` returns an optional, `int32?`, because the key may not be there. match stock.Get("pears") { count? => PrintLine("pears {}", count), none => PrintLine("pears not stocked") } match stock.Get("kiwis") { count? => PrintLine("kiwis {}", count), none => PrintLine("kiwis not stocked") } // A key appears at most once. Inserting it again replaces its value, and the map does not // grow. `Replace` does the same and also hands back the value it displaced. stock.Insert("apples", 15)?; let previous = stock.Replace("apples", 20)?; PrintLine("apples {} (was {}), {} entries", stock.Get("apples") ?? 0, previous ?? 0, stock.Length()); // `Remove` takes the entry out and returns its value, or `none` if there was no such key. PrintLine("removed plums {}", stock.Remove("plums") ?? 0); PrintLine("has plums {}", stock.ContainsKey("plums")); PrintLine("entries {}", stock.Length()); // What a hash map does not keep is order. A `for` loop over it visits the entries in // whatever arrangement the hashing produced, which may differ from one run to the next. // When order matters, the TreeMap lesson's map keeps it. } ``` Besides `Io`, its `Rux.toml` lists `Allocator` and `Collections` under `[Dependencies]`. ## Run it ```sh cd Examples/Collections/HashMap rux run ``` ```text entries 3 pears 4 kiwis not stocked apples 20 (was 15), 3 entries removed plums 30 has plums false entries 2 ``` ## Common mistakes ::mistake **Functions for the wrong key type.**:br The hash and equality functions must take the key type. `HashMap(allocator, HashInt32, EqualsInt32)` fails with: ```text error: argument 2 to 'HashMap' has type 'func(int32, uint64, uint64) -> uint64', but parameter 'hash' requires 'func(char8[..], uint64, uint64) -> uint64' ``` Text keys take `HashSlice` and `EqualsSlice`. :: ::mistake **Treating `Get` as a value.**:br`let n: int32 = stock.Get("pears");` fails with: ```text error: cannot assign 'int32?' to 'int32' ``` The key might be missing; say what to do then, with `??` or a `match`. :: ::mistake **Overwriting by accident.**:br`Insert` on an existing key replaces its value without a word. When a second entry for the same key is a mistake, ask `ContainsKey` first — or use `Replace` and look at what it displaced. :: ::mistake **Relying on the order of a walk.**:br A `for` loop over a hash map may visit the entries in a different order from one run to the next. Sort them, or keep them in a [tree map](https://rux-lang.dev/docs/learn/tree-map). :: ## Try it yourself 1. Add a fourth fruit, then print every entry with `for entry in stock`, using `entry.key` and `entry.value`. 2. Count the letters of `"banana"` in a `HashMap`, made with `HashChar8` and `EqualsChar8`: for each letter, insert `(counts.Get(c) ?? 0) + 1`. 3. Sell three apples: read the count, check there are enough, and store the new count. ## Learn more - [Hash set](https://rux-lang.dev/docs/learn/hash-set) — a hash map with only the keys - [Tree map](https://rux-lang.dev/docs/learn/tree-map) — a map that keeps its keys in order - [Callback](https://rux-lang.dev/docs/learn/callback) — passing a function as an argument - [Word count](https://rux-lang.dev/docs/learn/word-count) — a checkpoint project that counts words in a hash map # Hash set ::note **You'll need**: [Hash map](https://rux-lang.dev/docs/learn/hash-map), [Propagate](https://rux-lang.dev/docs/learn/propagate), [Presence](https://rux-lang.dev/docs/learn/presence), [Array](https://rux-lang.dev/docs/learn/array) :: Often the only question is "have I seen this one before?" — a visitor already counted, a file already processed, a word already in the dictionary. A [hash map](https://rux-lang.dev/docs/learn/hash-map) could answer it, but it would store a value under every key that nobody ever reads. A `HashSet` is that map with the values left out. It holds each element **at most once**, and answers membership in about the same time however large it grows. It is built the same way as a hash map — a hash function and an equality test — and, like a hash map, keeps no order. | | `HashMap` | `HashSet` | | ---------- | ---------------------------------- | ------------------------------- | | Stores | a value under each key | the elements alone | | Asks | "what is stored under this key?" | "is this one here?" | | Duplicates | a second insert replaces the value | a second insert changes nothing | | Order | none | none | ## Making a set The same three arguments as a hash map, for the element type instead of a key type: ```rux var visited = HashSet(allocator, HashSlice, EqualsSlice); ``` ## Inserting answers a question `Insert` answers as it works: `true` when the element was new, `false` when the set already had it. It may also need more room, so its type is `bool ! CollectionError` — a `bool`, or a failure — and `?` unwraps the answer or hands the failure to `Main`: ```rux let route: char8[..][6] = ["Lyon", "Paris", "Lille", "Paris", "Nice", "Lyon"]; for city in route { let isNew = visited.Insert(city)?; if isNew { PrintLine("{:6} first visit", city); } else { PrintLine("{:6} been here before", city); } } ``` `route` is an [array](https://rux-lang.dev/docs/learn/array) of six text slices. The second Paris and the second Lyon get `false`, so the set ends up with four cities from six stops: inserting and testing were one step, not two. When you only want the element added and do not care whether it was new, `visited.Insert(city)?;` on its own line is fine — the `bool` may be dropped once `?` has dealt with the failure. ## Asking and removing `Contains` asks without changing anything: ```rux PrintLine("visited Nice? {}", visited.Contains("Nice")); PrintLine("visited Brest? {}", visited.Contains("Brest")); ``` `Remove` hands the element back as an optional, `none` when it was not there: ```rux match visited.Remove("Lille") { city? => PrintLine("forgot {}", city), none => PrintLine("Lille was never visited") } ``` | Method | Returns | Changes the set | | ---------- | -------------------------------------- | --------------- | | `Insert` | `bool ! CollectionError` — was it new? | adds | | `Contains` | `bool` | no | | `Remove` | `T?` | removes | | `Length` | `uint` | no | ## Combining sets Two sets can be compared and combined as a whole. `IntersectWith` keeps only the elements both sets have, `Subtract` removes the other set's elements, `UnionWith` adds them — the last can need memory, so it is fallible — and `IsSubsetOf` asks whether every element of one is in the other. They are the classic set operations, done in one call each. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Collections/HashSet){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // Often the only question is "have I seen this one before?". A hash map could answer it, but it // would store a value under every key that nobody ever reads. // // A `HashSet` is that map with the values left out. It holds each element at most once and // answers membership in about the same time however large it grows. It is built the same way as // a hash map — a hash function and an equality test — and, like a hash map, keeps no order. import Allocator::{ Allocator, SystemAllocator }; import Collections::{ CollectionError, EqualsSlice, HashSet, HashSlice }; import Io::PrintLine; func Main() -> ! CollectionError { var system = SystemAllocator(); let allocator: Allocator = system; var visited = HashSet(allocator, HashSlice, EqualsSlice); // `Insert` answers a question as it works: `true` when the element was new, `false` when the // set already had it. It may also need more room, so its type is `bool ! CollectionError`, // and `?` unwraps the answer or hands the failure to `Main`. let route: char8[..][6] = ["Lyon", "Paris", "Lille", "Paris", "Nice", "Lyon"]; for city in route { let isNew = visited.Insert(city)?; if isNew { PrintLine("{:6} first visit", city); } else { PrintLine("{:6} been here before", city); } } PrintLine("{} stops, {} different cities", route.length, visited.Length()); // `Contains` asks without changing anything. PrintLine("visited Nice? {}", visited.Contains("Nice")); PrintLine("visited Brest? {}", visited.Contains("Brest")); // `Remove` hands the element back as an optional, `none` when it was not there. match visited.Remove("Lille") { city? => PrintLine("forgot {}", city), none => PrintLine("Lille was never visited") } PrintLine("visited Lille? {}", visited.Contains("Lille")); } ``` Besides `Io`, its `Rux.toml` lists `Allocator` and `Collections` under `[Dependencies]`. ## Run it ```sh cd Examples/Collections/HashSet rux run ``` ```text Lyon first visit Paris first visit Lille first visit Paris been here before Nice first visit Lyon been here before 6 stops, 4 different cities visited Nice? true visited Brest? false forgot Lille visited Lille? false ``` ## Common mistakes ::mistake **Using `Insert` directly as a condition.**:br`if visited.Insert("Lyon") { … }` fails with: ```text error: condition for 'if' must have type 'bool', but found 'bool8 ! CollectionError' ``` The answer comes wrapped in a fallible: unwrap it first, with `let isNew = visited.Insert("Lyon")?;`. :: ::mistake **Leaving out the `?`.**:br`visited.Insert("Lyon");` fails with: ```text error: fallible result of type 'bool8 ! CollectionError' is discarded ``` The `bool` may be dropped, but the possible failure may not. :: ::mistake **Expecting the elements back in order.**:br A `for` loop over a hash set visits its elements in no particular order. When order matters, use a [tree set](https://rux-lang.dev/docs/learn/tree-set). :: ## Try it yourself 1. Print every city in the set with `for city in visited`. Run it twice — is the order the one in `route`? 2. Make a second set of cities a friend visited and keep only the cities you both saw, with `visited.IntersectWith(friend)`. 3. Find the first repeated word in a sentence: insert each word, and stop at the first `false`. ## Learn more - [Hash map](https://rux-lang.dev/docs/learn/hash-map) — the same structure, with a value under each key - [Tree set](https://rux-lang.dev/docs/learn/tree-set) — a set that keeps its elements in order - [Propagate](https://rux-lang.dev/docs/learn/propagate) — what `?` does with the failure - [Word count](https://rux-lang.dev/docs/learn/word-count) and [Inventory](https://rux-lang.dev/docs/learn/inventory) — checkpoint projects built on collections # Tree map ::note **You'll need**: [Hash map](https://rux-lang.dev/docs/learn/hash-map), [Comparable](https://rux-lang.dev/docs/learn/comparable), [Iterable](https://rux-lang.dev/docs/learn/iterable), [Presence](https://rux-lang.dev/docs/learn/presence) :: A [hash map](https://rux-lang.dev/docs/learn/hash-map) finds an entry fast and keeps no order: walk it, and the entries come out however the hashing scattered them. For a stock list that is fine. For temperatures taken through the day, a timetable or a leaderboard, the order **is** the information. A `TreeMap` keeps its keys sorted. However they were inserted, a walk visits them smallest first, and questions about order become cheap: the first key, the last, the nearest one below a bound, everything between two bounds. A lookup costs a little more than a hash map's — the map is searched rather than jumped into — and that is the trade. ## Making a tree map A hash map was told how to hash and compare keys for equality. A tree map is told how to put two keys **in order**: ```rux var readings = TreeMap(allocator, CompareInt32); ``` `CompareInt32` takes two `int32` keys and returns an `Ordering` — less, equal or greater — as in the [Comparable](https://rux-lang.dev/docs/learn/comparable) lesson. `Collections` has the same for other key types, such as `CompareSlice` for text. ## Keys arrive in any order Temperatures, keyed by the hour they were taken, arrive out of order: ```rux readings.Insert(15, 21)?; readings.Insert(6, 9)?; readings.Insert(12, 19)?; readings.Insert(9, 14)?; readings.Insert(18, 16)?; readings.Insert(3, 7)?; ``` A `for` loop walks the map in key order anyway. Each entry is a `KeyValue`, with `key` and `value` fields: ```rux for entry in readings { PrintLine(" {:2}:00 {} C", entry.key, entry.value); } ``` The hours come out `3, 6, 9, 12, 15, 18`. `{:2}` pads each hour to two characters, so the colons line up. ## Walking part of the map `Range(start, end)` walks only the keys from `start` up to, but not including, `end` — the same half-open shape as `a..b`. It starts at `start` rather than at the smallest key, so it does not visit the entries it skips: ```rux for entry in readings.Range(9, 17) { PrintLine(" {:2}:00 {} C", entry.key, entry.value); } ``` ```mermaid flowchart LR subgraph range ["`Range(9, 17)`"] k9["`9`"] --> k12["`12`"] --> k15["`15`"] end k3["`3`"] --> k6["`6`"] --> k9 k15 --> k18["`18`"] ``` ## Ordered questions A tree map can answer questions a hash map cannot: | Method | Returns the entry with… | Here | | ------------ | ------------------------------------ | ---------------------- | | `First()` | the smallest key | 3:00 | | `Last()` | the largest key | 18:00 | | `Floor(k)` | the largest key at or **below** `k` | `Floor(14)` is 12:00 | | `Ceiling(k)` | the smallest key at or **above** `k` | `Ceiling(14)` is 15:00 | Each returns an optional `KeyValue`, since an empty map has no first key and a bound may have nothing below it. A `match` unwraps it: ```rux match readings.Floor(14) { entry? => PrintLine("latest by 14:00 was {}:00, {} C", entry.key, entry.value), none => PrintLine("nothing by 14:00") } ``` No reading was taken at 14:00, so `Floor` finds the latest before it — 12:00, 19 °C. ## Looking up a key Lookup reads the same as a hash map's. `Get` returns `int32?`, and `ContainsKey` a `bool`: ```rux PrintLine("at 12:00 it was {} C", readings.Get(12) ?? 0); PrintLine("any reading at 13:00? {}", readings.ContainsKey(13)); ``` `Insert`, `Replace`, `Remove`, `Get` and `ContainsKey` all work as they do on a hash map; only the order, and the questions it makes possible, are new. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Collections/TreeMap){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // A hash map finds an entry fast and keeps no order: walk it, and the entries come out however // the hashing scattered them. // // A `TreeMap` keeps its keys sorted instead. However they were inserted, a walk visits // them smallest first, and questions about order become cheap: the first key, the last, the // nearest one below a bound, everything between two bounds. A lookup costs a little more than a // hash map's — the map is searched rather than jumped into — and that is the trade. import Allocator::{ Allocator, SystemAllocator }; import Collections::{ CollectionError, CompareInt32, TreeMap }; import Io::PrintLine; func Main() -> ! CollectionError { var system = SystemAllocator(); let allocator: Allocator = system; // A tree map is told how to put two keys in order, where a hash map was told how to hash and // compare them. `CompareInt32` returns an `Ordering`, as in the Comparable lesson. var readings = TreeMap(allocator, CompareInt32); // Temperatures, keyed by the hour they were taken, arriving out of order. readings.Insert(15, 21)?; readings.Insert(6, 9)?; readings.Insert(12, 19)?; readings.Insert(9, 14)?; readings.Insert(18, 16)?; readings.Insert(3, 7)?; // A `for` loop walks the map in key order. Each entry is a `KeyValue`, with `key` and `value`. PrintLine("all readings"); for entry in readings { PrintLine(" {:2}:00 {} C", entry.key, entry.value); } // `Range(start, end)` walks only the keys from `start` up to, but not including, `end` — the // same half-open shape as `a..b`. It starts at `start` rather than at the smallest key. PrintLine("working hours, 9 to 17"); for entry in readings.Range(9, 17) { PrintLine(" {:2}:00 {} C", entry.key, entry.value); } // The ordered questions return optionals, since an empty map has no first key and a bound // may have nothing below it. `Floor` finds the largest key at or below the one asked for. match readings.Floor(14) { entry? => PrintLine("latest by 14:00 was {}:00, {} C", entry.key, entry.value), none => PrintLine("nothing by 14:00") } match readings.First() { entry? => PrintLine("first reading at {}:00", entry.key), none => PrintLine("no readings") } // Lookup reads the same as a hash map's: `Get` returns `int32?`. PrintLine("at 12:00 it was {} C", readings.Get(12) ?? 0); PrintLine("any reading at 13:00? {}", readings.ContainsKey(13)); } ``` Besides `Io`, its `Rux.toml` lists `Allocator` and `Collections` under `[Dependencies]`. ## Run it ```sh cd Examples/Collections/TreeMap rux run ``` ```text all readings 3:00 7 C 6:00 9 C 9:00 14 C 12:00 19 C 15:00 21 C 18:00 16 C working hours, 9 to 17 9:00 14 C 12:00 19 C 15:00 21 C latest by 14:00 was 12:00, 19 C first reading at 3:00 at 12:00 it was 19 C any reading at 13:00? false ``` ## Common mistakes ::mistake **Expecting `Range` to include its end.**:br`Range(9, 17)` stops **before** 17: a reading taken at 17:00 would not be visited. Pass the first key you do **not** want as the end, as with `a..b`. :: ::mistake **Reading a field through the optional.**:br`readings.Floor(16).key` fails with: ```text error: type 'KeyValue?' has no field 'key' ``` The entry may not exist; unwrap it with a `match` or `?? return` before reading `key` and `value`. :: ::mistake **Choosing a tree map by habit.**:br A tree map pays for its order on every insert and lookup. When nothing ever asks for order — no sorted walk, no `Floor`, no `Range` — a [hash map](https://rux-lang.dev/docs/learn/hash-map) does the same job faster. :: ## Try it yourself 1. Print the reading nearest **after** 10:00 with `Ceiling(10)`, and the last reading of the day with `Last()`. 2. Walk the morning readings, from midnight up to but not including noon. 3. Remove the 3:00 reading with `Remove(3)`, and check that `First()` now answers 6:00. 4. Make a `TreeMap` with `CompareSlice`, insert a few names with ages, and print them in alphabetical order. ## Learn more - [Hash map](https://rux-lang.dev/docs/learn/hash-map) — the unordered map, and the methods both share - [Tree set](https://rux-lang.dev/docs/learn/tree-set) — the ordered set, built the same way - [Comparable](https://rux-lang.dev/docs/learn/comparable) — `Ordering`, and how two values are put in order - [Range](https://rux-lang.dev/docs/learn/range) — the half-open `a..b` that `Range(start, end)` mirrors # Tree set ::note **You'll need**: [Hash set](https://rux-lang.dev/docs/learn/hash-set), [Tree map](https://rux-lang.dev/docs/learn/tree-map), [Coalesce](https://rux-lang.dev/docs/learn/coalesce) :: A [hash set](https://rux-lang.dev/docs/learn/hash-set) answers "is it here?" and nothing about order. A `TreeSet` answers the same question and also keeps its elements sorted, the way a [tree map](https://rux-lang.dev/docs/learn/tree-map) keeps its keys. That makes it the set to reach for when the members should come out in order — a word list in alphabetical order, free seat numbers lowest first — or when the question is "which member comes next after this one?". ## Making a tree set Like a tree map, it is told how to order two elements: ```rux var tags = TreeSet(allocator, CompareSlice); ``` `CompareSlice` orders text by its bytes. For lowercase English words that is alphabetical order; the Common mistakes below show where it is not. ## Membership, as in a hash set `Insert` reports whether the element was new, and a duplicate is not added a second time: ```rux let incoming: char8[..][7] = ["rust", "memory", "arena", "rux", "memory", "pool", "arena"]; for tag in incoming { let isNew = tags.Insert(tag)?; if !isNew { PrintLine("duplicate {}", tag); } } ``` Seven tags go in; `memory` and `arena` arrive twice, so five are kept. `Contains` asks without changing anything, just as on a hash set. ## Walking in order A `for` loop walks the set in order, whatever order the elements arrived in: ```rux for tag in tags { Print(" {}", tag); } ``` They arrived as `rust memory arena rux pool`; they come out as `arena memory pool rust rux`. ## Ordered questions The same questions a tree map answers about its keys, a tree set answers about its elements. Each returns an optional, because the answer may not exist — so the program supplies a stand-in with `??`: ```rux PrintLine("first {}", tags.First() ?? "(none)"); PrintLine("last {}", tags.Last() ?? "(none)"); PrintLine("from n on {}", tags.Ceiling("n") ?? "(none)"); PrintLine("from z on {}", tags.Ceiling("z") ?? "(none)"); ``` `Ceiling` is the smallest element at or above the one asked for. `"n"` is not a tag, so `Ceiling("n")` finds the first tag from `n` on: `pool`. Nothing comes at or after `"z"`, so that one prints `(none)`. ```mermaid flowchart LR a["`arena`"] --> m["`memory`"] --> p["`pool`"] --> r["`rust`"] --> x["`rux`"] n(["`Ceiling` of `n`"]) -. "smallest element
at or above `n`" .-> p f(["`Floor` of `n`"]) -. "largest element
at or below `n`" .-> m ``` | Method | Returns | | ------------- | ----------------------------------------- | | `First()` | the smallest element | | `Last()` | the largest element | | `Floor(x)` | the largest element at or below `x` | | `Ceiling(x)` | the smallest element at or above `x` | | `Range(a, b)` | a walk from `a` up to, not including, `b` | ## A range of elements `Range(start, end)` walks the elements from `start` up to, but not including, `end`: ```rux for tag in tags.Range("r", "s") { Print(" {}", tag); } ``` Every word that starts with `r` sorts at or after `"r"` and before `"s"`, so this prints `rust rux` — a prefix search in one call. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Collections/TreeSet){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // A hash set answers "is it here?" and nothing about order. A `TreeSet` answers the same // question and also keeps its elements sorted, the way a tree map keeps its keys. // // That makes it the set to reach for when the members should come out in order — a word list // in alphabetical order, a list of free seat numbers lowest first — or when the question is // "which member comes next after this one?". import Allocator::{ Allocator, SystemAllocator }; import Collections::{ CollectionError, CompareSlice, TreeSet }; import Io::{ Print, PrintLine }; func Main() -> ! CollectionError { var system = SystemAllocator(); let allocator: Allocator = system; // Like a tree map, it is told how to order two elements. `CompareSlice` orders text by its // bytes, which is alphabetical for lowercase English words. var tags = TreeSet(allocator, CompareSlice); // Membership works as in a hash set: `Insert` reports whether the element was new, and a // duplicate is not added a second time. let incoming: char8[..][7] = ["rust", "memory", "arena", "rux", "memory", "pool", "arena"]; for tag in incoming { let isNew = tags.Insert(tag)?; if !isNew { PrintLine("duplicate {}", tag); } } PrintLine("{} tags in, {} kept", incoming.length, tags.Length()); PrintLine("has pool? {}", tags.Contains("pool")); // A `for` loop walks the set in order, whatever order the elements arrived in. Print("in order "); for tag in tags { Print(" {}", tag); } PrintLine(); // Ordered questions return optionals, because the answer may not exist. `Ceiling` is the // smallest element at or above the one asked for, so it finds the first tag from "n" on. PrintLine("first {}", tags.First() ?? "(none)"); PrintLine("last {}", tags.Last() ?? "(none)"); PrintLine("from n on {}", tags.Ceiling("n") ?? "(none)"); PrintLine("from z on {}", tags.Ceiling("z") ?? "(none)"); // `Range(start, end)` walks the elements from `start` up to, but not including, `end`. Print("r to s "); for tag in tags.Range("r", "s") { Print(" {}", tag); } PrintLine(); } ``` Besides `Io`, its `Rux.toml` lists `Allocator` and `Collections` under `[Dependencies]`. ## Run it ```sh cd Examples/Collections/TreeSet rux run ``` ```text duplicate memory duplicate arena 7 tags in, 5 kept has pool? true in order arena memory pool rust rux first arena last rux from n on pool from z on (none) r to s rust rux ``` ## Common mistakes ::mistake **Expecting dictionary order from `CompareSlice`.**:br It compares bytes, and every uppercase letter's byte is smaller than every lowercase one's. Insert `"Zebra"`, `"apple"` and `"mango"`, and the walk gives `Zebra apple mango`. Store words in one case when you want alphabetical order. :: ::mistake **Printing an ordered answer directly.**:br`First`, `Last`, `Floor` and `Ceiling` return optionals, which cannot be printed as they are: `PrintLine("{}", tags.First())` fails with: ```text error: no matching overload for 'PrintLine' with argument types (char8[..], char8[..]?) ``` Supply a stand-in with `??`, as the program does, or `match` on the result. :: ::mistake **Expecting `Remove` to return the element.**:br A hash set's `Remove` hands the element back as an optional; a tree set's returns a `bool` — whether it was there. Write `if tags.Remove("pool") { … }`. :: ## Try it yourself 1. Print `tags.Floor("n")`, the largest tag at or below `"n"`. Then `Floor("a")` — what does it give, and why? 2. Insert `"Zebra"` and see where it lands in the walk. Then insert it as `"zebra"`. 3. Keep free seat numbers in a `TreeSet` made with `CompareInt32`. Take the lowest free seat with `First()`, and remove it so it is no longer free. 4. Print every tag from `"a"` up to, but not including, `"n"` with `Range`. ## Learn more - [Hash set](https://rux-lang.dev/docs/learn/hash-set) — the unordered set, and the methods both share - [Tree map](https://rux-lang.dev/docs/learn/tree-map) — the same ordered questions, for keys with values - [Coalesce](https://rux-lang.dev/docs/learn/coalesce) — the `??` that supplies `(none)` - [Sort](https://rux-lang.dev/docs/learn/sort) — sorting a slice once, when the values do not change afterwards # Priority queue ::note **You'll need**: [Operator overload](https://rux-lang.dev/docs/learn/operator-overload), [Coalesce exit](https://rux-lang.dev/docs/learn/coalesce-exit), [Vector](https://rux-lang.dev/docs/learn/vector) :: A [deque](https://rux-lang.dev/docs/learn/deque) is a fair queue: whoever came first is served first. Plenty of work is not fair in that way. A support desk takes the outage before the typo, a game loop runs the timer due soonest, a route planner explores the cheapest path found so far. Each wants the **most important** item next, whenever it arrived. A `PriorityQueue` is that queue. Items go in in any order, and `Pop` always hands out the largest one still inside: ```rux import Collections::{ CollectionError, PriorityQueue }; ``` ## Largest first "Largest" is the element type's own `<`. Unlike a [tree map](https://rux-lang.dev/docs/learn/tree-map), a priority queue takes no ordering function — so a type to be queued declares `<`, as in [Operator overload](https://rux-lang.dev/docs/learn/operator-overload). A support ticket is larger when it is more urgent, and, among equals, when it arrived first: ```rux pub struct Ticket { priority: int32; arrival: int32; subject: char8[..]; } extend Ticket { pub func <(self: &Ticket, other: Ticket) -> bool { if self.priority != other.priority { return self.priority < other.priority; } return self.arrival > other.arrival; } } ``` Both the struct and its `<` are `pub`. The queue's code lives in the `Collections` package, and an operator is only visible to another package when it and its type are public — see [Visibility](https://rux-lang.dev/docs/lang/modules/visibility). ## Push, peek and pop ```rux var tickets = PriorityQueue(allocator); tickets.Push(Ticket { priority: 1, arrival: 1, subject: "typo on the pricing page" })?; tickets.Push(Ticket { priority: 3, arrival: 2, subject: "checkout is down" })?; ``` | Method | Returns | Does | | --------- | ------------------- | ------------------------------------------------------------------- | | `Push` | `! CollectionError` | adds an item; may need more room, and so can fail | | `Peek` | `(*T)?` | points at the largest item without taking it out | | `Pop` | `T?` | takes the largest item out, `none` when empty | | `Length` | `uint` | how many items are inside | | `IsEmpty` | `bool` | whether there are none | | `Clear` | — | destroys every item, keeping the storage | | `AsSlice` | `T[..]` | every item, in heap order — the largest first, then no useful order | `Pop` returns an optional, because the queue may be empty, so a loop that drains the queue stops at the first `none` with [`?? break`](https://rux-lang.dev/docs/learn/coalesce-exit): ```rux loop { let ticket = tickets.Pop() ?? break; PrintLine(" priority {} #{} {}", ticket.priority, ticket.arrival, ticket.subject); } ``` `Peek` returns a [pointer](https://rux-lang.dev/docs/learn/pointer) to the front item rather than a copy, so a large item is not copied just to be looked at. The pointer is valid only until the queue next changes. ## The heap inside The queue keeps its items in a vector arranged as a **binary heap**: a tree flattened into the vector, where item `i` has its children at `2i + 1` and `2i + 2`, and every parent is at least as large as its children. After the five pushes, the tickets sit like this: ```mermaid flowchart TD a["0: priority 3, #2
checkout is down"] --> b["1: priority 3, #4
site is slow"] a --> c["2: priority 2, #3
password reset"] b --> d["3: priority 1, #1
typo"] b --> e["4: priority 1, #5
dark mode"] ``` The largest item is always at index 0, which is why `Peek` costs nothing. `Push` puts the new item at the end and swaps it upwards past every smaller parent; `Pop` moves the last item to the top and swaps it downwards past its larger child. Either repairs one path from the top to the bottom — about 20 steps for a million items, where keeping a sorted vector would move up to a million. The price is that nothing but the front is in order. Below the top, siblings and cousins in the tree are in no promised order, so the heap is the right tool when you only ever want the next item, and a [sort](https://rux-lang.dev/docs/learn/sort) or a [tree set](https://rux-lang.dev/docs/learn/tree-set) is right when you want them all in order. ## Smallest first A queue that should hand out the smallest first — the earliest timer, the cheapest path — needs no other type of queue. Reverse the element's `<`, so that a later timer counts as the smaller: ```rux extend Timer { pub func <(self: &Timer, other: Timer) -> bool { return self.at > other.at; } } ``` The same `PriorityQueue` now pops the timer at 5 seconds first. Keeping the order in the type means every queue of `Timer` agrees on it, with no function to pass and none to pass wrongly. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Collections/PriorityQueue){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // A queue serves whoever came first. A priority queue serves whoever matters most: the most // urgent support ticket, the next timer to go off, the cheapest route found so far. Items go in // in any order, and `Pop` always hands out the largest one still inside. // // `PriorityQueue` keeps its items in a vector arranged as a binary heap: a tree, flattened // into the vector, in which every parent is at least as large as its children. The largest is // therefore always at the front, and a `Push` or a `Pop` only repairs one path from the top to // the bottom of the tree — a few steps even for a million items. What the heap does not keep is // a sorted order: only the front is known to be the largest. // // "Largest" means the element type's own `<`. There is no ordering function to pass, as there is // for a tree map: to change the order, change the type's `<`. The queue lives in another package, // so both the type and its `<` must be `pub` for the queue's code to see them. Without `pub`, the // operator is invisible there and the queue reports it as missing: // // error: operator '<' is not defined for 'Ticket' // help: declare '<' on 'Ticket' import Allocator::{ Allocator, SystemAllocator }; import Collections::{ CollectionError, PriorityQueue }; import Io::PrintLine; // A support ticket. A higher priority is more urgent; among equals, the one that arrived first // should be served first, so it counts as the larger. pub struct Ticket { priority: int32; arrival: int32; subject: char8[..]; } extend Ticket { pub func <(self: &Ticket, other: Ticket) -> bool { if self.priority != other.priority { return self.priority < other.priority; } return self.arrival > other.arrival; } } // A timer that goes off at a given second. The earliest should come out first, so its `<` is // reversed: a later timer counts as the smaller. pub struct Timer { at: int32; name: char8[..]; } extend Timer { pub func <(self: &Timer, other: Timer) -> bool { return self.at > other.at; } } func Main() -> ! CollectionError { var system = SystemAllocator(); let allocator: Allocator = system; // `Push` may need more room, and so can fail; `?` hands that failure to `Main`. var tickets = PriorityQueue(allocator); tickets.Push(Ticket { priority: 1, arrival: 1, subject: "typo on the pricing page" })?; tickets.Push(Ticket { priority: 3, arrival: 2, subject: "checkout is down" })?; tickets.Push(Ticket { priority: 2, arrival: 3, subject: "password reset email is late" })?; tickets.Push(Ticket { priority: 3, arrival: 4, subject: "site is slow" })?; tickets.Push(Ticket { priority: 1, arrival: 5, subject: "dark mode request" })?; // `Peek` looks at the front without taking it out. It returns a pointer, valid until the // queue next changes, or `none` when the queue is empty. match tickets.Peek() { top? => PrintLine("next up: {} ({} waiting)", top.subject, tickets.Length()), none => PrintLine("no tickets") } // `Pop` takes the front out and returns it, or `none` once the queue is empty. loop { let ticket = tickets.Pop() ?? break; PrintLine(" priority {} #{} {}", ticket.priority, ticket.arrival, ticket.subject); } PrintLine("empty: {}", tickets.IsEmpty()); // The same queue over the reversed `<` hands out the earliest time first. var timers = PriorityQueue(allocator); timers.Push(Timer { at: 30, name: "autosave" })?; timers.Push(Timer { at: 5, name: "blink the cursor" })?; timers.Push(Timer { at: 60, name: "check mail" })?; timers.Push(Timer { at: 12, name: "refresh the feed" })?; loop { let timer = timers.Pop() ?? break; PrintLine("at {:2}s {}", timer.at, timer.name); } } ``` Besides `Io`, its `Rux.toml` lists `Allocator` and `Collections` under `[Dependencies]`. ## Run it ```sh cd Examples/Collections/PriorityQueue rux run ``` ```text next up: checkout is down (5 waiting) priority 3 #2 checkout is down priority 3 #4 site is slow priority 2 #3 password reset email is late priority 1 #1 typo on the pricing page priority 1 #5 dark mode request empty: true at 5s blink the cursor at 12s refresh the feed at 30s autosave at 60s check mail ``` ## Common mistakes ::mistake **A private `<`.**:br Leave `pub` off the struct or off its `<`, and the queue's code in `Collections` cannot see the operator. Every place it compares reports it as missing: ```text error: operator '<' is not defined for 'Ticket' help: declare '<' on 'Ticket' ``` The operator is declared; it is just not visible from there. Mark both `pub`. :: ::mistake **Expecting first come, first served among equals.**:br A heap keeps no arrival order. Five tickets of the same priority, pushed as #1 to #5 into a queue whose `<` compares only the priority, come out as #1, #5, #4, #3, #2. When equals must keep their order, make the order part of `<`, as `Ticket` does with `arrival`. :: ::mistake **Treating `AsSlice` as sorted.**:br Only its first element is known to be the largest. The tickets above read `3 3 2 1 1` by priority, but that is luck: in general the rest are in heap order, not sorted order. Pop them to get them in order, or [sort](https://rux-lang.dev/docs/learn/sort) a copy. :: ::mistake **Treating `Pop` as an item.**:br`let first: Ticket = tickets.Pop();` fails with: ```text error: cannot assign 'Ticket?' to 'Ticket' ``` The queue may be empty. Say what to do then, with `?? break`, `??` and a default, or a `match`. :: ## Try it yourself 1. Push a sixth ticket of priority 2 that arrives last. Where does it come out, and why? 2. Make a min-queue of plain numbers without a new type: push each value negated into a `PriorityQueue`, and negate what comes out. 3. Before draining the tickets, print `tickets.Peek()` after each `Push`, to watch the front change only when a more urgent ticket arrives. 4. Merge two sorted lists of times into one sorted list with a single `PriorityQueue`. ## Learn more - [Operator overload](https://rux-lang.dev/docs/learn/operator-overload) — declaring `<` for a type of your own - [Comparable](https://rux-lang.dev/docs/learn/comparable) — a type's order as an interface, with three answers - [Tree set](https://rux-lang.dev/docs/learn/tree-set) — every element in order, not just the largest - [Collections API](https://rux-lang.dev/docs/api/collections) — `PriorityQueue` and the other containers - [Operators](https://rux-lang.dev/docs/lang/interfaces/operators) and [Visibility](https://rux-lang.dev/docs/lang/modules/visibility) in the Rux Reference # Bit set ::note **You'll need**: [Bitwise](https://rux-lang.dev/docs/learn/bitwise), [Move](https://rux-lang.dev/docs/learn/move), [Hash set](https://rux-lang.dev/docs/learn/hash-set) :: A [hash set](https://rux-lang.dev/docs/learn/hash-set) can hold anything, and pays for it: every member costs a slot, a hash and the bytes of the value. When the members are small non-negative integers — the days of a month, seat numbers, the ids of a few hundred features — there is a far cheaper way. Give every possible member one bit, and set the bit when the number is in the set. `BitSet` is that set. Thirty days of availability fit in a single 64-bit word, and asking whether day 9 is free is a shift and a mask: ```rux import Collections::{ BitSet, CollectionError }; ``` ## One bit per member The bits live in 64-bit words, member 0 in the lowest bit of the first word. Ann's free days, `2 3 9 10 16 23 30`, are one word with seven bits set — here its low 32 bits, the highest on the left: ```text bit 31 bit 0 0100 0000 1000 0001 0000 0110 0000 1100 ^ ^ ^ ^^ ^^ 30 23 16 10,9 3,2 ``` | Method | Returns | Does | | --------------- | ------------------- | ----------------------------------------------------- | | `Set(i)` | `! CollectionError` | puts `i` in, growing the set to span it | | `Reset(i)` | — | takes `i` out | | `Toggle(i)` | `! CollectionError` | flips `i`, growing the set to span it | | `Get(i)` | `bool` | whether `i` is in — `false` for anything past the end | | `Count()` | `uint` | how many members | | `Length()` | `uint` | how many bits the set spans, set or not | | `NextSet(from)` | `uint?` | the smallest member at or after `from` | | `IsEmpty()` | `bool` | whether no bit is set | `Set` and `Toggle` can fail because a bit past the end needs another word, and that may need memory. `Get` never fails: a bit the set does not span is simply not set, so `ann.Get(99)` is `false`, not an error. ## Walking the members A bit set has no iterator. `NextSet(from)` finds the lowest member at or after `from`, so each answer plus one is where to look next, and the walk visits the members in increasing order: ```rux var from: uint = 0; loop { let day = days.NextSet(from) ?? break; Print(" {}", day); from = day + 1; } ``` `NextSet` skips a whole word of zeros at a time, so walking a sparse set does not visit every bit. ## Combining sets The three set operations change the set they are called on, using another set's bits: | Operation | Keeps | Day picker meaning | | --------------------- | -------------------------- | ------------------ | | `a.UnionWith(b)` | members of `a` or `b` | either is free | | `a.IntersectWith(b)` | members of `a` and `b` | both are free | | `a.DifferenceWith(b)` | members of `a` but not `b` | only Ann is free | Each works a whole word — 64 members — per step. Only `UnionWith` can fail, since it may have to grow to span the other set. A bit set owns its words, so it is [move-only](https://rux-lang.dev/docs/learn/move): `var both = ann;` is refused, and `var both <- ann;` would use Ann's set up. To combine two sets and keep both, build the result in a fresh set: ```rux var both = BitSet(allocator); both.UnionWith(ann)?; both.IntersectWith(ben); ``` ```mermaid flowchart LR ann["ann
2 3 9 10 16 23 30"] --> u["fresh set
UnionWith(ann)"] u --> i["IntersectWith(ben)"] ben["ben
3 4 10 17 23 24"] --> i i --> both["both
3 10 23"] ``` ## Length and count `Length` is how many bits the set spans; `Count` is how many of them are set. After Ann books the 10th she has six free days, but her set still spans 31 bits, because its highest member is 30. The two differ most for a sparse set: one member at 1,000,000 makes a set of `Count` 1 and `Length` 1,000,001 — about 122 KiB of words for a single member. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Collections/BitSet){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // A hash set of small numbers spends many bytes on each one. When the members are small // non-negative integers — the days of a month, seat numbers, the ids of a few hundred features // — one bit per possible member is enough: bit 7 set means 7 is in the set. // // `BitSet` keeps those bits in 64-bit words. A membership test is a shift and a mask, counting // the members is a population count per word, and union, intersection and difference combine // two sets a whole word — 64 members — at a time. Setting a bit past the end grows the set; // asking about a bit past the end answers false, since an absent bit is an unset one. // // A bit set owns its words, so it cannot be copied: // // var both = ann; // error: move-only value 'ann' requires an explicit '<-' in initialization // // Moving it with `<-` would use `ann` up. To combine sets and keep the originals, build the // combination in a new set. import Allocator::{ Allocator, SystemAllocator }; import Collections::{ BitSet, CollectionError }; import Io::{ Print, PrintLine }; // Prints the members in order. `NextSet(from)` finds the lowest set bit at or after `from`, so // each answer plus one is where to look next. func Show(label: char8[..], days: &BitSet) { Print("{:<10}", label); var from: uint = 0; loop { let day = days.NextSet(from) ?? break; Print(" {}", day); from = day + 1; } PrintLine(" ({} days)", days.Count()); } func Main() -> ! CollectionError { var system = SystemAllocator(); let allocator: Allocator = system; // The days of June each person is free. `Set` may need another word, and so can fail. var ann = BitSet(allocator); let annFree: uint[7] = [2, 3, 9, 10, 16, 23, 30]; for day in annFree[..] { ann.Set(day)?; } var ben = BitSet(allocator); let benFree: uint[6] = [3, 4, 10, 17, 23, 24]; for day in benFree[..] { ben.Set(day)?; } Show("ann", ann); Show("ben", ben); PrintLine("ann free on the 9th? {} on the 99th? {}", ann.Get(9), ann.Get(99)); // Days both are free: start from Ann's days and keep only those Ben has too. var both = BitSet(allocator); both.UnionWith(ann)?; both.IntersectWith(ben); Show("both", both); // Days either is free, and days only Ann is free. var either = BitSet(allocator); either.UnionWith(ann)?; either.UnionWith(ben)?; Show("either", either); var annOnly = BitSet(allocator); annOnly.UnionWith(ann)?; annOnly.DifferenceWith(ben); Show("ann only", annOnly); // Plans change: Ann books the 10th, and `Toggle` flips Ben's 17th off and his 18th on. ann.Reset(10); ben.Toggle(17)?; ben.Toggle(18)?; Show("ann now", ann); Show("ben now", ben); // The set spans as many bits as its highest member needed: 31 here, in one word. PrintLine("ann spans {} bits", ann.Length()); } ``` Besides `Io`, its `Rux.toml` lists `Allocator` and `Collections` under `[Dependencies]`. ## Run it ```sh cd Examples/Collections/BitSet rux run ``` ```text ann 2 3 9 10 16 23 30 (7 days) ben 3 4 10 17 23 24 (6 days) ann free on the 9th? true on the 99th? false both 3 10 23 (3 days) either 2 3 4 9 10 16 17 23 24 30 (10 days) ann only 2 9 16 30 (4 days) ann now 2 3 9 16 23 30 (6 days) ben now 3 4 10 18 23 24 (6 days) ann spans 31 bits ``` ## Common mistakes ::mistake **Copying a set to combine it.**:br`var both = ann;` fails with: ```text error: move-only value 'ann' requires an explicit '<-' in initialization ``` Moving it with `var both <- ann;` compiles, but then any later use of `ann` fails with `error: value 'ann' is used after it was moved`. Start from a fresh set and `UnionWith` the one to keep. :: ::mistake **A signed index.**:br Members are `uint`. With `let day: int32 = 5;`, `ann.Set(day)?;` fails with: ```text error: argument 1 to 'Set' has type 'int32', but parameter 'index' requires 'uint' ``` A bit set has no place for a negative member. Convert only after checking the value is not negative. :: ::mistake **Large or scattered numbers.**:br A bit set spans every number up to its largest member. Setting member 1,000,000 alone makes it 1,000,001 bits long — around 122 KiB to hold one number. For a few large or scattered values, a [hash set](https://rux-lang.dev/docs/learn/hash-set) is smaller. :: ::mistake **Shrinking and expecting the bits back.**:br`Resize` to a shorter length drops the bits past it for good. Set 30, resize to 10 and back to 40, and `Get(30)` is `false`. :: ## Try it yourself 1. Add Cai, free on `3 10 11 23 29`, and find the days all three are free. 2. Print the days of June that **nobody** is free: `Set` days 1 to 30 in a fresh set, then take away `either` with `DifferenceWith`. 3. Write the Sieve of Eratosthenes with a `BitSet`: mark every multiple of each prime up to 100, then walk the unmarked numbers from 2 with a loop over `Get`. ## Learn more - [Bitwise](https://rux-lang.dev/docs/learn/bitwise) — the shifts and masks a bit set is made of - [Hash set](https://rux-lang.dev/docs/learn/hash-set) — a set of any type, for members that are not small integers - [Move](https://rux-lang.dev/docs/learn/move) — why a set that owns memory moves rather than copies - [Collections API](https://rux-lang.dev/docs/api/collections) — `BitSet` and the other containers - [Bitwise operators](https://rux-lang.dev/docs/lang/expressions/bitwise) in the Rux Reference # Small vector ::note **You'll need**: [Vector](https://rux-lang.dev/docs/learn/vector), [Move](https://rux-lang.dev/docs/learn/move), [Out parameter](https://rux-lang.dev/docs/learn/out-parameter) :: Many lists are short almost every time: the prime factors of a number, the tags on a post, the children of a tree node, the arguments of a call. A [`Vector`](https://rux-lang.dev/docs/learn/vector) asks its allocator for a block on its first push, so a program that builds a hundred thousand short lists makes a hundred thousand small allocations — each one a trip into the allocator, and each block somewhere else in memory. A `SmallVector` avoids most of them. It carries 64 bytes of room inside itself, and its first elements go there. Only when one more element no longer fits do they all move to a block from the allocator: ```rux import Collections::{ CollectionError, SmallVector }; ``` ## Room inside How many elements fit inline depends on their size: | Element type | Size | Inline capacity | | ----------------------- | -------- | ------------------ | | `uint8` | 1 byte | 64 | | `int32` | 4 bytes | 16 | | `uint64` | 8 bytes | 8 | | a struct of 3 `float64` | 24 bytes | 2 | | a struct over 64 bytes | 72 bytes | 0 — a plain vector | `InlineCapacity` reports it. The program collects prime factors as `uint64`, so eight fit: ```rux let probe = SmallVector(allocator); PrintLine("inline room: {} uint64 values", probe.InlineCapacity()); ``` Eight is plenty for most numbers. Counted with repetition, the smallest number with nine prime factors is 512, or 2⁹, and a typical number around a billion has about three. ## Spilling to the heap ```mermaid flowchart LR s["new small vector"] --> i["elements 1 to 8
inline, no allocation"] i -- "9th push" --> h["all moved to a heap block
of 16, then 32, …"] h -- "pop, truncate, clear" --> h ``` The program pushes each factor with an ordinary `Push`, and `IsInline` says where they ended up: ```rux let place = factors.IsInline() ? "inline" : "on the heap"; PrintLine(" count {}, {}, capacity {}", factors.Length(), place, factors.Capacity()); ``` `9699690`, the product of the first eight primes, fills the inline room exactly and still allocates nothing. `1024` has ten factors: the ninth push moves all of them to a heap block of 16, which then grows as a vector's does. Once on the heap, the elements stay there — popping or truncating back to two does not return them inside, as the last line of the output shows. ## Everything else is a vector Apart from where the elements live, a small vector is used as a vector is: | Method | Returns | Does | | -------------------- | ------------------- | -------------------------------------------------- | | `Push` | `! CollectionError` | adds at the end; may need a block, and so can fail | | `TryPop(@out)` | `bool` | moves the last element out through a pointer | | `Get(i)` | `T?` | a copy of element `i`, `none` past the end | | `AsSlice` | `T[..]` | a view of the elements | | `AsMutableSlice` | `var T[..]` | a writable view | | `Truncate`, `Clear` | — | destroy the elements past a length, or all of them | | `Length`, `Capacity` | `uint` | as for a vector | | `IsEmpty` | `bool` | whether it holds nothing | `TryPop` reports a miss with a `bool` and hands the element back through an [out-parameter](https://rux-lang.dev/docs/learn/out-parameter): ```rux var last: uint64 = 0; if factors.TryPop(@last) { PrintLine("popped {}, {} left", last, factors.Length()); } ``` A small vector owns its elements, so it is [move-only](https://rux-lang.dev/docs/learn/move). `Factor` builds one and hands it back with `return <-factors;`. ## The price The room travels with the small vector, so the small vector itself is larger: 104 bytes for a `SmallVector` against 40 for a `Vector`, whether it holds one element or none. And because its elements may live inside it, they move whenever it moves. A view from `AsSlice` lasts only until the small vector next changes or is moved — a `Push` that spills to the heap moves every element at once. Reach for a small vector when lists are many, short and short-lived, and their usual length is known. For one long list, a plain `Vector` is smaller and simpler. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Collections/SmallVector){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // Many lists are short almost every time: the prime factors of a number, the tags on a post, the // children of a node. A `Vector` asks the allocator for a block on its first push, so a program // that makes thousands of short lists makes thousands of small allocations. // // A `SmallVector` carries 64 bytes of room inside itself. Its first elements go there, and // only an element that no longer fits sends them all to a block from the allocator, where they // stay. That is 16 `int32` values, or 8 `uint64` values; a type larger than 64 bytes gets no // inline room at all and behaves as a plain vector. // // The price is that the small vector itself is larger, and that its elements move when it moves: // a view from `AsSlice` lasts only until the vector next changes or is moved. import Allocator::{ Allocator, SystemAllocator }; import Collections::{ CollectionError, SmallVector }; import Io::{ Print, PrintLine }; // Collects the prime factors of `number`, smallest first, by dividing out each factor in turn. func Factor(allocator: Allocator, number: uint64) -> SmallVector ! CollectionError { var factors = SmallVector(allocator); var rest = number; var divisor: uint64 = 2; while divisor * divisor <= rest { while rest % divisor == 0 { factors.Push(divisor)?; rest = rest / divisor; } divisor = divisor + 1; } if rest > 1 { factors.Push(rest)?; } // A small vector owns its elements and cannot be copied, so it is moved out. A plain // `return factors;` is refused: // // error: move-only value 'factors' requires an explicit '<-' in return // help: prefix the return value with '<-', as in 'return <-factors' return <-factors; } func Main() -> ! CollectionError { var system = SystemAllocator(); let allocator: Allocator = system; // `InlineCapacity` is how many elements fit in the 64 bytes. let probe = SmallVector(allocator); PrintLine("inline room: {} uint64 values", probe.InlineCapacity()); let numbers: uint64[5] = [97, 360, 9699690, 1024, 3072000]; for number in numbers[..] { let factors = Factor(allocator, number)?; Print("{:>8} =", number); for factor in factors.AsSlice() { Print(" {}", factor); } // `IsInline` says whether the elements still live inside the small vector. let place = factors.IsInline() ? "inline" : "on the heap"; PrintLine(" count {}, {}, capacity {}", factors.Length(), place, factors.Capacity()); } // A small vector also pops, truncates and clears like a vector. Once its elements have moved // to the heap they stay there, even when only a few are left. var factors = Factor(allocator, 1024)?; var last: uint64 = 0; if factors.TryPop(@last) { PrintLine("popped {}, {} left", last, factors.Length()); } factors.Truncate(2); PrintLine("after truncating: {} left, inline: {}", factors.Length(), factors.IsInline()); } ``` Besides `Io`, its `Rux.toml` lists `Allocator` and `Collections` under `[Dependencies]`. ## Run it ```sh cd Examples/Collections/SmallVector rux run ``` ```text inline room: 8 uint64 values 97 = 97 count 1, inline, capacity 8 360 = 2 2 2 3 3 5 count 6, inline, capacity 8 9699690 = 2 3 5 7 11 13 17 19 count 8, inline, capacity 8 1024 = 2 2 2 2 2 2 2 2 2 2 count 10, on the heap, capacity 16 3072000 = 2 2 2 2 2 2 2 2 2 2 2 2 2 3 5 5 5 count 17, on the heap, capacity 32 popped 2, 9 left after truncating: 2 left, inline: false ``` ## Common mistakes ::mistake **Returning it as a copy.**:br A small vector cannot be copied, so `return factors;` fails with: ```text error: move-only value 'factors' requires an explicit '<-' in return help: prefix the return value with '<-', as in 'return <-factors' ``` Write `return <-factors;`. :: ::mistake **Keeping a view across a push.**:br`let view = factors.AsSlice();` points at the inline room. The push that spills to the heap moves every element, and `view` is left pointing at the old place. Take a fresh view after any change — and after moving the small vector itself. :: ::mistake **Expecting large elements inline.**:br The room is 64 bytes, not a number of elements. A struct of three `float64` gets two inline places; a struct larger than 64 bytes gets none, and every push allocates as a vector's would. Check `InlineCapacity()` for your element type. :: ::mistake **Treating `Get` as a value.**:br`let n: int32 = numbers.Get(0);` fails with: ```text error: cannot assign 'int32?' to 'int32' ``` The index may be past the end; handle the `none` with `??` or a `match`. :: ## Try it yourself 1. Factor `510510`, the product of the first seven primes, and `2`. Which stays inline with room to spare? 2. Make a `SmallVector` and push 1 to 20, printing `IsInline()` and `Capacity()` after each push. At which push does it move? 3. Print `sizeof(SmallVector)` beside `sizeof(Vector)`. Why is the difference what it is? ## Learn more - [Vector](https://rux-lang.dev/docs/learn/vector) — the growable array a small vector imitates - [Out-parameter](https://rux-lang.dev/docs/learn/out-parameter) — how `TryPop` hands an element back - [Move](https://rux-lang.dev/docs/learn/move) — why a small vector is returned with `<-` - [Collections API](https://rux-lang.dev/docs/api/collections) — `SmallVector` and the other containers - [Copy and move](https://rux-lang.dev/docs/lang/ownership/copy-and-move) in the Rux Reference # LRU cache ::note **You'll need**: [Hash map](https://rux-lang.dev/docs/learn/hash-map), [Mutable reference](https://rux-lang.dev/docs/learn/mutable-reference) :: A cache keeps answers that were slow to get — a file read from disk, a page fetched over the network, a row from a database — so asking again is quick. A [hash map](https://rux-lang.dev/docs/learn/hash-map) can hold them, but a hash map only grows. A cache that never forgets anything is a memory leak with good intentions, so a real cache needs a size limit and a rule for what to forget. The usual rule is **least recently used**: when the cache is full, forget the entry nobody has asked for in the longest time. What was used a moment ago is likely to be wanted again soon; what has sat untouched is the best guess at what will not be missed. `LruCache` is a map with that rule built in: ```rux import Collections::{ CollectionError, EqualsInt32, HashInt32, LruCache }; ``` ## Making a cache A cache is made like a hash map, plus its capacity: ```rux var cache = LruCache(allocator, 3, HashInt32, EqualsInt32); ``` | Argument | Does | | ------------- | ------------------------------------------- | | `allocator` | Provides the memory for the entries | | `3` | The most entries it keeps | | `HashInt32` | Turns a key into a number, as in a hash map | | `EqualsInt32` | Tells whether two keys are equal | The cache allocates as it fills. Once it holds its full three entries it never allocates again: a new entry reuses the room of the one it evicts. ## Hit or miss The pattern every cache is used with: look the key up; on a **hit**, use the cached value; on a **miss**, do the slow work and put the answer in for next time. ```rux match cache.Get(id) { name? => { PrintLine("user {} hit {}", id, name); return name; }, none => {} } let name = LoadName(id); let evicted = cache.Put(id, name)?; ``` `Get` returns `V?`, `none` on a miss. `Put` returns `K? ! CollectionError`: it may need memory while the cache is filling, and when the cache is full it hands back the key it evicted, so the program can log it, or write the evicted value somewhere before it is lost. ## Recency Both `Get` and `Put` count as a **use**: they move the entry to the front of the recency order. The eviction always takes the entry at the back. Following the program's eight requests through a cache of three, newest first: | Request | Result | Order afterwards | | ------- | -------------- | ---------------- | | 1 | miss | 1 | | 2 | miss | 2 1 | | 3 | miss | 3 2 1 | | 1 | hit | 1 3 2 | | 4 | miss, evicts 2 | 4 1 3 | | 2 | miss, evicts 3 | 2 4 1 | | 1 | hit | 1 2 4 | | 3 | miss, evicts 4 | 3 1 2 | User 1, asked for often, never leaves; users 2, 3 and 4 take turns in the other two places. Six loads for eight requests is the price of a cache smaller than the set of keys being asked for. ```mermaid flowchart LR get["`Get` or `Put`"] -- "moves the entry to" --> front["front:
most recently used"] front --- mid["…"] --- back["back:
least recently used"] full["`Put` of a new key
into a full cache"] -- "evicts" --> back ``` Inside, the entries sit in a vector, linked in recency order, with a hash map from each key to its entry. So `Get`, `Put` and the eviction each cost about the same whatever the capacity. ## Looking without using Sometimes you want to look without changing the order — to print the cache, say, or to check before deciding. Three methods leave the order alone: | Method | Returns | Does | | --------------- | ------- | ---------------------------------------------- | | `Peek(key)` | `V?` | the value, without counting as a use | | `Contains(key)` | `bool` | whether the key is cached | | `KeysByRecency` | `uint` | writes the keys, newest first, into your slice | Because they do not change the cache, they work through a read-only `&LruCache` — while `Get` needs `&var`, since a lookup reorders the entries. `Remove` and `Clear` take entries out by hand. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Collections/LruCache){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // A cache keeps answers that were slow to get — a file read from disk, a page fetched over the // network, a row from a database — so asking again is quick. But memory is finite, so a cache // that only ever grows is a leak with good intentions. It needs a rule for what to forget. // // "Least recently used" is the usual rule: when the cache is full, forget the entry nobody has // asked for in the longest time. Whatever was used a moment ago is likely to be used again soon; // whatever has sat untouched is the best guess at what will not be missed. // // `LruCache` is a map with that rule built in. It is made with a capacity, and the same // two functions as a hash map to hash and compare keys. `Get` and `Put` both count as a use and // move the entry to the front; `Put` into a full cache evicts the entry at the back and tells you // which key it was. Once full, the cache reuses that entry's room, so it never allocates again. import Allocator::{ Allocator, SystemAllocator }; import Collections::{ CollectionError, EqualsInt32, HashInt32, LruCache }; import Io::{ Print, PrintLine }; var Loads: int32 = 0; // Stands in for the slow part: a database lookup of a user's name. It counts its calls. func LoadName(id: int32) -> char8[..] { Loads = Loads + 1; return match id { 1 => "ada", 2 => "brian", 3 => "carmen", 4 => "dmitri", else => "unknown" }; } // Answers from the cache when it can, and loads and caches the name when it cannot. func Name(cache: &var LruCache, id: int32) -> char8[..] ! CollectionError { match cache.Get(id) { name? => { PrintLine("user {} hit {}", id, name); return name; }, none => {} } let name = LoadName(id); let evicted = cache.Put(id, name)?; match evicted { old? => PrintLine("user {} miss {:<6} (evicted user {})", id, name, old), none => PrintLine("user {} miss {}", id, name) } return name; } // Prints the keys from the most to the least recently used. It takes a read-only reference, so it // cannot call `Get`: a lookup moves the entry to the front, which changes the cache. // // let first = cache.Get(1); // error: cannot call 'Get' through immutable reference '&LruCache' // // `Peek` and `Contains` read without counting as a use, and work through `&`. func ShowOrder(cache: &LruCache) { var keys: int32[3] = [0; 3]; let count = cache.KeysByRecency(keys[..]); Print("recency:"); for key in keys[..count] { Print(" {}", key); } PrintLine(); } func Main() -> ! CollectionError { var system = SystemAllocator(); let allocator: Allocator = system; // Room for three names, keyed by `int32`. var cache = LruCache(allocator, 3, HashInt32, EqualsInt32); let requests: int32[8] = [1, 2, 3, 1, 4, 2, 1, 3]; for id in requests[..] { Name(cache, id)?; } ShowOrder(cache); PrintLine("{} requests, {} loads", requests.length, Loads); // `Peek` reads without counting as a use, so the order does not change. `Contains` asks // without reading the value at all. PrintLine("peek 2: {}", cache.Peek(2) ?? "(not cached)"); PrintLine("has 4: {}", cache.Contains(4)); ShowOrder(cache); } ``` Besides `Io`, its `Rux.toml` lists `Allocator` and `Collections` under `[Dependencies]`. ## Run it ```sh cd Examples/Collections/LruCache rux run ``` ```text user 1 miss ada user 2 miss brian user 3 miss carmen user 1 hit ada user 4 miss dmitri (evicted user 2) user 2 miss brian (evicted user 3) user 1 hit ada user 3 miss carmen (evicted user 4) recency: 3 1 2 8 requests, 6 loads peek 2: brian has 4: false recency: 3 1 2 ``` ## Common mistakes ::mistake **Calling `Get` through a read-only reference.**:br A lookup reorders the cache, so a function that takes `cache: &LruCache` cannot call `Get`: ```text error: cannot call 'Get' through immutable reference '&LruCache' ``` Use `Peek` when you only want to look, or take the cache as `&var` when the lookup should count. :: ::mistake **Ignoring `Put`.**:br`cache.Put(1, "ada");` on its own fails with: ```text error: fallible result of type 'int32? ! CollectionError' is discarded ``` A cache still filling up may run out of memory. Handle the failure, with `?` or `catch`; the evicted key, if you do not need it, can then be dropped. :: ::mistake **Expecting `Peek` to keep an entry alive.**:br Only `Get` and `Put` count as uses. A key that is only ever peeked at drifts to the back and is evicted, however often it is read. :: ::mistake **A capacity of zero.**:br A cache always keeps at least one entry: `LruCache(allocator, 0, HashInt32, EqualsInt32)` makes a cache of capacity 1, which `Capacity()` reports. Choose the capacity from how many entries you can afford to hold. :: ::mistake **Serving stale answers.**:br A cache does not know when the original changes. If a user renames themselves, the cache keeps the old name until the entry is evicted. `Remove` the key when you know the source changed, or `Put` the new value. :: ## Try it yourself 1. Change the capacity to 4 and run again. How many loads now? Then try 2. 2. Reorder the requests so that the cache of three never hits, and so that it misses only three times. 3. After the requests, `Remove(1)` and print the order. Then `Put` user 4 back and see that nothing is evicted. 4. Use the cache for something slow to compute: cache `Fibonacci(n)` worked out the slow recursive way, and count how many calls each request saves. ## Learn more - [Hash map](https://rux-lang.dev/docs/learn/hash-map) — the map an LRU cache is built on - [Mutable reference](https://rux-lang.dev/docs/learn/mutable-reference) — why `Get` needs `&var` - [Collections API](https://rux-lang.dev/docs/api/collections) — `LruCache` and the other containers - [References](https://rux-lang.dev/docs/lang/references/overview) in the Rux Reference # Part 18: Algorithms From here on the course tours the standard packages, and it starts with the one every program reaches for sooner or later. The `Algorithms` package is a set of generic functions over slices: sort them, search them, find their extremes, fold them into one answer. Because every function takes a slice, one function serves an array of any length, part of an array, or the contents of a collection — and none of them ever allocates memory. The last two lessons go a step further: Core's lazy adaptors, which change any iterator item by item, and scans, which keep every step of a fold. ## What you will learn - Sorting a slice in place through a writable view, by the element's own `<` or by an order function of yours. - Searching any slice from the front, and handling the `none` that "not found" is. - Searching sorted data in logarithmic time, and the promise that comes with it. - The smaller of two values, and the position of the smallest in a slice — which may not exist. - Collapsing a slice into one answer with `Fold` and a step function. - Chaining lazy adaptors such as `Map`, `Filter` and `Take` over any iterator, computing each item only when it is asked for. - Running totals and other scans, counting sequences with `Iota`, and a `Midpoint` that cannot overflow. ## Which function? ```mermaid flowchart LR q(["What do you want
from a slice?"]) --> order["to put it in order"] q --> find["to find a value"] q --> ext["its smallest or
largest element"] q --> one["one answer
from every element"] q --> run["the running answer
after every element"] q --> lazy["a changed sequence,
item by item"] order --> sort["`Sort`, `SortDescending`, `SortBy`
(18.1)"] find --> sorted{"is it sorted?"} sorted -- "no, or not sure" --> lin["`IndexOf`, `LastIndexOf`, `Contains`
(18.2)"] sorted -- "yes" --> bin["`BinarySearch`, `LowerBound`, `UpperBound`
(18.3)"] ext --> mm["`MinIndex`, `MaxIndex`
(18.4)"] one --> fold["`Fold`, `FoldRight`
(18.5)"] run --> scan["`PartialSum`, `InclusiveScan`, `ExclusiveScan`
(18.7)"] lazy --> adapt["`Map`, `Filter`, `Take`, …
(18.6)"] ``` The functions share a few habits, and knowing them makes the rest of the package predictable: | Habit | Functions in this part | | --------------------------------------------------- | -------------------------------------------------------------------------------- | | Take a writable view, `var T[..]`, and change it | `Sort`, `SortDescending`, `SortBy`, the scans, `Iota` | | Answer with `uint?`, `none` when there is no answer | `IndexOf`, `LastIndexOf`, `BinarySearch`, `MinIndex`, `MaxIndex` | | Always have an answer | `Contains`, `LowerBound`, `UpperBound`, `Min`, `Max`, `Fold`, `Midpoint` | | Take a named function for the part that varies | `SortBy`, `Fold`, `FoldRight`, `InclusiveScan`, `ExclusiveScan`, `Map`, `Filter` | ## Lessons | | Lesson | What you will learn | | ---- | --------------------------------------------------------------------- | -------------------------------------------------------------- | | 18.1 | [Sort](https://rux-lang.dev/docs/learn/sort) | sort a slice in place | | 18.2 | [Search](https://rux-lang.dev/docs/learn/search) | find a value in a slice, and handle not finding it | | 18.3 | [Binary search](https://rux-lang.dev/docs/learn/binary-search) | find a value in sorted data quickly | | 18.4 | [Min and max](https://rux-lang.dev/docs/learn/min-max) | the smallest and largest values, and the empty case | | 18.5 | [Fold](https://rux-lang.dev/docs/learn/fold) | combine all elements into one value with a function | | 18.6 | [Iterator adaptors](https://rux-lang.dev/docs/learn/iterator-adaptor) | chain lazy steps such as map, filter and take over an iterator | | 18.7 | [Scan](https://rux-lang.dev/docs/learn/scan) | running sums and scans, counting sequences and safe midpoints | ## Before you start The lessons lean on [Slice](https://rux-lang.dev/docs/learn/slice) and [Writable slice](https://rux-lang.dev/docs/learn/writable-slice) from Part 5, [Callback](https://rux-lang.dev/docs/learn/callback) and [Generic](https://rux-lang.dev/docs/learn/generic) from Part 4, [Presence](https://rux-lang.dev/docs/learn/presence) and [Coalesce](https://rux-lang.dev/docs/learn/coalesce) from [Part 8: Optionals](https://rux-lang.dev/docs/learn/optionals), [Comparable](https://rux-lang.dev/docs/learn/comparable), [Iterator](https://rux-lang.dev/docs/learn/iterator) and [Iterable](https://rux-lang.dev/docs/learn/iterable) from Part 12, and [Wrapping arithmetic](https://rux-lang.dev/docs/learn/wrapping-arithmetic) from Part 16. Each lesson's package is in the Examples repository's `Algorithms/` folder: ```sh cd Examples/Algorithms/Sort rux run ``` ## After this part The checkpoint project [Statistics](https://rux-lang.dev/docs/learn/statistics) puts the whole part to work: it sorts, finds extremes and folds slices of numbers into a count, a mean, a variance and a median, including the awkward cases of one value and none. Then [Part 19: Files](https://rux-lang.dev/docs/learn/files) leaves memory behind and reads and writes the disk. For the rules underneath this part, see [Slices](https://rux-lang.dev/docs/lang/slices/overview), [Function types](https://rux-lang.dev/docs/lang/functions/function-types), [Generic functions](https://rux-lang.dev/docs/lang/generics/overview) and [Iteration](https://rux-lang.dev/docs/lang/interfaces/iteration) in the Rux Reference. # Sort ::note **You'll need**: [Writable slice](https://rux-lang.dev/docs/learn/writable-slice), [Callback](https://rux-lang.dev/docs/learn/callback), [Comparable](https://rux-lang.dev/docs/learn/comparable) :: Sorting puts a sequence in order, smallest first. It is the first job of the `Algorithms` package, the standard package this part tours: a set of generic functions that work on slices of any element type. `Sort` rearranges the elements **in place** — where they already are, with nothing copied and nothing allocated — so the array itself comes out in order. Like every standard package, `Algorithms` is a dependency you name in `Rux.toml`, next to `Io`: ```toml [Dependencies] Algorithms = { Namespace = "Rux", Version = "*" } ``` ## Sorting needs a writable view In place means `Sort` writes into your array, so it asks for the kind of slice that may write: `var T[..]`, from [Writable slice](https://rux-lang.dev/docs/learn/writable-slice). ```rux var numbers: int[7] = [5, -8, 3, -1, 6, 0, -4]; Show("start ", numbers); Sort(numbers[..]); Show("sorted ", numbers); ``` `numbers[..]` is a writable view of the whole array. Plain `numbers` would not do: an array turns into a slice on its own, but only into a read-only one, and a sort through a read-only view could not move anything. `Show` takes `int[..]` because it only reads, so plain `numbers` is fine there. Because `Sort` takes a slice, not an array, one function serves every length, any part of an array, and the contents of a [Vector](https://rux-lang.dev/docs/learn/vector), whose `AsMutableSlice` hands out the same kind of writable view. | Argument | `numbers` declared with | Gives | `Sort` accepts it? | | --------------- | ----------------------- | --------------------------------- | ---------------------- | | `numbers` | `var` | a read-only view | no | | `numbers[..]` | `var` | a writable view of every element | yes | | `numbers[1..6]` | `var` | a writable view of indexes 1 to 5 | yes — sorts only those | | `numbers[..]` | `let` | a read-only view | no | ## Three ways to order `Sort` uses the element's own `<`, so the result runs from smallest to largest. `SortDescending` turns that round: ```rux SortDescending(numbers[..]); Show("descending ", numbers); ``` When the order you want is not the type's own, `SortBy` takes it as a function. Given two elements, the function answers with an `Ordering` — `Less`, `Equal` or `Greater` — the same three answers [Comparable](https://rux-lang.dev/docs/learn/comparable) introduced. This one orders numbers by their distance from zero, whatever the sign: ```rux func ByMagnitude(left: int, right: int) -> Ordering { if Magnitude(left) < Magnitude(right) { return Ordering::Less; } if Magnitude(right) < Magnitude(left) { return Ordering::Greater; } return Ordering::Equal; } ``` The function is passed by name, the way [Callback](https://rux-lang.dev/docs/learn/callback) passed one — not called: ```rux SortBy(numbers[..], ByMagnitude); ``` ```mermaid flowchart LR s["`SortBy(numbers[..], ByMagnitude)`"] --> pick["picks a pair,
such as `6` and `-8`"] pick --> ask["asks `ByMagnitude(6, -8)`"] ask --> ans{"the answer"} ans -- "`Less`" --> a["`6` belongs first"] ans -- "`Greater`" --> b["`-8` belongs first"] ans -- "`Equal`" --> c["either order will do"] ``` `SortBy` repeats that with other pairs until the slice is in order. It decides which pairs to ask about and how often; your function only ever answers for one pair. `Ordering` lives in `Core`, which is why the lesson imports `Core::Ordering` and lists `Core` as a dependency. ## Sorting part of an array A range picks out part of the array, and only that part is sorted: ```rux var part: int[7] = [9, 7, 5, 3, 1, 8, 6]; Sort(part[1..6]); Show("middle only ", part); ``` `1..6` covers indexes 1 to 5. The 9 at index 0 and the 6 at index 6 are outside the view, so they stay exactly where they were, and the output reads `9 1 3 5 7 8 6`. ## Equal elements may swap `Sort` and `SortBy` are not **stable**: elements the order calls equal may come out in either order. With `ByMagnitude`, `-1` and `1` are equal, so a slice holding both may put either one first. The sort is deterministic — the same input gives the same output every time — but it promises nothing about ties. Usually that does not matter. When it does — sort a table by one column, then by another, and you want the first order kept within each group — `StableSort` and `StableSortBy` keep equal elements in the order they arrived. The price is storage: they ask you for a `scratch` slice as long as the one being sorted, because the `Algorithms` package never allocates memory on its own. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Algorithms/Sort){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // Sorting puts a sequence in order, smallest first. `Sort`, from the Algorithms package, sorts in // place: it rearranges the elements where they already are instead of building a sorted copy, so // nothing is allocated and the array itself comes out in order. // // That is why it asks for a writable slice, `var T[..]`, the kind the WritableSlice lesson // introduced. Because it takes a slice rather than an array, the same function sorts an array of // any length, a part of one, or the contents of a vector. // // `Sort` uses the element's own `<`. `SortBy` takes the order as a function instead: given two // elements it answers `Less`, `Equal` or `Greater`, the `Ordering` from the Comparable lesson. // Neither sort is stable, so elements the order calls equal may end up in either order. import Algorithms::{ Sort, SortBy, SortDescending }; import Core::Ordering; import Io::{ Print, PrintLine }; func Show(label: char8[..], items: int[..]) { Print("{}", label); for item in items { Print(" {}", item); } PrintLine(); } func Magnitude(value: int) -> int { return value < 0 ? -value : value; } // A custom order: closest to zero first, whatever the sign. func ByMagnitude(left: int, right: int) -> Ordering { if Magnitude(left) < Magnitude(right) { return Ordering::Less; } if Magnitude(right) < Magnitude(left) { return Ordering::Greater; } return Ordering::Equal; } func Main() -> int { var numbers: int[7] = [5, -8, 3, -1, 6, 0, -4]; Show("start ", numbers); // `numbers[..]` asks for a writable view of the whole array. Writing just `Sort(numbers)` is // rejected: an array becomes a slice on its own, but only a read-only one. Sort(numbers[..]); Show("sorted ", numbers); SortDescending(numbers[..]); Show("descending ", numbers); // The function is passed by name, not called. `SortBy` calls it whenever it compares a pair. SortBy(numbers[..], ByMagnitude); Show("by magnitude", numbers); // A range sorts just that part. The two ends are left where they were. var part: int[7] = [9, 7, 5, 3, 1, 8, 6]; Sort(part[1..6]); Show("middle only ", part); return 0; } ``` Besides `Io`, its `Rux.toml` lists `Algorithms` and `Core` under `[Dependencies]`. ## Run it ```sh cd Examples/Algorithms/Sort rux run ``` ```text start 5 -8 3 -1 6 0 -4 sorted -8 -4 -1 0 3 5 6 descending 6 5 3 0 -1 -4 -8 by magnitude 0 -1 3 -4 5 6 -8 middle only 9 1 3 5 7 8 6 ``` ## Common mistakes ::mistake **Passing the array itself.**:br`Sort(numbers)` fails with: ```text error: argument 1 to 'Sort' has type 'int[7]', but parameter 'items' requires 'var T[..]' ``` An array becomes a read-only view on its own; write `Sort(numbers[..])` to hand over a writable one. :: ::mistake **Sorting a `let` array.**:br Declare the array with `let` and even `Sort(numbers[..])` fails, this time naming `'int[..]'` — a read-only view. A view can never grant more than its array allows, so an array you mean to sort must be `var`. :: ::mistake **Sorting a type that has no `<`.**:br Sort an array of a struct that declares no `<` and the error appears inside the package, with a note naming the call that instantiated the sort and a help line: ```text error: operator '<' is not defined for 'P' help: declare '<' on 'P' ``` Either give the struct a `<`, as in [Operator overload](https://rux-lang.dev/docs/learn/operator-overload), or sort it with `SortBy` and an order function. :: ::mistake **Calling the order function instead of passing it.**:br`SortBy(numbers[..], ByMagnitude(1, 2))` is rejected. `ByMagnitude(1, 2)` is one `Ordering` value, not a way to compare; pass the name alone and let `SortBy` do the calling. :: ::mistake **A range that runs past the end.**:br`Sort(part[1..9])` on a seven-element array compiles, and when it runs, stops the program with: ```text Panic: index out of range ``` The view is checked when it is made, before anything is sorted. :: ## Try it yourself 1. Sort an array of `float64` values, and then an array of `char8` letters. Nothing about `Sort` changes. 2. Sort only the first three elements of `numbers` with `numbers[..3]`, and predict the output before you run it. 3. Write an order function `ByLastDigit` for non-negative numbers that compares `value % 10`, and sort `[42, 17, 5, 30, 21]` with it. 4. Sort `[3, -1, -3, 1, 2, -2]` with `SortBy` and `ByMagnitude`. Then sort it with `StableSortBy(mixed[..], scratch[..], ByMagnitude)`, where `scratch` is a `var int[6]`, and check that each pair of equals keeps its original order. ## Learn more - [Slicing](https://rux-lang.dev/docs/lang/arrays/overview#arrays-as-slices) and [Function types](https://rux-lang.dev/docs/lang/functions/function-types) in the Rux Reference - [Writable slice](https://rux-lang.dev/docs/learn/writable-slice) — the `var T[..]` view a sort writes through - [Comparable](https://rux-lang.dev/docs/learn/comparable) — `Ordering`, and giving your own types an order - [Binary search](https://rux-lang.dev/docs/learn/binary-search) — what sorted data lets you do quickly # Search ::note **You'll need**: [Slice](https://rux-lang.dev/docs/learn/slice), [Presence](https://rux-lang.dev/docs/learn/presence), [Coalesce](https://rux-lang.dev/docs/learn/coalesce) :: A **linear search** looks at the elements one by one, from the front, until it finds what it wants. It works on any slice, sorted or not, and it takes time in proportion to the length: twice the elements, twice the looking. The interesting part is not the looking but the answer, because the value you want may not be there at all. ## "Where is it?" may have no answer `IndexOf` returns the position of the first element equal to the value. No position could honestly say "nowhere": 0 is a real position, and a made-up one such as the length is easy to use by mistake. So the answer is an optional index, `uint?`, and it is `none` when nothing matched — the [Optional](https://rux-lang.dev/docs/learn/optional) idea from Part 8. `Report` takes the answer apart with a [presence](https://rux-lang.dev/docs/learn/presence) match before it uses it: ```rux func Report(rolls: int[..], value: int) { match IndexOf(rolls, value) { at? => PrintLine("{} first appears at {}", value, at), none => PrintLine("{} was never rolled", value) } } ``` Inside the `at?` arm, `at` is a plain `uint` you can print or index with. Outside the match there is only the `uint?`, and the compiler will not let you treat it as a position until you have looked. ```rux let rolls: int[8] = [4, 2, 6, 6, 1, 3, 6, 5]; Report(rolls, 1); Report(rolls, 6); Report(rolls, 7); ``` 1 appears once, at index 4. 6 appears three times; `IndexOf` reports the earliest, index 2. 7 is not there, so the `none` arm runs. ## Three questions, three functions | Function | Question | Answer | | --------------------------- | --------------------------- | ------------------------- | | `IndexOf(items, value)` | where does it first appear? | `uint?` — `none` if never | | `LastIndexOf(items, value)` | where does it last appear? | `uint?` — `none` if never | | `Contains(items, value)` | is it there at all? | `bool` | `LastIndexOf` searches from the back, which matters only when the value appears more than once: for 6 it reports index 6, not 2. `Contains` answers the plainer question with a plain `bool`, so there is nothing to unwrap: ```rux PrintLine("contains 5 {}", Contains(rolls, 5)); PrintLine("contains 0 {}", Contains(rolls, 0)); ``` The `Algorithms` package has more in the same family: `Count` says how many elements equal a value, and `IndexWhere` finds the first element a function of yours accepts, for searches that are not about equality. ## A stand-in with `??` When a missing value has an obvious stand-in, [`??`](https://rux-lang.dev/docs/learn/coalesce) supplies it: ```rux let at = IndexOf(rolls, 7) ?? rolls.length; PrintLine("7 at {} of {}", at, rolls.length); ``` `at` is now a plain `uint`. The length works as "past the end", but notice what has happened: the type no longer says "maybe absent", so the code that reads `at` has to remember that 8 means "not found". Use the stand-in when that meaning is obvious and local; keep the `uint?` when it travels further. ## Positions are relative to the slice A search of part of an array reports positions within that part: ```rux let tail = rolls[4..]; PrintLine("6 in the tail at {}", IndexOf(tail, 6) ?? tail.length); ``` `tail` starts at index 4 of `rolls`, so its own index 2 is index 6 of the array. `IndexOf` only ever sees the slice it is given, and has no idea where that slice came from. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Algorithms/Search){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // A linear search looks at the elements one by one, from the front, until it finds what it wants. // It works on any slice, sorted or not, and takes time in proportion to the length. // // `IndexOf` answers "where is it?". The value might not be there at all, and no index could // honestly say so: 0 is a real position, and a made-up one such as the length is easy to use by // mistake. So the answer is an optional index, `uint?`, which is `none` when nothing matched, and // the program has to look before it can use the position. // // `Contains` answers the plainer question "is it there?" with a `bool`. `LastIndexOf` searches // from the back, which matters only when the value appears more than once. import Algorithms::{ Contains, IndexOf, LastIndexOf }; import Io::PrintLine; func Report(rolls: int[..], value: int) { match IndexOf(rolls, value) { at? => PrintLine("{} first appears at {}", value, at), none => PrintLine("{} was never rolled", value) } } func Main() -> int { let rolls: int[8] = [4, 2, 6, 6, 1, 3, 6, 5]; // Present once, present three times, and absent. With several matches, `IndexOf` reports the // earliest. Report(rolls, 1); Report(rolls, 6); Report(rolls, 7); match LastIndexOf(rolls, 6) { at? => PrintLine("6 last appears at {}", at), none => PrintLine("6 was never rolled") } PrintLine("contains 5 {}", Contains(rolls, 5)); PrintLine("contains 0 {}", Contains(rolls, 0)); // When a missing value has an obvious stand-in, `??` supplies it. Here the length works as // "past the end", but now the code has to remember that it means "not found". let at = IndexOf(rolls, 7) ?? rolls.length; PrintLine("7 at {} of {}", at, rolls.length); // A search of part of the array reports positions within that part, not within the array. let tail = rolls[4..]; PrintLine("6 in the tail at {}", IndexOf(tail, 6) ?? tail.length); return 0; } ``` Besides `Io`, its `Rux.toml` lists `Algorithms` under `[Dependencies]`. ## Run it ```sh cd Examples/Algorithms/Search rux run ``` ```text 1 first appears at 4 6 first appears at 2 7 was never rolled 6 last appears at 6 contains 5 true contains 0 false 7 at 8 of 8 6 in the tail at 2 ``` ## Common mistakes ::mistake **Using the answer as an index before looking.**:br`rolls[IndexOf(rolls, 6)]` fails with: ```text error: index for type 'int[8]' must be an integer or range, but has type 'uint?' ``` Match it, or supply a stand-in with `??`, and index with the plain `uint` you get out. :: ::mistake **Doing arithmetic on the optional.**:br`IndexOf(rolls, 6) + 1` fails with: ```text error: operator '+' cannot combine left operand 'uint?' with right operand 'int' ``` "One past nowhere" means nothing, so the absent case has to be dealt with first. :: ::mistake **Forgetting where a slice starts.**:br`IndexOf(rolls[4..], 6)` reports 2, not 6. Add the slice's starting index back when you need a position in the whole array. :: ::mistake **Searching for a value of another type.**:br`Contains(rolls, 2.5)` is rejected: `T` cannot be both the `int` of the elements and the `float64` of the value. The value must have the element type. :: ## Try it yourself 1. Use `Count(rolls, 6)` to print how many sixes were rolled. Remember to add `Count` to the import. 2. Write `func IsHigh(value: int) -> bool` that accepts rolls above 4, and print the result of `IndexWhere(rolls, IsHigh) ?? rolls.length`. 3. Change `Report` to also print the last position, using `LastIndexOf`, but only when it differs from the first. 4. Search a string. Declare `let text: char8[..] = "rux-lang";` and `let dash: char8 = '-';`, then print `IndexOf(text, dash) ?? text.length`. Then try `IndexOf(text, '-')` and work out why it is rejected: a character literal with no typed partner is a `char`, not a `char8`. ## Learn more - [Slices](https://rux-lang.dev/docs/lang/slices/overview) in the Rux Reference - [Presence](https://rux-lang.dev/docs/learn/presence) and [Coalesce](https://rux-lang.dev/docs/learn/coalesce) — the two ways to use an optional answer - [Binary search](https://rux-lang.dev/docs/learn/binary-search) — a much faster search, when the data is sorted - [Min and max](https://rux-lang.dev/docs/learn/min-max) — another search whose answer may be `none` # Binary search ::note **You'll need**: [Search](https://rux-lang.dev/docs/learn/search), [Sort](https://rux-lang.dev/docs/learn/sort) :: [Search](https://rux-lang.dev/docs/learn/search) looked at every element in turn. When the slice is already **sorted**, that is wasted effort. A **binary search** checks the middle element, throws away the half that cannot hold the value, and repeats on the half that is left. Every step halves the work, so a million elements take about twenty steps instead of a million. ## Halving, step by step `BinarySearch` answers like `IndexOf`, with a `uint?` that is `none` when the value is absent: ```rux func Report(sorted: int[..], value: int) { match BinarySearch(sorted, value) { at? => PrintLine("{} found at {}", value, at), none => PrintLine("{} not found, would go at {}", value, LowerBound(sorted, value)) } } ``` Here is how it finds 8 in `[2, 3, 5, 5, 5, 8, 13, 21]`. It keeps a range of positions that may still hold the answer and looks at the middle one: | Step | Still in play | Middle | Element there | So the answer is… | | ---- | ------------- | ------ | ------------- | -------------------- | | 1 | 0 to 7 | 4 | 5 | after 4: keep 5 to 7 | | 2 | 5 to 7 | 6 | 13 | before 6: keep 5 | | 3 | 5 | 5 | 8 | found at 5 | ```mermaid flowchart LR start["the whole slice
is in play"] --> mid["look at the middle element"] mid --> q{"`middle < value?`"} q -- "yes" --> right["keep the half
after the middle"] q -- "no" --> left["keep the middle
and the half before it"] right --> more{"anything
left in play?"} left --> more more -- "yes" --> mid more -- "no" --> done["the position is found:
is the value there?"] ``` Three looks instead of six. The search never reads 2, 3 or 21 at all — and it can only skip them because the order promises what they hold. ## Where a value would go Notice what the search actually narrows down to: a **position**, the first one whose element is not less than the value. `LowerBound` returns exactly that, and `BinarySearch` is `LowerBound` plus one check — is the element at that position equal to the value? So `LowerBound` is useful even when the value is absent. It says where the value *would* go to keep the slice sorted: ```rux Report(sorted, 4); Report(sorted, 99); ``` 4 belongs at index 2, between the 3 and the first 5. 99 is larger than everything, so its place is 8, the length — one past the end. A position always exists, so `LowerBound` returns a plain `uint`, never `none`. ## Bracketing duplicates `UpperBound` is the last position where the value could go: one past the last equal element. Between the two bounds lie all the equal elements: ```rux let first = LowerBound(sorted, 5); let after = UpperBound(sorted, 5); PrintLine("5 runs from {} to {}, {} of them", first, after, after - first); ``` The 5s occupy indexes 2, 3 and 4, so the bounds are 2 and 5, and `after - first` counts them without a scan. With duplicates, `BinarySearch` reports the first of them — index 2 — because it is built on `LowerBound`. | Function | Returns | Means | | ---------------------------- | ------- | ------------------------------------------- | | `BinarySearch(items, value)` | `uint?` | where an equal element is; `none` if absent | | `LowerBound(items, value)` | `uint` | the first place the value could go | | `UpperBound(items, value)` | `uint` | the last place the value could go | ## The promise nothing checks A binary search is only correct on sorted data, and nothing checks that the data is sorted. Checking would mean reading every element — the very scan a binary search exists to avoid. On unsorted data it still answers, and the answer is meaningless: ```rux let shuffled: int[3] = [9, 1, 5]; Report(shuffled, 9); ``` 9 is right there at index 0. But the first look lands on the 1 in the middle; in sorted data, everything before a 1 would be smaller than 9, so the search drops that half and never looks left again. It reports 9 as not found. Sort first, with [Sort](https://rux-lang.dev/docs/learn/sort), or keep the data sorted as you add to it — `LowerBound` tells you where each new value goes. When in doubt, `IsSorted(items)` answers with a `bool`, at the cost of the full scan. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Algorithms/BinarySearch){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // When a slice is already sorted, a search does not have to look at every element. A binary // search checks the middle, discards the half that cannot hold the value, and repeats, so a // million elements take about twenty steps instead of a million. // // `BinarySearch` answers like `IndexOf`, with a `uint?`. With duplicates it reports the first. // `LowerBound` answers a different question: the first position where the value could be // inserted without breaking the order. That is a position, not a match, so it is a plain `uint` // and never `none`. `UpperBound` is the last such position, and the equal elements lie between. // // The surprise is the promise that comes with it. The slice must be sorted, and nothing checks: // checking would cost the very scan a binary search exists to avoid. On unsorted data the search // still answers, and the answer is meaningless. import Algorithms::{ BinarySearch, LowerBound, UpperBound }; import Io::PrintLine; func Report(sorted: int[..], value: int) { match BinarySearch(sorted, value) { at? => PrintLine("{} found at {}", value, at), none => PrintLine("{} not found, would go at {}", value, LowerBound(sorted, value)) } } func Main() -> int { let sorted: int[8] = [2, 3, 5, 5, 5, 8, 13, 21]; Report(sorted, 8); Report(sorted, 4); Report(sorted, 99); // Three 5s. The bounds bracket them, and their difference counts them without a scan. let first = LowerBound(sorted, 5); let after = UpperBound(sorted, 5); PrintLine("5 runs from {} to {}, {} of them", first, after, after - first); Report(sorted, 5); // 9 is present, but the data is not sorted. The first step looks at the 1 in the middle, // concludes 9 must be to its right, and never looks left again. let shuffled: int[3] = [9, 1, 5]; Report(shuffled, 9); return 0; } ``` Besides `Io`, its `Rux.toml` lists `Algorithms` under `[Dependencies]`. ## Run it ```sh cd Examples/Algorithms/BinarySearch rux run ``` ```text 8 found at 5 4 not found, would go at 2 99 not found, would go at 8 5 runs from 2 to 5, 3 of them 5 found at 2 9 not found, would go at 3 ``` ## Common mistakes ::mistake **Searching data that is not sorted.**:br Nothing stops `BinarySearch` on unsorted data, and nothing reports it either: the program compiles, runs and prints a wrong answer, as the `[9, 1, 5]` example shows. The only cure is to sort first, or to know the data arrives sorted. :: ::mistake **Matching a bound as if it were optional.**:br A bound is always a position. `match LowerBound(sorted, 4) { at? => …, none => … }` fails with: ```text error: a presence suffix needs an optional subject, but the matched value has type 'uint' ``` And `LowerBound(sorted, 4) ?? 0` fails with: ```text error: operator '??' requires an optional left operand, but found 'uint' ``` :: ::mistake **Reading the lower bound as a match.**:br`LowerBound(sorted, 4)` is 2, and the element at index 2 is a 5, not a 4. A bound says where a value would go, not that it is there. Compare the element with the value, or use `BinarySearch`, before treating the position as a hit. :: ## Try it yourself 1. Search for 2 and for 21, the two ends. How many steps does each take? Trace them as the table does. 2. Count the 4s in `sorted` with `UpperBound` and `LowerBound`. What do the two bounds tell you when the count is zero? 3. Call `EqualRange(sorted, 5)`. It returns a range; print its `start` and `end` and compare them with the bounds above. 4. Print `IsSorted(shuffled)`, then sort `shuffled` with `Sort` (it must become `var`) and search for 9 again. ## Learn more - [Ranges](https://rux-lang.dev/docs/lang/ranges/overview) in the Rux Reference - [Search](https://rux-lang.dev/docs/learn/search) — the linear search that works on anything - [Sort](https://rux-lang.dev/docs/learn/sort) — getting the data into the order a binary search needs - [Tree map](https://rux-lang.dev/docs/learn/tree-map) — a collection that keeps its keys sorted for you # Min and max ::note **You'll need**: [Search](https://rux-lang.dev/docs/learn/search), [Presence](https://rux-lang.dev/docs/learn/presence) :: "Which is smaller?" is a question about two values, and it always has an answer. "Which is the smallest?" is a question about a slice, and it has none when the slice is empty. The `Algorithms` package answers the two questions with different functions, and the difference is in their return types. ## The smaller of two `Min` and `Max` take two values and return one of them, unchanged: ```rux PrintLine("Min(3, 8) = {}", Min(3, 8)); PrintLine("Max(3, 8) = {}", Max(3, 8)); PrintLine("Max(-2.5, -7.0) = {}", Max(-2.5, -7.0)); ``` They are generic, so they work for any type with `<` — integers, floats, characters, and your own types once they declare `<`. Both arguments must have the same type, which is why the last line writes `-7.0` and not `-7`: a lone `-7` is an `int`, and `Max` cannot take an `int` and a `float64` at once. A third function in the family, `Clamp(value, low, high)`, keeps a value inside a range: it returns `low` for anything below it, `high` for anything above, and the value itself otherwise. ## The smallest of many Over a slice there may be nothing to compare. Rather than invent an answer for an empty slice, `MinIndex` and `MaxIndex` return an optional index, `uint?`, which is `none` when the slice is empty: ```rux func Report(temperatures: int[..]) { match MinIndex(temperatures) { day? => PrintLine("coldest: day {} at {}", day, temperatures[day]), none => PrintLine("coldest: no readings") } match MaxIndex(temperatures) { day? => PrintLine("warmest: day {} at {}", day, temperatures[day]), none => PrintLine("warmest: no readings") } } ``` They return the **position**, not the value. The position is the more useful answer — it says *which* day was coldest, not just how cold — and the value is one index away: `temperatures[day]`. ```mermaid flowchart LR s["`MinIndex(temperatures)`"] --> q{"is the slice empty?"} q -- "yes" --> n["`none`:
no readings"] q -- "no" --> w["walk the elements,
keeping the first smallest"] w --> i["`day?`
its index, a `uint`"] i --> v["`temperatures[day]`
is the value"] ``` | Function | Takes | Returns | Empty input | | ----------------- | ---------- | ------- | ------------- | | `Min(a, b)` | two values | `T` | cannot happen | | `Max(a, b)` | two values | `T` | cannot happen | | `MinIndex(items)` | a slice | `uint?` | `none` | | `MaxIndex(items)` | a slice | `uint?` | `none` | ## Ties go to the earliest ```rux let week: int[7] = [-3, 4, 11, 0, 11, 6, -3]; Report(week); ``` Day 4 is as warm as day 2, and day 6 as cold as day 0. Both functions report the **earlier** day: 0 for the coldest and 2 for the warmest. That is a promise, not an accident, so you can rely on it — the first coldest day is always the one you get. ## The empty case ```rux Report(week[..0]); ``` `week[..0]` is a view of no elements at all — the same array, cut down to nothing. There is nothing to compare, so both matches take their `none` arm. Without the optional, the function would have to return something for this case: index 0, which does not exist here, or a made-up number the caller could mistake for a real day. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Algorithms/MinMax){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // `Min` and `Max` pick the smaller or larger of two values. They work for any type with `<`, // numbers included, and return one of the two unchanged. // // Over a whole slice the question changes, because a slice may be empty, and an empty slice has // no smallest element. Rather than invent one, `MinIndex` and `MaxIndex` answer with an optional // index, `uint?`, which is `none` for an empty slice. They give the position, not the value: the // position is the more useful answer (it says *which* day, not just how cold), and the value is // one index away. // // When several elements tie, both report the earliest. That is a promise, not an accident. import Algorithms::{ Max, MaxIndex, Min, MinIndex }; import Io::PrintLine; func Report(temperatures: int[..]) { match MinIndex(temperatures) { day? => PrintLine("coldest: day {} at {}", day, temperatures[day]), none => PrintLine("coldest: no readings") } match MaxIndex(temperatures) { day? => PrintLine("warmest: day {} at {}", day, temperatures[day]), none => PrintLine("warmest: no readings") } } func Main() -> int { PrintLine("Min(3, 8) = {}", Min(3, 8)); PrintLine("Max(3, 8) = {}", Max(3, 8)); PrintLine("Max(-2.5, -7.0) = {}", Max(-2.5, -7.0)); // Day 4 is as warm as day 2, and day 6 as cold as day 0: the earlier day is reported. let week: int[7] = [-3, 4, 11, 0, 11, 6, -3]; Report(week); // An empty view of the same array, `[..0]`. Nothing to compare, so `none` both times. Report(week[..0]); return 0; } ``` Besides `Io`, its `Rux.toml` lists `Algorithms` under `[Dependencies]`. ## Run it ```sh cd Examples/Algorithms/MinMax rux run ``` ```text Min(3, 8) = 3 Max(3, 8) = 8 Max(-2.5, -7.0) = -2.5 coldest: day 0 at -3 warmest: day 2 at 11 coldest: no readings warmest: no readings ``` ## Common mistakes ::mistake **Mixing an integer literal with a float.**:br`Max(-2.5, -7)` fails with: ```text error: argument 1 to 'Max' has type 'float64', but parameter 'left' requires 'T' ``` With no typed partner, `-7` is an `int` and `-2.5` a `float64`, so no single `T` fits both. Write `-7.0`. :: ::mistake **Treating the index as the value.**:br`let cold: int = MinIndex(week);` fails with: ```text error: cannot assign 'uint?' to 'int' ``` The answer is an optional position: match it, then read `week[day]`. :: ::mistake **Passing a slice to `Min`.**:br`Min(week)` fails with: ```text error: call to 'Min' expects 2 arguments, but 1 was provided ``` `Min` compares two values; for the smallest element of a slice, use `MinIndex`. :: ## Try it yourself 1. Print `Clamp(15, 0, 10)`, `Clamp(-3, 0, 10)` and `Clamp(7, 0, 10)`. Remember to import `Clamp`. 2. Add a second week of readings and print the coldest day of each, then the colder of the two coldest values with `Min`. 3. Report only the first three days with `week[..3]`. Which day is the warmest now? 4. Use `Min` and `Max` on two `char8` values. Which letter is "smaller"? ## Learn more - [Search](https://rux-lang.dev/docs/learn/search) — the other search whose answer may be `none` - [Presence](https://rux-lang.dev/docs/learn/presence) — matching `day?` and `none` - [Fold](https://rux-lang.dev/docs/learn/fold) — combining every element into one answer, of which the minimum is one example - [Number limit](https://rux-lang.dev/docs/learn/number-limit) — the smallest and largest values a type can hold, which is a different question # Fold ::note **You'll need**: [Callback](https://rux-lang.dev/docs/learn/callback), [Slice](https://rux-lang.dev/docs/learn/slice), [Literal](https://rux-lang.dev/docs/learn/literal) :: Many loops over a slice share one shape: start with an answer, walk the elements, and update the answer from each one. A total, a product, a count. `Fold` is that loop written once, so you only write the part that differs — the update. ## The step function You give `Fold` three things: the slice, the starting answer, and a **step** function. The step takes the answer so far and one element, and returns the new answer: ```rux func Add(total: int, value: int) -> int { return total + value; } ``` ```rux let values: int[5] = [3, -1, 4, -1, 5]; PrintLine("sum {}", Fold(values, 0, Add)); PrintLine("product {}", Fold(values, 1, Multiply)); ``` `Fold` calls `Add` once per element, feeding each answer into the next call: ```mermaid flowchart LR s(["`0`"]) -- "`Add(0, 3)`" --> a["`3`"] a -- "`Add(3, -1)`" --> b["`2`"] b -- "`Add(2, 4)`" --> c["`6`"] c -- "`Add(6, -1)`" --> d["`5`"] d -- "`Add(5, 5)`" --> e(["`10`"]) ``` Written as one expression, `Fold(items, initial, step)` computes `step(…step(step(initial, a), b)…, z)`. The product works the same way from a start of 1 — the value that leaves a product unchanged, as 0 leaves a sum unchanged. The step is a named function, passed by name as in [Callback](https://rux-lang.dev/docs/learn/callback). Rux has no closures, so a step cannot reach into the caller's local variables: everything it needs arrives as its two arguments. ## The starting answer The starting answer is also what an empty slice gives back, untouched: ```rux PrintLine("empty sum {}", Fold(values[..0], 0, Add)); ``` There are no elements, so `Add` is never called, and the result is the 0 that went in. That is why the start matters: a sum must start at 0 and a product at 1, or every answer is off by the starting value — and the empty case shows it most plainly. ## Left or right When the step is like `+`, the order of the elements does not change the answer. When it is not, it does. `AppendDigit` shifts a number one decimal place left and puts the digit in the gap: ```rux func AppendDigit(number: int, digit: int) -> int { return number * 10 + digit; } ``` `Fold` walks from the front; `FoldRight` walks from the back, with the same step: ```rux let digits: int[3] = [4, 0, 7]; PrintLine("left {}", Fold(digits, 0, AppendDigit)); PrintLine("right {}", FoldRight(digits, 0, AppendDigit)); ``` | Call | Steps | Result | | ----------------------------------- | ---------------- | ------ | | `Fold(digits, 0, AppendDigit)` | 0 → 4 → 40 → 407 | 407 | | `FoldRight(digits, 0, AppendDigit)` | 0 → 7 → 70 → 704 | 704 | ## The answer need not be an element Nothing says the answer has the element's type. `Fold` has two type parameters: `T` for the elements and `A` for the answer, and the step is a `func(A, T) -> A`. This step counts `int` elements into a `uint`: ```rux func CountNegative(count: uint, value: int) -> uint { return value < 0 ? count + 1 : count; } ``` ```rux PrintLine("negatives {}", Fold(values, 0, CountNegative)); ``` The unsuffixed `0` takes its type from the step function — `A` is `uint` — just as a literal takes the type of its partner in [Literal](https://rux-lang.dev/docs/learn/literal). For the two most common folds, the package has them ready-made: `Sum(items, initial)` adds with `+` and `Product(items, initial)` multiplies with `*`, so `Sum(values, 0)` is 10 with no step function to write. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Algorithms/Fold){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // Many loops over a slice share one shape: start with an answer, walk the elements, and update // the answer from each one. A total, a product, a count. `Fold` is that loop written once. You // give it the slice, the starting answer, and a *step* function, which takes the answer so far and // one element and returns the new answer: // // Fold(items, initial, step) computes step(...step(step(initial, a), b)..., z) // // The step must be a named function, passed by name as in the Callback lesson. Rux has no // closures, so a step cannot reach into the caller's locals; everything it needs arrives as its // two arguments. Note also that the answer need not have the element's type: the last step below // counts `int` elements into a `uint`. import Algorithms::{ Fold, FoldRight }; import Io::PrintLine; func Add(total: int, value: int) -> int { return total + value; } func Multiply(product: int, value: int) -> int { return product * value; } // Shifts the number one decimal place left and puts the digit in the gap. func AppendDigit(number: int, digit: int) -> int { return number * 10 + digit; } func CountNegative(count: uint, value: int) -> uint { return value < 0 ? count + 1 : count; } func Main() -> int { let values: int[5] = [3, -1, 4, -1, 5]; PrintLine("sum {}", Fold(values, 0, Add)); PrintLine("product {}", Fold(values, 1, Multiply)); // The starting answer is what an empty slice gives back, untouched. PrintLine("empty sum {}", Fold(values[..0], 0, Add)); // Order matters when the step is not like `+`. `FoldRight` walks from the back. let digits: int[3] = [4, 0, 7]; PrintLine("left {}", Fold(digits, 0, AppendDigit)); PrintLine("right {}", FoldRight(digits, 0, AppendDigit)); // The answer here is a `uint`. The unsuffixed `0` takes that type from the step function. PrintLine("negatives {}", Fold(values, 0, CountNegative)); return 0; } ``` Besides `Io`, its `Rux.toml` lists `Algorithms` under `[Dependencies]`. ## Run it ```sh cd Examples/Algorithms/Fold rux run ``` ```text sum 10 product 60 empty sum 0 left 407 right 704 negatives 2 ``` ## Common mistakes ::mistake **Giving the start a type of its own.**:br With `let start = 0;`, the call `Fold(values, start, CountNegative)` fails with: ```text error: argument 2 to 'Fold' has type 'int', but parameter 'initial' requires 'uint' ``` A bare literal adapts to the step; a variable already has its type. Declare it `let start: uint = 0;`. :: ::mistake **Writing the step inline.**:br`Fold(values, 0, func(c: uint, v: int) -> uint { … })` fails to parse: ```text error: expected an expression after ',' in the argument list before 'func' ``` Rux has no closures or inline functions. Declare the step as a named function and pass its name. :: ::mistake **Parameters in the wrong order.**:br The step takes the answer first and the element second. A `CountNegative(value: int, count: uint)` does not fit `func(A, T) -> A`, and the call is rejected. :: ::mistake **Calling the step instead of passing it.**:br`Fold(values, 0, Add(0, 1))` passes the number 1, not a function, and is rejected. Write `Add` alone. :: ## Try it yourself 1. Write `func Larger(best: int, value: int) -> int` and fold `values` with it to find the largest value. What should the starting answer be? Why is 0 wrong when every value is negative, and why does `values[0]` work? 2. Count the even numbers in `values` into a `uint`. 3. Print `Sum(values, 0)` and `Product(values, 1)`, and check them against the folds above. 4. Fold `digits` with `AppendDigit` starting from 9 instead of 0. Predict both results first. ## Learn more - [Function types](https://rux-lang.dev/docs/lang/functions/function-types) and [Generic functions](https://rux-lang.dev/docs/lang/generics/overview) in the Rux Reference - [Callback](https://rux-lang.dev/docs/learn/callback) — passing a function by name - [Generic](https://rux-lang.dev/docs/learn/generic) — functions with type parameters, such as `T` and `A` here - [Min and max](https://rux-lang.dev/docs/learn/min-max) — ready-made answers to two common folds # Iterator adaptors ::note **You'll need**: [Iterator](https://rux-lang.dev/docs/learn/iterator), [Iterable](https://rux-lang.dev/docs/learn/iterable), [Callback](https://rux-lang.dev/docs/learn/callback) :: The [Iterator](https://rux-lang.dev/docs/learn/iterator) lesson built a type whose `Next` hands out one item at a time, and `for` walked it. Very often the walk you want is a small change to one you already have: the same scores, curved; only the passes; the second page of results; each item with its position. Writing a new iterator type for every such change would be tedious. An **adaptor** is an iterator that wraps another one and changes what comes out. Core provides seven, and because each adaptor is an iterator too, they nest: ```rux import Core::{ Chain, Enumerate, Filter, Indexed, Map, Skip, Take, Walk, Zip }; ``` ## Cursors and `Walk` An adaptor takes anything whose `Next` returns `T?`. Core calls that shape a `Cursor`, and these all have it: - a container's iterator, such as a [vector](https://rux-lang.dev/docs/learn/vector)'s `Iterate()`; - an iterator type of your own, like the program's `Counter`; - another adaptor. A slice does not: `for` walks a slice directly, but it has no `Next`. `Walk` wraps one in a cursor, so a chain over a slice starts there: ```rux for score in Map(Walk(scores[..]), Curve) { Print(" {}", score); } ``` ## The seven adaptors | Adaptor | Hands out | Item type | | ----------------- | ------------------------------------------------------ | ---------------- | | `Map(c, f)` | `f(item)` for each item | what `f` returns | | `Filter(c, keep)` | the items for which `keep(item)` is `true` | same as `c` | | `Take(c, n)` | the first `n` items, then stops | same as `c` | | `Skip(c, n)` | everything after the first `n` items | same as `c` | | `Enumerate(c)` | each item with its position, counting from 0 | `Indexed` | | `Zip(a, b)` | an item from each, side by side, until either runs out | `Pair` | | `Chain(a, b)` | every item of `a`, then every item of `b` | same as both | `Map` and `Filter` take a named function, as a [callback](https://rux-lang.dev/docs/learn/callback). `Indexed` has the fields `index` and `item`; `Pair` has `first` and `second`. No type arguments are written anywhere. Each adaptor works its item type out from the cursor it wraps, and from the function's return type for `Map`. ## Reading a chain A chain reads from the inside out. The innermost call is the source; each call around it is one more step: ```rux for score in Filter(Map(Walk(scores[..]), Curve), Passed) { Print(" {}", score); } ``` Walk the scores, curve each, keep the passes. The order matters: filtering before curving would test the raw scores, and fail the 45 and 49 that the curve lifts to 50 and 54. In the same way, `Enumerate` before `Filter` keeps the original positions — the program reports the failures at 1, 3 and 5 — where `Enumerate` after `Filter` would number the survivors 0, 1, 2. ## Lazy Building a chain computes nothing. When `for` asks the outermost adaptor for an item, it asks the one inside it, and so on down to the source, one item at a time: ```mermaid flowchart TD f["`for` wants an item"] --> t["`Take`: fewer than 3 handed out?
Then ask `Filter`"] t --> fi["`Filter`: ask `Map` again
until an item is even"] fi --> m["`Map`: ask `Counter`,
square the answer"] m --> c["`Counter`: hand out
the next number"] ``` So no list of intermediate results is ever built, and a chain can draw on a source that never ends. The program's `Counter` counts up for ever, and prints each time it is asked: ```rux for value in Take(Filter(Map(Counter { next: 1 }, Square), IsEven), 3) { Print(" -> {}", value); } ``` The output shows each number asked for just before the result it leads to, and the asking stops at 6: after the third even square, `Take` stops asking. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Algorithms/IteratorAdaptor){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // An iterator hands out one item each time its `Next` is called. An adaptor is an iterator that // wraps another one and changes what comes out: `Map` passes each item through a function, // `Filter` drops the items that fail a test, `Take` stops after a number of them, and so on. // Core provides seven, and because each is an iterator itself they nest, each one wrapping the // next: // // Take(Filter(Map(source, Square), IsEven), 3) // // Read that from the inside out: square each item, keep the even squares, stop after three. // // Adaptors are lazy. Building the chain computes nothing; each adaptor asks the one inside it // for an item only when it is itself asked for one. So no list of results is ever built, and a // chain can even draw from a source that never ends, as long as something stops asking. // // An adaptor takes anything whose `Next` returns `T?` — Core calls that a `Cursor`. That is // a container's iterator, another adaptor, or a slice turned into one by `Walk`. import Core::{ Chain, Enumerate, Filter, Indexed, Map, Skip, Take, Walk, Zip }; import Io::{ Print, PrintLine }; // Counts up from a number, for ever, and says each time it is asked. struct Counter { next: int32; } extend Counter { func Next(self: &var Counter) -> int32? { Print(" (asked: {})", self.next); self.next = self.next + 1; return self.next - 1; } } func Curve(score: int32) -> int32 { return score + 5; } func Passed(score: int32) -> bool { return score >= 50; } func Failed(entry: Indexed) -> bool { return entry.item < 50; } func Square(value: int32) -> int32 { return value * value; } func IsEven(value: int32) -> bool { return value % 2 == 0; } func Main() -> int { let names: char8[..][6] = ["ada", "ben", "cai", "dee", "eve", "fay"]; let scores: int32[6] = [72, 45, 90, 38, 66, 49]; // A slice is not an iterator; `Walk` makes one. `Map` then hands out each score curved. // Leave out the `Walk` and the slice fails the bound: // // for score in Map(scores[..], Curve) { ... } // error: type argument 'int32[..]' does not satisfy interface bound 'Cursor' on type // parameter 'I' Print("curved: "); for score in Map(Walk(scores[..]), Curve) { Print(" {}", score); } PrintLine(); // Adaptors nest: curve every score, then keep the passes. Print("passed: "); for score in Filter(Map(Walk(scores[..]), Curve), Passed) { Print(" {}", score); } PrintLine(); // `Skip` and `Take` cut out a window: the second page of two. Print("page 2: "); for score in Take(Skip(Walk(scores[..]), 2), 2) { Print(" {}", score); } PrintLine(); // `Enumerate` pairs each item with its position, as an `Indexed`, so a filter after // it still knows where each item stood. Print("failed at:"); for entry in Filter(Enumerate(Walk(scores[..])), Failed) { Print(" {}", entry.index); } PrintLine(); // `Zip` walks two sources side by side, as a `Pair`, and stops when either runs out. for pair in Take(Zip(Walk(names[..]), Walk(scores[..])), 3) { PrintLine("{} {}", pair.first, pair.second); } // `Chain` reads one source to its end, then the other. let late: int32[2] = [81, 57]; Print("all: "); for score in Chain(Walk(scores[..]), Walk(late[..])) { Print(" {}", score); } PrintLine(); // Laziness: the counter never ends, yet it is asked for only six numbers, one at a time as // each result is wanted, because `Take` stops asking once it has handed out three. Print("lazy: "); for value in Take(Filter(Map(Counter { next: 1 }, Square), IsEven), 3) { Print(" -> {}", value); } PrintLine(); return 0; } ``` Besides `Io`, its `Rux.toml` lists `Core` under `[Dependencies]`. ## Run it ```sh cd Examples/Algorithms/IteratorAdaptor rux run ``` ```text curved: 77 50 95 43 71 54 passed: 77 50 95 71 54 page 2: 90 38 failed at: 1 3 5 ada 72 ben 45 cai 90 all: 72 45 90 38 66 49 81 57 lazy: (asked: 1) (asked: 2) -> 4 (asked: 3) (asked: 4) -> 16 (asked: 5) (asked: 6) -> 36 ``` ## Common mistakes ::mistake **Passing a slice straight in.**:br`Map(scores[..], Curve)` fails with: ```text error: type argument 'int32[..]' does not satisfy interface bound 'Cursor' on type parameter 'I' ``` A slice has no `Next`. Wrap it: `Map(Walk(scores[..]), Curve)`. :: ::mistake **A function of the wrong shape.**:br`Filter` wants a test, `func(T) -> bool`. Give it `Curve`, which returns `int32`, and the call fails — but the message points at the first argument: ```text error: argument 1 to 'Filter' has type 'SliceCursor', but parameter 'source' requires 'I' ``` When an adaptor call is refused like this, check the function's parameter and return types against the table above. :: ::mistake **Expecting the cursor you passed in to move.**:br An adaptor works on its own copy. After `for score in Take(cursor, 2) { … }`, `cursor.Next()` still returns the first score, `72`. Make the cursor inside the call, or move it in with `<-cursor`, so nobody is tempted to use it afterwards. :: ::mistake **An endless source with nothing to stop it.**:br`for value in Map(Counter { next: 1 }, Square) { … }` never ends: nothing in the chain ever says `none`. Over an endless source, put a `Take` in the chain, or `break` out of the loop. :: ## Try it yourself 1. Print the names of the students who passed after the curve: `Zip` the names with the curved scores, then `Filter` the pairs. 2. Print the scores with a rank, starting from 1, using `Enumerate` and `entry.index + 1`. 3. `Chain` `scores` and `late`, `Skip` the first five and `Take` two. Predict the output before you run it. 4. Write a cursor `Repeat` that hands out the same value for ever, and `Zip` it with the scores. ## Learn more - [Iterator](https://rux-lang.dev/docs/learn/iterator) — the `Next` method every adaptor is built on - [Iterable](https://rux-lang.dev/docs/learn/iterable) — types that hand out an iterator for `for` - [Callback](https://rux-lang.dev/docs/learn/callback) — passing `Curve` and `Passed` by name - [Fold](https://rux-lang.dev/docs/learn/fold) — collapsing a slice into one answer - [Core API](https://rux-lang.dev/docs/api/core) — `Cursor`, `Walk` and the adaptors - [Iteration](https://rux-lang.dev/docs/lang/interfaces/iteration) and [Generic bounds](https://rux-lang.dev/docs/lang/generics/bounds) in the Rux Reference # Scan ::note **You'll need**: [Fold](https://rux-lang.dev/docs/learn/fold), [Writable slice](https://rux-lang.dev/docs/learn/writable-slice), [Wrapping arithmetic](https://rux-lang.dev/docs/learn/wrapping-arithmetic), [Overload](https://rux-lang.dev/docs/learn/overload) :: [Fold](https://rux-lang.dev/docs/learn/fold) collapses a slice into one answer: a week's sales into one total. A **scan** keeps every step of the way instead — the total so far after each day. That running answer is a slice of its own, as long as the input, and it answers questions a single total cannot: on which day did the sales pass 100, what was the best day up to Friday, where in a file does record 3 begin. This lesson's functions come from the `Algorithms` package, like the rest of the part: ```rux import Algorithms::{ ExclusiveScan, InclusiveScan, Iota, Midpoint, PartialSum }; ``` ## Running totals `PartialSum` writes the running sums of a slice into a [writable slice](https://rux-lang.dev/docs/learn/writable-slice) you supply. Element `i` of the result is the sum of the first `i + 1` inputs: ```rux var total: int32[7] = [0; 7]; PartialSum(sales[..], total[..]); ``` | day | 1 | 2 | 3 | 4 | 5 | 6 | 7 | | ----- | -- | -- | -- | -- | -- | --- | --- | | sales | 12 | 30 | 7 | 25 | 18 | 40 | 9 | | total | 12 | 42 | 49 | 74 | 92 | 132 | 141 | The last running total is what `Fold` with `+` would have returned; the scan keeps the six before it too. The sales passed 100 on day 6. The scans allocate nothing: you provide the destination. It may even be the input itself — each element is read before its result is written — so `PartialSum(values[..], values[..])` turns a slice into its running sums in place. A destination shorter than the input is refused: the function returns `false` and writes nothing. ## Any combination `InclusiveScan` is the same scan with a function of yours in place of `+`. With `Larger`, each place holds the best day so far — a running maximum: ```rux var best: int32[7] = [0; 7]; InclusiveScan(sales[..], best[..], Larger); ``` `PartialSum` is `InclusiveScan` with `+`. A running product, a running minimum, a running bitwise or: each is one small function away. ## Everything before `ExclusiveScan` writes, at each place, the combination of everything **before** it, starting from a value you give. Its classic use is turning lengths into offsets. Records of 14, 6, 22 and 10 bytes stored one after another start at the sum of the lengths before each: ```rux let lengths: int32[4] = [14, 6, 22, 10]; var offsets: int32[4] = [0; 4]; ExclusiveScan(lengths[..], offsets[..], 0, Add); ``` ```mermaid flowchart LR r0["record 0
offset 0
14 bytes"] --> r1["record 1
offset 14
6 bytes"] r1 --> r2["record 2
offset 20
22 bytes"] r2 --> r3["record 3
offset 42
10 bytes"] ``` | Function | Element `i` of the result | First element | | --------------- | -------------------------------------------- | ------------- | | `PartialSum` | the first `i + 1` inputs added | `items[0]` | | `InclusiveScan` | the first `i + 1` inputs combined | `items[0]` | | `ExclusiveScan` | `initial` combined with the first `i` inputs | `initial` | `ExclusiveScan` has no `+` built in, so the program passes `Add`, a two-line function. The last length, 10, takes part in no offset; add it to the last offset to get the total size, 52. ## Counting sequences `Iota` fills a slice with `start`, `start + step`, `start + 2 * step` and so on. The program uses it for the day numbers: ```rux var days: int32[7] = [0; 7]; Iota(days[..], 1, 1); ``` ## A midpoint that cannot overflow Halfway between `low` and `high` looks like `(low + high) / 2`. Binary search does it on every step. But the sum can be too large for the type even when the answer is not. Two positions near the top of `int32`: ```rux let low: int32 = 2000000000; let high: int32 = 2100000000; PrintLine("(low + high) / 2 {}", (low + high) / 2); PrintLine("Midpoint {}", Midpoint(low, high)); ``` The true sum, 4,100,000,000, is past `int32`'s largest value of 2,147,483,647, so `+` [wraps round](https://rux-lang.dev/docs/learn/wrapping-arithmetic) to −194,967,296, and halving that gives the nonsense `-97483648`. The bug is famous: it sat for years in the binary search of Java's standard library, waiting for an array of a billion elements. `Midpoint` never forms the sum. It takes the **distance** between the two — which, for any two `int32` values, fits in a `uint32` — halves that, and steps from `low` towards `high`: ```text low + (high − low) / 2 = 2000000000 + 100000000 / 2 = 2050000000 ``` There is one `Midpoint` for each of `int32`, `int64`, `uint32`, `uint64` and `float64`, each right across that type's whole range. With an odd distance there is no exact middle, and integers round **towards the first argument**: `Midpoint(3i32, 8i32)` is 5, but `Midpoint(8i32, 3i32)` is 6. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Algorithms/Scan){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // `Fold` collapses a slice into one answer: the total of a month's sales. A scan keeps every // step of the way instead: the total so far after each day. That running answer is a slice of // its own, as long as the input, and it answers questions a single total cannot — when did the // sales pass 100, what was the best day up to Friday, where does record 4 start in a file. // // `PartialSum` writes the running sums; `InclusiveScan` does the same with any combining function; // `ExclusiveScan` writes, at each place, the combination of everything *before* it. All three // write into a writable slice that you supply, which may be the input itself, and refuse one that // is too short by returning false. `Iota` fills a slice with a counting sequence. // // `Midpoint` finds the number halfway between two others. That sounds like `(a + b) / 2`, but // the sum can be too large for the type even when the answer is not, and then it wraps round to // a nonsense value. `Midpoint` never forms the sum, so it is right for any two values. import Algorithms::{ ExclusiveScan, InclusiveScan, Iota, Midpoint, PartialSum }; import Io::{ Print, PrintLine }; func Larger(left: int32, right: int32) -> int32 { return left > right ? left : right; } func Add(left: int32, right: int32) -> int32 { return left + right; } func Show(label: char8[..], values: int32[..]) { Print("{:<10}", label); for value in values { Print("{:>5}", value); } PrintLine(); } func Main() -> int { // A week's sales, and the day numbers 1 to 7 to label them: start at 1, step by 1. let sales: int32[7] = [12, 30, 7, 25, 18, 40, 9]; var days: int32[7] = [0; 7]; Iota(days[..], 1, 1); Show("day", days[..]); Show("sales", sales[..]); // The total so far after each day. var total: int32[7] = [0; 7]; PartialSum(sales[..], total[..]); Show("total", total[..]); // The best day so far: the same scan, combining with `Larger` instead of `+`. var best: int32[7] = [0; 7]; InclusiveScan(sales[..], best[..], Larger); Show("best", best[..]); // Records of these lengths sit one after another in a file. Where does each start? At the // sum of the lengths before it — an exclusive scan from 0. let lengths: int32[4] = [14, 6, 22, 10]; var offsets: int32[4] = [0; 4]; ExclusiveScan(lengths[..], offsets[..], 0, Add); Show("length", lengths[..]); Show("offset", offsets[..]); // A destination too short is refused, and left as it was. var short: int32[3] = [0; 3]; PrintLine("fits in 3? {}", PartialSum(sales[..], short[..])); // Halfway between two large positions. Their sum, 4100000000, does not fit in an `int32`, so // `(low + high) / 2` wraps round to a negative number. `Midpoint` takes the distance between // them instead — always representable as a `uint32` — and adds half of it to `low`. let low: int32 = 2000000000; let high: int32 = 2100000000; PrintLine("(low + high) / 2 {}", (low + high) / 2); PrintLine("Midpoint {}", Midpoint(low, high)); // With an odd distance there is no exact middle; integers round towards the first argument. // There is one `Midpoint` per type, so a bare literal, which several of them accept, needs // its type written: // // Midpoint(3, 8) // error: call to 'Midpoint' is ambiguous: 4 overloads accept argument types (int, int) PrintLine("Midpoint(3, 8) {}", Midpoint(3i32, 8i32)); PrintLine("Midpoint(8, 3) {}", Midpoint(8i32, 3i32)); return 0; } ``` Besides `Io`, its `Rux.toml` lists `Algorithms` under `[Dependencies]`. ## Run it ```sh cd Examples/Algorithms/Scan rux run ``` ```text day 1 2 3 4 5 6 7 sales 12 30 7 25 18 40 9 total 12 42 49 74 92 132 141 best 12 30 30 30 30 40 40 length 14 6 22 10 offset 0 14 20 42 fits in 3? false (low + high) / 2 -97483648 Midpoint 2050000000 Midpoint(3, 8) 5 Midpoint(8, 3) 6 ``` ## Common mistakes ::mistake **Bare literals to `Midpoint`.**:br There is one `Midpoint` per type, and an unsuffixed literal fits several of them, so `Midpoint(3, 8)` fails with: ```text error: call to 'Midpoint' is ambiguous: 4 overloads accept argument types (int, int) ``` Give the literals a type, `Midpoint(3i32, 8i32)`, or pass variables that have one. :: ::mistake **Ignoring a refused destination.**:br A destination shorter than the input is not half filled: the scan returns `false` and writes nothing. The program's `PartialSum` into three places prints `fits in 3? false`. A scan whose answer is ignored leaves the destination as it was — all zeros here — with no sign that anything went wrong. Size the destination from the input, or check the `bool`. :: ::mistake **Running totals that outgrow the type.**:br The scans add with the element type's own `+`, which wraps. The running sums of two `int32` values of 2,000,000,000 are `2000000000` and `-294967296`. Scan in a wider type — `int64` — when the totals can grow large. :: ::mistake **Forgetting the last element of an exclusive scan.**:br`ExclusiveScan` stops before the last input: the offsets `0 14 20 42` say nothing about the 10 bytes of the last record. The total size is the last offset plus the last length, 52. :: ## Try it yourself 1. Find the first day on which the running total passes 100 by searching `total` — it is sorted, since sales are never negative. 2. Write `Smaller` and compute the running minimum of the sales. 3. Use `Iota` with a step of 7 to list the first days of five weeks starting on day 1. 4. Write a binary search over `total` that uses `Midpoint` for the middle index, and look up the day the total reached 92. ## Learn more - [Fold](https://rux-lang.dev/docs/learn/fold) — one answer from a whole slice, where a scan keeps them all - [Binary search](https://rux-lang.dev/docs/learn/binary-search) — the search whose midpoint must not overflow - [Wrapping arithmetic](https://rux-lang.dev/docs/learn/wrapping-arithmetic) — what `+` does past the largest value - [Overload](https://rux-lang.dev/docs/learn/overload) — why `Midpoint` needs a typed argument - [Algorithms API](https://rux-lang.dev/docs/api/algorithms) — the scans, `Iota` and `Midpoint` - [Arithmetic](https://rux-lang.dev/docs/lang/expressions/arithmetic) and [Overloading](https://rux-lang.dev/docs/lang/functions/overloading) in the Rux Reference # Part 19: Files Everything so far has lived in memory and vanished when the program ended. A file is how data outlives the program — and it is also where a program meets a world it does not control: names that are not valid text, disks that fill up, files that someone else deletes or reads half-written. This part tours the `Path` package, which names files, and the `FileSystem` package, which reads, writes and manages them, and it handles every failure along the way. It ends with `Io`'s memory streams, which run the same reading and writing code with no file at all. ## What you will learn - Why a path is not a string, and how `OsString`, `Path` and `PathBuffer` take one apart, build one and tidy one. - Opening, writing, reading and closing a file, with `IoError` handled at every step — including the end of the file, which arrives as a failure. - Making, listing and removing directories, and asking the filesystem what a name refers to. - Writing fixed-width binary records, and refusing one that the file cut short. - Gathering small writes in a buffer, and knowing when the bytes really reach the file. - Replacing a file so that no reader ever sees it half-written, and scratch files that clean up after themselves. - Reading and writing bytes in memory through the same `Reader` and `Writer` code as a file, so a format can be tested without the disk. ## A file's life Every lesson here covers a piece of one sequence: turn text into a path, open the file, move bytes, close it — and check each step, because each one asks the operating system for something it may refuse. ```mermaid sequenceDiagram participant P as Program participant F as `File` participant OS as Operating system Note over P: `OsString::FromText(text)?`
`Path::FromView(…)` P->>F: `File::Open(path, Writing())?` F->>OS: create the file, or empty it P->>F: `WriteAll(file, bytes)?` F->>OS: `Write`, again and again until every byte is out P->>F: `Close()?` OS-->>P: success, or a failure delayed until now P->>F: `File::Open(path, Reading())?` loop until the end of the file P->>F: `Read(buffer[..])` F-->>P: a count of bytes, or an `IoError` end Note over P: `IsEnd()` is `true`: the file is read P->>F: `Close()?` P->>OS: `DeleteFile(path)?` ``` | You want to… | Use | Lesson | | -------------------------------------------- | ---------------------------------- | ---------------------------------------------------------------- | | take a path apart | `Components`, `FileName`, `Parent` | [Path](https://rux-lang.dev/docs/learn/path) | | build a path from pieces | `Join`, `PathBuffer::Push` | [Path join](https://rux-lang.dev/docs/learn/path-join) | | compare or display paths | `Normalize` | [Path normalize](https://rux-lang.dev/docs/learn/path-normalize) | | read or write a text file | `File::Open`, `WriteAll`, `Read` | [File](https://rux-lang.dev/docs/learn/file) | | list a directory | `ReadDirectory`, `Next` | [Directory](https://rux-lang.dev/docs/learn/directory) | | ask whether a file exists, and what it is | `MetadataOf` | [Metadata](https://rux-lang.dev/docs/learn/metadata) | | store numbers as bytes | `WriteUint32`, `ReadUint32`, … | [Binary](https://rux-lang.dev/docs/learn/binary) | | make many small writes cheaply | `BufferedWriter` | [Buffered I/O](https://rux-lang.dev/docs/learn/buffered-io) | | replace a file without a half-written moment | `WriteAtomically`, `AtomicWrite` | [Atomic file](https://rux-lang.dev/docs/learn/atomic-file) | | scratch space that removes itself | `TemporaryFile` | [Temporary file](https://rux-lang.dev/docs/learn/temporary-file) | | run file code on bytes in memory | `ByteWriter`, `ByteReader` | [Memory streams](https://rux-lang.dev/docs/learn/memory-stream) | ## Lessons | | Lesson | What you will learn | | ----- | ---------------------------------------------------------------- | -------------------------------------------------------------------------------------- | | 19.1 | [Path](https://rux-lang.dev/docs/learn/path) | split a path into its parts, and see why a path is not a string | | 19.2 | [Path join](https://rux-lang.dev/docs/learn/path-join) | build a path from parts | | 19.3 | [Path normalize](https://rux-lang.dev/docs/learn/path-normalize) | tidy a path by removing `.` and `..` | | 19.4 | [File](https://rux-lang.dev/docs/learn/file) | write text to a file and read it back, handling failure at every step | | 19.5 | [Directory](https://rux-lang.dev/docs/learn/directory) | create, list, and remove directories | | 19.6 | [Metadata](https://rux-lang.dev/docs/learn/metadata) | ask a file for its size and kind | | 19.7 | [Binary](https://rux-lang.dev/docs/learn/binary) | read and write fixed-width values and raw bytes | | 19.8 | [Buffered I/O](https://rux-lang.dev/docs/learn/buffered-io) | buffer writes and flush them | | 19.9 | [Atomic file](https://rux-lang.dev/docs/learn/atomic-file) | replace a file's contents all at once or not at all | | 19.10 | [Temporary file](https://rux-lang.dev/docs/learn/temporary-file) | a scratch file that cleans up after itself | | 19.11 | [Memory streams](https://rux-lang.dev/docs/learn/memory-stream) | read and write bytes in memory through the same reader and writer interfaces as a file | ## Before you start This part leans hard on [Part 9: Errors](https://rux-lang.dev/docs/learn/errors) — every lesson's `Main` is a [fallible main](https://rux-lang.dev/docs/learn/fallible-main) with an [error sum](https://rux-lang.dev/docs/learn/error-sum) on its failure side, and the lessons use [Catch](https://rux-lang.dev/docs/learn/catch), [Guard](https://rux-lang.dev/docs/learn/guard), [Nested fallible](https://rux-lang.dev/docs/learn/nested-fallible) and [Coalesce exit](https://rux-lang.dev/docs/learn/coalesce-exit). It also uses [Move](https://rux-lang.dev/docs/learn/move) and [Destructor](https://rux-lang.dev/docs/learn/destructor) from Part 11, [Interface value](https://rux-lang.dev/docs/learn/interface-value), [Interface parameter](https://rux-lang.dev/docs/learn/interface-parameter) and [Iterator](https://rux-lang.dev/docs/learn/iterator) from Part 12, [Allocator](https://rux-lang.dev/docs/learn/allocator) from Part 15 and [Endian](https://rux-lang.dev/docs/learn/endian) from Part 16. Each lesson's package is in the Examples repository's `Files/` folder: ```sh cd Examples/Files/File rux run ``` The programs create their files inside their own package's `Bin/` folder and delete them before they finish. If a run stops part-way, a leftover file or `Bin/scratch` directory may need deleting by hand. ## After this part [Part 20: Utilities](https://rux-lang.dev/docs/learn/utilities) covers time, randomness, hashing and UUIDs — including the `Timestamp` that [Metadata](https://rux-lang.dev/docs/learn/metadata) reported. [Part 21: Data formats](https://rux-lang.dev/docs/learn/data-formats) then gives your files a structure, and its checkpoint project, [Notes](https://rux-lang.dev/docs/learn/notes), keeps a to-do list as JSON in a file — saved with `WriteAtomically`, loaded back, and recovered when the file is missing or damaged. The Rux Reference describes the language features these packages are built from: [Interfaces](https://rux-lang.dev/docs/lang/interfaces/overview), the mechanism behind `Reader` and `Writer`, and [Enumerations](https://rux-lang.dev/docs/lang/enums/overview), the shape of `IoErrorKind` and `FileKind`. # Path ::note **You'll need**: [Fallible main](https://rux-lang.dev/docs/learn/fallible-main), [Coalesce](https://rux-lang.dev/docs/learn/coalesce), [Iterator](https://rux-lang.dev/docs/learn/iterator), [Allocator](https://rux-lang.dev/docs/learn/allocator) :: Every file a program touches is named by a **path**: `Bin/reports/summary.txt`. A path looks like a string, and the first lesson of this part is why it is not one. The `Path` package gives paths their own types, and this lesson takes one apart — into its components, its file name, stem and extension, and its parent — without ever asking the disk whether the file exists. ## A path is not text The operating system decides what a file name may hold, and its answer is not "valid text". On Windows a name is a run of 16-bit units that need not form valid UTF-16; on Linux and macOS it is bytes that need not form valid UTF-8. A type that insisted on text could not name every file that exists. So the `Path` package has its own types, built on the units the system uses: | Type | What it is | | -------------- | --------------------------------------------------------------------------------------------------- | | `OsString` | owns a name in the system's own units; needs an allocator | | `OsStringView` | a borrowed, read-only look at such units | | `Path` | a borrowed view with path meaning attached: components, parent, extension | | `PathBuffer` | an owned path that can grow — the subject of [Path join](https://rux-lang.dev/docs/learn/path-join) | Text goes in through `OsString::FromText`, which converts it to the system's units and so needs memory — an `Allocator`, the interface from [Allocator](https://rux-lang.dev/docs/learn/allocator): ```rux var system = SystemAllocator(); let allocator: Allocator = system; var holder = OsString::FromText(allocator, "Bin//reports/summary.txt")?; let path = Path::FromView(holder.View()); ``` `FromText` returns `OsString ! TextError`, so the `?` passes a failure on, and `Main` is fallible — `func Main() -> ! TextError`, as in [Fallible main](https://rux-lang.dev/docs/learn/fallible-main). The `OsString` is the **holder**: it owns the units. `path` is only a view of them, so the holder must stay alive for as long as the path is used. ```mermaid flowchart LR t["text
`char8[..]`"] -- "`OsString::FromText(…)?`" --> h["`OsString`
owns the units"] h -- "`.View()`" --> v["`OsStringView`"] v -- "`Path::FromView`" --> p["`Path`
a view with path meaning"] p -- "`Components`, `FileName`,
`Stem`, `Extension`, `Parent`" --> parts["more views
of the same units"] p -- "`.AsView().ToText(…)?`" --> s["`String`
text again"] ``` ## Components A path is a sequence of components, and the separators between them belong to the platform: Windows accepts `/` and `\`, the others only `/`. `Components` returns an [iterator](https://rux-lang.dev/docs/learn/iterator), so `for` walks it: ```rux for part in path.Components() { Print(" [{}]", part); } ``` The output is `[Bin] [reports] [summary.txt]`. A run of separators counts as one, so the doubled slash yields no empty component — which is exactly what splitting the text on `"/"` by hand would get wrong. ## Named parts may be missing `FileName`, `Stem` and `Extension` each return an `OsStringView?`, because each can be absent: a root such as `/` has no file name, and `Makefile` has no extension. `ShowPart` matches the optional before printing: ```rux func ShowPart(label: char8[..], part: OsStringView?) { match part { name? => PrintLine("{:10} {}", label, name), none => PrintLine("{:10} (none)", label) } } ``` | Call | For `Bin//reports/summary.txt` | | ------------- | ------------------------------ | | `FileName()` | `summary.txt` | | `Stem()` | `summary` | | `Extension()` | `txt` — without the dot | | `Parent()` | `Bin//reports` | `Parent` drops the last component and returns a `Path?`, absent once there is nothing left to drop. Here [`??`](https://rux-lang.dev/docs/learn/coalesce) supplies an empty `Path()` in that case: ```rux let parent = path.Parent() ?? Path(); ``` The parent keeps the doubled slash: these calls only pick out part of the units, and never rewrite them. Tidying a path is the job of [Path normalize](https://rux-lang.dev/docs/learn/path-normalize). ## Back to text Printing with `{}` always works: any unit that is not text is swapped for the replacement character U+FFFD. That is fine for a message and useless for reopening the file. The exact way back is `ToText`, and it is fallible, because a name from the system may not be text at all: ```rux let text = path.AsView().ToText(allocator)?; ``` Here it succeeds, because this name began as text. A name read from a directory listing comes with no such guarantee. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Files/Path){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // A path looks like a string and is not one. // // The operating system decides what a file name may hold, and its answer is not "valid text". // On Windows a name is 16-bit units that need not form valid UTF-16; on Linux and macOS it is // bytes that need not form valid UTF-8. A type that insisted on text could not name every file // that exists. So the `Path` package has `OsString`, which holds the units the system holds, // and `Path`, a borrowed view of them with path meaning attached. // // That meaning is structure. A path is a sequence of components, and the separators between // them belong to the platform: Windows accepts `/` and `\`, the others only `/`. Runs of // separators count as one, so splitting the text on "/" by hand would invent empty pieces. // Nothing here asks the filesystem anything: a path need not name a file that exists. // // Text goes in through `OsString::FromText` and comes back out through `ToText`. Both return // `T ! TextError`, and the way out is the one that can really fail: a name from the system may // not be text at all. `{}` shows a path anyway, swapping any unit that is not text for U+FFFD, // which is fine for a message and useless for reopening the file. import Allocator::{ Allocator, SystemAllocator }; import Io::{ Print, PrintLine }; import Path::{ OsString, OsStringView, Path }; import Text::TextError; // The named parts are optional: a root has no file name, and `Makefile` has no extension. func ShowPart(label: char8[..], part: OsStringView?) { match part { name? => PrintLine("{:10} {}", label, name), none => PrintLine("{:10} (none)", label) } } func Main() -> ! TextError { var system = SystemAllocator(); let allocator: Allocator = system; var holder = OsString::FromText(allocator, "Bin//reports/summary.txt")?; let path = Path::FromView(holder.View()); PrintLine("{:10} {}", "path", path); // `Components` is an iterator, so `for` walks it. The doubled slash yields no empty part. Print("{:10}", "components"); for part in path.Components() { Print(" [{}]", part); } PrintLine(); ShowPart("file name", path.FileName()); ShowPart("stem", path.Stem()); ShowPart("extension", path.Extension()); // `Parent` drops the last component, and is absent once there is nothing left to drop. let parent = path.Parent() ?? Path(); PrintLine("{:10} {}", "parent", parent); // The exact conversion back to text. It succeeds here because the name began as text. let text = path.AsView().ToText(allocator)?; PrintLine("{:10} {}", "as text", text); } ``` Besides `Io`, its `Rux.toml` lists `Allocator`, `Path` and `Text` under `[Dependencies]`. ## Run it ```sh cd Examples/Files/Path rux run ``` ```text path Bin//reports/summary.txt components [Bin] [reports] [summary.txt] file name summary.txt stem summary extension txt parent Bin//reports as text Bin//reports/summary.txt ``` ## Common mistakes ::mistake **Forgetting the `?` after `FromText`.**:br Without it, `holder` is the whole `OsString ! TextError`, not the string, and `holder.View()` fails with: ```text error: type 'OsString ! TextError' has no field 'View' ``` Unwrap the fallible first. :: ::mistake **Using `?` in a `Main` that returns `int`.**:br`?` needs somewhere to send the failure. In `func Main() -> int`, it fails with: ```text error: '?' propagates native fallible 'OsString ! TextError', but the enclosing function returns 'int' ``` The help suggests the fix: declare the error channel, as `Main` here does with `-> ! TextError`. :: ::mistake **Passing text where a path is expected.**:br`Path::FromView("Bin/notes.txt")` fails with: ```text error: argument 1 to 'Path::FromView' has type 'char8[..]', but parameter 'view' requires 'OsStringView' ``` Text never becomes a path on its own; it goes through `OsString::FromText` first. :: ::mistake **Printing a part without unwrapping it.**:br`PrintLine("{}", path.Parent())` fails with: ```text error: no matching overload for 'PrintLine' with argument types (char8[..], Path?) ``` An optional has no text of its own; match it or supply a fallback with `??`. :: ::mistake **Backslashes in a string literal.**:br Because `\` starts an escape, `"C:\Users\me"` fails to compile with: ```text error: escape sequence '\U' is not recognized ``` Write `"C:\\Users\\me"`, or simply use `/`, which Windows accepts too. :: ## Try it yourself 1. Change the path to `archive.tar.gz` and predict the stem and extension before you run it. 2. Try `.gitignore` and `Makefile`. Which parts are `none`, and which are just short? 3. Walk up the tree: call `Parent` in a loop, printing each path, until it returns `none` (`current = current.Parent() ?? break;`). What is the last path printed before that? 4. Print the number of components by counting them in the `for` loop. ## Learn more - [Path join](https://rux-lang.dev/docs/learn/path-join) — building a path from parts with `PathBuffer` - [Allocator](https://rux-lang.dev/docs/learn/allocator) — where an `OsString`'s memory comes from - [Encoding](https://rux-lang.dev/docs/learn/encoding) and [UTF-8](https://rux-lang.dev/docs/learn/utf8) — why a name that is not valid text is a real possibility - [Iterator](https://rux-lang.dev/docs/learn/iterator) — what makes `for part in path.Components()` work # Path join ::note **You'll need**: [Path](https://rux-lang.dev/docs/learn/path), [Move](https://rux-lang.dev/docs/learn/move) :: Programs build paths all the time: a folder from the settings plus a file name, a base directory plus a date. It is tempting to glue two strings with a `/` between them, and gluing goes wrong in three ways. It doubles the separator when the base already ends in one; it writes `/` where Windows prefers `\`; and it does something odd when the second piece is itself a full path. `Path::Join` knows the rules. ## Join ```rux func Join(allocator, base: Path, segment: OsStringView) -> PathBuffer ! TextError ``` The base is a `Path` and the segment an `OsStringView`, so text goes through `OsString::FromText` first, as in [Path](https://rux-lang.dev/docs/learn/path). The lesson wraps that in a helper so each example is one line: ```rux func JoinText(allocator: Allocator, base: char8[..], segment: char8[..]) -> PathBuffer ! TextError { var baseHolder = OsString::FromText(allocator, base)?; var segmentHolder = OsString::FromText(allocator, segment)?; return Join(allocator, Path::FromView(baseHolder.View()), segmentHolder.View()); } ``` Joining is fallible only because the new path needs memory. It never looks at the disk: neither piece has to exist. ## The rules ```mermaid flowchart LR j["`Join(base, segment)`"] --> e{"`segment` empty?"} e -- "yes" --> same["the base, unchanged"] e -- "no" --> abs{"`segment` starts
with a separator?"} abs -- "yes" --> rep["the segment alone:
it replaces the base"] abs -- "no" --> tail{"`base` ends
with a separator?"} tail -- "yes" --> app["`base + segment`"] tail -- "no" --> sep["`base` + preferred
separator + `segment`"] ``` The program runs all four cases. The output on the page is from Windows, where the preferred separator is `\`; on Linux and macOS it is `/`: | Base | Segment | Windows | Linux and macOS | Why | | ------ | ------------- | ------------- | --------------- | ------------------------------------- | | `Bin` | `reports` | `Bin\reports` | `Bin/reports` | a separator is added, the platform's | | `Bin/` | `reports` | `Bin/reports` | `Bin/reports` | the base already ends in one | | `Bin` | (empty) | `Bin` | `Bin` | an empty segment changes nothing | | `Bin` | `/etc/passwd` | `/etc/passwd` | `/etc/passwd` | an absolute segment replaces the base | The last rule is what joining means in most languages and shells, and it is a trap. If the segment comes from outside — a file name typed by a user, a name inside an archive — joining it onto a safe base can escape the base entirely. Check untrusted input before you join it. ## PathBuffer: a path that owns its units `Join` returns a `PathBuffer`, not a `Path`. A `Path` only borrows units someone else holds; a `PathBuffer` owns its own, so it can be returned from `JoinText` and outlive the holders inside it. Owning has a consequence from [Move](https://rux-lang.dev/docs/learn/move): a `PathBuffer` is move-only. Anything that reads a path — printing it, passing it to another `Path` function — borrows it as a `Path` through `AsPath`: ```rux let plain = JoinText(allocator, "Bin", "reports")?; PrintLine("Bin + reports {}", plain.AsPath()); ``` | Type | Owns its units? | Can grow? | Copyable? | Use it to | | ------------ | --------------- | --------- | ----------------- | ---------------- | | `Path` | no — a view | no | yes, it is a view | read and pass on | | `PathBuffer` | yes | `Push` | no — move-only | build and keep | ## Growing one buffer with Push `Push` adds a segment to the end of a buffer in place, by the same rules as `Join`. It starts from an empty `PathBuffer(allocator)`, which must be `var` because `Push` changes it: ```rux var built = PathBuffer(allocator); let pieces = ["Bin", "reports", "2026", "summary.txt"]; for piece in pieces { var holder = OsString::FromText(allocator, piece)?; built.Push(holder.View())?; } ``` Four pushes, three separators added, none doubled: `Bin\reports\2026\summary.txt` on Windows. `Push` is fallible for the same reason `Join` is — growing needs memory. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Files/PathJoin){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // Joining two paths is not gluing two strings with a `/` between them. Gluing doubles the // separator when the base already ends in one, writes `/` where Windows prefers `\`, and does // something odd when the second piece is itself a full path. `Path::Join` knows the rules: // // func Join(allocator, base: Path, segment: OsStringView) -> PathBuffer ! TextError // // - a separator is added only where one is missing, and it is the platform's preferred one; // - a segment that starts with a separator is absolute, and replaces the base instead of // extending it, which is what joining means in most languages and shells. // // The result is a `PathBuffer`: a path that owns its units and can grow with `Push`, which // follows the same rules. A buffer is move-only, so to print it or pass it to anything that // reads a path, lend it out as a `Path` through `AsPath`. // // Joining is fallible only because the new buffer needs memory; it never looks at the disk. // On Windows the separators it adds are `\`; on Linux and macOS they are `/`. import Allocator::{ Allocator, SystemAllocator }; import Io::PrintLine; import Path::{ Join, OsString, Path, PathBuffer }; import Text::TextError; // Joins two pieces of text, both converted to native names first. func JoinText(allocator: Allocator, base: char8[..], segment: char8[..]) -> PathBuffer ! TextError { var baseHolder = OsString::FromText(allocator, base)?; var segmentHolder = OsString::FromText(allocator, segment)?; return Join(allocator, Path::FromView(baseHolder.View()), segmentHolder.View()); } func Main() -> ! TextError { var system = SystemAllocator(); let allocator: Allocator = system; let plain = JoinText(allocator, "Bin", "reports")?; PrintLine("Bin + reports {}", plain.AsPath()); // The base already ends in a separator, so none is added. let trailing = JoinText(allocator, "Bin/", "reports")?; PrintLine("Bin/ + reports {}", trailing.AsPath()); // An empty segment changes nothing. let empty = JoinText(allocator, "Bin", "")?; PrintLine("Bin + (empty) {}", empty.AsPath()); // An absolute segment wins. Joining untrusted input onto a safe base can escape it. let absolute = JoinText(allocator, "Bin", "/etc/passwd")?; PrintLine("Bin + /etc/passwd {}", absolute.AsPath()); // Growing one buffer in place, a segment at a time. var built = PathBuffer(allocator); let pieces = ["Bin", "reports", "2026", "summary.txt"]; for piece in pieces { var holder = OsString::FromText(allocator, piece)?; built.Push(holder.View())?; } PrintLine("pushed four {}", built.AsPath()); } ``` Besides `Io`, its `Rux.toml` lists `Allocator`, `Path` and `Text` under `[Dependencies]`. ## Run it ```sh cd Examples/Files/PathJoin rux run ``` ```text Bin + reports Bin\reports Bin/ + reports Bin/reports Bin + (empty) Bin Bin + /etc/passwd /etc/passwd pushed four Bin\reports\2026\summary.txt ``` ## Common mistakes ::mistake **Printing a buffer directly.**:br`PrintLine("{}", plain)` fails with: ```text error: move-only value 'plain' requires an explicit '<-' in argument ``` Printing would move the buffer away. Lend it instead: `plain.AsPath()`. :: ::mistake **Copying a buffer.**:br`let copy = plain;` fails with an error and a note: ```text error: move-only value 'plain' requires an explicit '<-' in initialization 'PathBuffer' prohibits copying ``` Move it with `<-plain` if you mean to hand it over, or make a new one with `PathBuffer::FromPath`. :: ::mistake **Passing a buffer where a `Path` is expected.**:br`Normalize(allocator, plain)` fails with: ```text has type 'PathBuffer', but parameter 'path' requires 'Path' ``` A buffer is not a path; `plain.AsPath()` is. :: ::mistake **Joining text directly.**:br`Join(allocator, base, "reports")` fails with: ```text error: argument 3 to 'Join' has type 'char8[..]', but parameter 'segment' requires 'OsStringView' ``` Convert the text with `OsString::FromText` first, as `JoinText` does. :: ::mistake **Pushing onto a `let` buffer.**:br`let built = PathBuffer(allocator);` and then `built.Push(…)` fails with: ```text error: cannot call 'Push' on immutable 'built' ``` A note adds that `Push` declares a writable receiver. :: ## Try it yourself 1. Join `Bin` and `reports/2026` in one call. Is the `/` inside the segment rewritten? 2. Join `Bin` and `../secrets.txt`. `Join` keeps the `..`; what would [Path normalize](https://rux-lang.dev/docs/learn/path-normalize) make of it? 3. Write `func IsSafeSegment(text: char8[..]) -> bool` that refuses a segment starting with `/` or `\`, and use it before joining. 4. Build `Bin/reports/2026/summary.txt` with `Join` calls instead of `Push`. How many buffers do you end up with? ## Learn more - [Path](https://rux-lang.dev/docs/learn/path) — `OsString`, `Path` and the holder that keeps a view alive - [Move](https://rux-lang.dev/docs/learn/move) — why a `PathBuffer` is passed with `<-` and lent with `AsPath` - [Path normalize](https://rux-lang.dev/docs/learn/path-normalize) — tidying the result of a join - [File](https://rux-lang.dev/docs/learn/file) — opening the path you have built # Path normalize ::note **You'll need**: [Path join](https://rux-lang.dev/docs/learn/path-join) :: The same place can be spelled many ways: `Bin/reports`, `Bin//reports`, `Bin/./reports`, `Bin/old/../reports`. That makes paths awkward to compare, to show to a person, or to use as keys. `Path::Normalize` rewrites a path into one tidy spelling — and the most important thing to learn about it is what it *cannot* know. ## Three rewrites ```rux func Normalize(allocator, path: Path) -> PathBuffer ! TextError ``` Like `Join`, it builds a new `PathBuffer` and is fallible only because that needs memory. It applies three rules: - every run of separators becomes one preferred separator — `\` on Windows, `/` elsewhere; - `.` segments go, because `.` means "right here"; - `..` removes the segment before it. The lesson's `Tidy` helper converts text and normalizes it, and `Show` prints the before and after side by side: ```rux func Tidy(allocator: Allocator, text: char8[..]) -> PathBuffer ! TextError { var holder = OsString::FromText(allocator, text)?; return Normalize(allocator, Path::FromView(holder.View())); } ``` The output on the page is from Windows; on Linux and macOS the separators are `/`. | Written | Normalized (Windows) | What happened | | ----------------------------- | --------------------- | --------------------------------------- | | `Bin//reports/./2026` | `Bin\reports\2026` | `//` became one separator, `.` went | | `Bin/old/../reports` | `Bin\reports` | `..` cancelled `old` | | `Bin/reports/2026/../../logs` | `Bin\logs` | two `..` cancelled two segments | | `../shared/./notes.txt` | `..\shared\notes.txt` | a leading `..` has nothing to cancel | | `/../etc` | `\etc` | at the root there is nowhere further up | | `Bin/reports/` | `Bin\reports` | the trailing separator went | ## Lexical, not real ```mermaid flowchart LR p["a `Path`"] --> n["`Normalize`"] n --> t["looks only at the text"] t --> ok["right for display,
comparison and deduplication"] t -.-> blind["never asks the disk:
links, existence, case"] blind -.-> fs["`FileSystem::Canonicalize`
asks the disk,
for paths that exist"] ``` The work is **lexical**: it looks only at the text, and never asks the filesystem. That is why it is fast and cannot fail for lack of a file — and it is also the source of its limits: - `link/..` is dropped even when `link` is a symbolic link to somewhere else entirely, where the real parent is a different directory. The text cannot know. - The result is not made absolute, and not checked to exist. - On Windows it is not case-folded, so `bin` and `Bin` still differ although they name one folder. Use `Normalize` to display, compare or deduplicate paths. When the true answer matters — "are these the same file?" — ask the filesystem: `FileSystem::Canonicalize` resolves links, but only for paths that exist. ## Comparing paths `Equals` compares two paths unit by unit, exactly as written, so two spellings of one place differ until both are normalized: ```rux PrintLine("equal as written {}", one.Equals(two)); let tidyOne = Normalize(allocator, one)?; let tidyTwo = Normalize(allocator, two)?; PrintLine("equal normalized {}", tidyOne.AsPath().Equals(tidyTwo.AsPath())); ``` `Bin//reports` and `Bin/old/../reports` are not equal as written, and are equal once tidied. `Equals` is a method of `Path`, so the two buffers are lent out with `AsPath` first. ## A helper that can fail `Show` itself is fallible — it calls `Tidy`, which can fail — so every call in `Main` ends in `?`: ```rux Show(allocator, "Bin//reports/./2026")?; ``` A fallible call that stands alone as a statement must be dealt with, even when its success carries no value. That is the rule from [Discard](https://rux-lang.dev/docs/learn/discard), and the next lesson leans on it at every step. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Files/PathNormalize){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // The same place can be spelled many ways: `Bin/reports`, `Bin//reports`, `Bin/./reports` and // `Bin/old/../reports`. `Path::Normalize` rewrites a path into one tidy spelling: // // func Normalize(allocator, path: Path) -> PathBuffer ! TextError // // - every run of separators becomes one preferred separator: `\` on Windows, `/` elsewhere; // - `.` segments go, because `.` means "right here"; // - `..` removes the segment before it. // // The work is lexical: it looks only at the text and never asks the disk. That is the source of // its limits, and they are the point of this lesson. // // - A leading `..` in a relative path has nothing to cancel, so it stays. // - At the root there is nowhere further up, so `/..` simply vanishes. // - `link/..` is dropped even when `link` is a symbolic link to somewhere else entirely, where // the real parent is not the same directory. The text cannot know. // - The result is not made absolute, not checked to exist, and on Windows not case-folded, so // `bin` and `Bin` still differ although they name one folder. // // Use it to display, compare or deduplicate paths. When the true answer matters, ask the // filesystem: `FileSystem::Canonicalize` resolves links, but only for paths that exist. import Allocator::{ Allocator, SystemAllocator }; import Io::PrintLine; import Path::{ Normalize, OsString, Path, PathBuffer }; import Text::TextError; func Tidy(allocator: Allocator, text: char8[..]) -> PathBuffer ! TextError { var holder = OsString::FromText(allocator, text)?; return Normalize(allocator, Path::FromView(holder.View())); } func Show(allocator: Allocator, text: char8[..]) -> ! TextError { let tidy = Tidy(allocator, text)?; PrintLine("{:28} {}", text, tidy.AsPath()); } func Main() -> ! TextError { var system = SystemAllocator(); let allocator: Allocator = system; Show(allocator, "Bin//reports/./2026")?; Show(allocator, "Bin/old/../reports")?; Show(allocator, "Bin/reports/2026/../../logs")?; Show(allocator, "../shared/./notes.txt")?; Show(allocator, "/../etc")?; Show(allocator, "Bin/reports/")?; PrintLine(); // `Equals` compares units exactly, so two spellings of one place differ until both are // normalized. var oneHolder = OsString::FromText(allocator, "Bin//reports")?; var twoHolder = OsString::FromText(allocator, "Bin/old/../reports")?; let one = Path::FromView(oneHolder.View()); let two = Path::FromView(twoHolder.View()); PrintLine("equal as written {}", one.Equals(two)); let tidyOne = Normalize(allocator, one)?; let tidyTwo = Normalize(allocator, two)?; PrintLine("equal normalized {}", tidyOne.AsPath().Equals(tidyTwo.AsPath())); } ``` Besides `Io`, its `Rux.toml` lists `Allocator`, `Path` and `Text` under `[Dependencies]`. ## Run it ```sh cd Examples/Files/PathNormalize rux run ``` ```text Bin//reports/./2026 Bin\reports\2026 Bin/old/../reports Bin\reports Bin/reports/2026/../../logs Bin\logs ../shared/./notes.txt ..\shared\notes.txt /../etc \etc Bin/reports/ Bin\reports equal as written false equal normalized true ``` ## Common mistakes ::mistake **Comparing paths with `==`.**:br`one == two` fails with: ```text error: structural equality for 'Path' is unavailable because element type … ``` A path holds the system's units, which have no `==` here. Use `one.Equals(two)`, after normalizing both if the spelling may differ. :: ::mistake **Calling `Equals` on a buffer.**:br`tidyOne.Equals(tidyTwo)` fails with: ```text error: struct 'PathBuffer' has no field 'Equals' ``` Compare the paths the buffers lend: `tidyOne.AsPath().Equals(tidyTwo.AsPath())`. :: ::mistake **Dropping the `?` on a fallible helper.**:br`Show(allocator, "/../etc");` without the `?` fails with an error and a note: ```text error: fallible result of type '! TextError' is discarded a failure that nothing handles is lost ``` :: ::mistake **Trusting a normalized path to be safe.**:br`../shared/notes.txt` stays `..\shared\notes.txt`: normalizing does not stop a path from leaving a directory. And `link/..` is tidied away without looking at where `link` points. For security decisions, ask the filesystem. :: ## Try it yourself 1. Normalize `./a/./b/.` and `a/b/../../..`. Predict both before running. 2. Write `func SamePlace(allocator: Allocator, left: char8[..], right: char8[..]) -> bool ! TextError` that normalizes both and compares them. 3. Normalize `Bin` and `bin`, and compare the results. Then ask yourself whether they name the same folder on your system. 4. Join `Bin` and `../secrets.txt` as in [Path join](https://rux-lang.dev/docs/learn/path-join), then normalize the result. ## Learn more - [Path join](https://rux-lang.dev/docs/learn/path-join) — `PathBuffer`, which `Normalize` returns - [Path](https://rux-lang.dev/docs/learn/path) — components, which are what `Normalize` rewrites - [Discard](https://rux-lang.dev/docs/learn/discard) — why a fallible statement cannot simply be left alone - [Metadata](https://rux-lang.dev/docs/learn/metadata) — asking the filesystem about a path, instead of reading its text # File ::note **You'll need**: [Path](https://rux-lang.dev/docs/learn/path), [Error sum](https://rux-lang.dev/docs/learn/error-sum), [Catch](https://rux-lang.dev/docs/learn/catch), [Guard](https://rux-lang.dev/docs/learn/guard) :: A file is where a program's data outlives the program. Writing one and reading it back takes only a handful of calls, but every one of them can fail for reasons outside the program: the disk is full, the name is taken, permission is refused, the file is not there. So every step returns a fallible, `T ! IoError`, and this lesson accounts for each one. `Main` is fallible too: `func Main() -> ! IoError | TextError`. Its failure side is an [error sum](https://rux-lang.dev/docs/learn/error-sum) of two errors — `IoError` from the file calls and `TextError` from turning text into a path. A `?` anywhere passes a failure on, and the program ends with exit status 1. ## Opening a file `File::Open` takes an allocator, a [path](https://rux-lang.dev/docs/learn/path) and an `OpenOptions` saying what you mean to do: ```rux var writing = File::Open(allocator, path, OpenOptions::Writing())?; ``` The options decide both what the handle may do and what happens to the file itself: | Options | The handle may | If the file is missing | If it exists | | -------------------------- | ---------------- | ---------------------- | ------------------------ | | `OpenOptions::Reading()` | read | fails with `NotFound` | opened as it is | | `OpenOptions::Writing()` | write | created | emptied first | | `OpenOptions::Appending()` | write at the end | created | kept; writes go after it | The open file is a `File`, and it must be `var`: writing, reading and closing all change it. ## Writing, and closing ```rux WriteAll(writing, "first line\nsecond line\n")?; writing.Close()?; ``` `File::Write` is a single attempt: it may move fewer bytes than asked, and the count it returns says how many. `Io::WriteAll` keeps calling `Write` until every byte is out, which is almost always what you want. `Close` is fallible as well. The system may have delayed reporting a failed write until now, so a close that is not checked can lose an error that happened earlier. ## Reading until the end `File::Read` fills as much of a buffer as it can in one attempt and returns how many bytes it put there. The lesson's buffer is only eight bytes, so the 23 bytes of the file take several reads: ```rux var buffer: char8[8]; var reads = 0; var total: uint = 0; loop { let filled = reading.Read(buffer[..8]) catch { error if error.IsEnd() => break, error => fail error }; Print("{}", buffer[..filled]); reads += 1; total += filled; } ``` The surprise is how the end arrives. It is not a count of zero: it comes on the **failure** channel, as an `IoError` whose `IsEnd()` is true. So the [`catch`](https://rux-lang.dev/docs/learn/catch) has two arms, separated by a [guard](https://rux-lang.dev/docs/learn/guard): the end of the file breaks out of the loop, and any other error is a real failure, passed on with `fail`. ```mermaid flowchart LR r["`reading.Read(buffer[..8])`"] --> q{"what came back?"} q -- "a count" --> use["print `buffer[..filled]`,
add it up, read again"] use --> r q -- "an `IoError`,
`IsEnd()` `true`" --> done["break: the file is read"] q -- "any other
`IoError`" --> fail["`fail error`:
`Main` ends with status `1`"] ``` Only the first `filled` bytes are new. The rest of the buffer still holds whatever the previous read left there, which is why the loop prints `buffer[..filled]`, never the whole buffer. | Read | Bytes | Buffer holds | | ---- | ----- | ---------------------------------------- | | 1 | 8 | `first li` | | 2 | 8 | `ne`, a newline, `secon` | | 3 | 7 | `d line` and a newline, plus a stale `n` | | 4 | — | the end of the file: `break` | ## Handling a failure instead of passing it on Not every failure should end the program. After `DeleteFile` the file is gone, so opening it again must fail — and here that is the expected outcome. A `match` on the fallible takes it apart: ```rux match File::Open(allocator, path, OpenOptions::Reading()) { .Success(_) => PrintLine("still there?"), .Failure(error) if error.kind == IoErrorKind::NotFound => PrintLine("deleted, as expected"), .Failure(error) => fail error } ``` `error.kind` is an `IoErrorKind`, an enum that names what went wrong in the same way on every platform: `NotFound`, `PermissionDenied`, `AlreadyExists`, `StorageFull` and more. The guard picks out the one failure this code expects; anything else is still passed on. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Files/File){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // Writing a text file and reading it back, with every failure accounted for. // // Each step can fail for reasons outside the program: the disk is full, the name is taken, // permission is refused. So each one returns `T ! IoError`, and `Main` is fallible: `?` passes a // failure on and the program ends with exit status 1. Its failure side also names `TextError`, // which turning text into a path can produce. // // Two surprises are worth knowing before the code. // // - `File::Write` and `File::Read` are single attempts. Each may move fewer bytes than asked, // and the count it returns says how many. `Io::WriteAll` keeps calling `Write` until every // byte is out, and a reader loops in the same way. // - The end of a file is not a count of zero. It arrives on the failure channel, as an // `IoError` whose `IsEnd()` is true, so the read loop's `catch` treats it as "done" and any // other error as a real failure. // // The file lives in this package's `Bin/` folder, and the program deletes it at the end. import Allocator::{ Allocator, SystemAllocator }; import FileSystem::{ DeleteFile, File, OpenOptions }; import Io::{ IoError, IoErrorKind, Print, PrintLine, WriteAll }; import Path::{ OsString, Path }; import Text::TextError; func Main() -> ! IoError | TextError { var system = SystemAllocator(); let allocator: Allocator = system; var holder = OsString::FromText(allocator, "Bin/notes.txt")?; let path = Path::FromView(holder.View()); // `Writing` creates the file, or empties it if it already exists. var writing = File::Open(allocator, path, OpenOptions::Writing())?; WriteAll(writing, "first line\nsecond line\n")?; // Closing can report a failure that was delayed until now, so it is fallible too. writing.Close()?; PrintLine("wrote {}", path); // `Reading` requires the file to exist. A small buffer makes the loop take several reads. var reading = File::Open(allocator, path, OpenOptions::Reading())?; var buffer: char8[8]; var reads = 0; var total: uint = 0; loop { let filled = reading.Read(buffer[..8]) catch { error if error.IsEnd() => break, error => fail error }; // Only the first `filled` bytes are new. The rest of the buffer is left over. Print("{}", buffer[..filled]); reads += 1; total += filled; } reading.Close()?; PrintLine("read {} bytes in {} reads", total, reads); DeleteFile(allocator, path)?; // Handling a failure instead of passing it on: the file is gone, so opening it fails. match File::Open(allocator, path, OpenOptions::Reading()) { .Success(_) => PrintLine("still there?"), .Failure(error) if error.kind == IoErrorKind::NotFound => PrintLine("deleted, as expected"), .Failure(error) => fail error } } ``` Besides `Io`, its `Rux.toml` lists `Allocator`, `FileSystem`, `Path` and `Text` under `[Dependencies]`. ## Run it ```sh cd Examples/Files/File rux run ``` ```text wrote Bin/notes.txt first line second line read 23 bytes in 3 reads deleted, as expected ``` ## Common mistakes ::mistake **Leaving `Close` unchecked.**:br`writing.Close();` fails with: ```text error: fallible result of type '! IoError' is discarded ``` Close can report a failure that was delayed until then, so handle it like any other step. :: ::mistake **Treating the end of the file as an error.**:br Replace the `catch` with `?` and the program compiles, prints the file — and then ends with exit status 1 and no message, because the end arrives as an `IoError` and `?` passes it on. It never reaches `DeleteFile`, so `Bin/notes.txt` is left behind. Catch the end with `IsEnd()`. :: ::mistake **Printing the whole buffer.**:br`Print("{}", buffer[..])` prints the stale bytes too: the output gains a stray `n` after `second line`, left over from the second read. Print `buffer[..filled]`. :: ::mistake **Opening a file with `let`.**:br`let writing = File::Open(…)?;` makes the later calls fail: ```text error: argument 1 to 'WriteAll' cannot borrow immutable 'writing' as '&var Writer' error: cannot call 'Close' on immutable 'writing' ``` An open file changes as you use it; declare it `var`. :: ::mistake **Passing text as the path.**:br`File::Open(allocator, "Bin/notes.txt", …)` fails with: ```text error: argument 2 to 'File::Open' has type 'char8[..]', but parameter 'path' requires 'Path' ``` Convert the text with `OsString::FromText` and take a `Path` of it, as at the top of `Main`. :: ## Try it yourself 1. Change the buffer to 4 bytes, and then to 64. How many reads does the file take each time? 2. Open the file a second time with `OpenOptions::Appending()`, add a third line, and read the whole file back. 3. Open a file that does not exist with `OpenOptions::Reading()` and let `?` pass the failure on. Check the exit status with `echo $?`. 4. Count the lines as you read, by counting the newline characters in each `buffer[..filled]`. ## Learn more - [Error sum](https://rux-lang.dev/docs/learn/error-sum), [Catch](https://rux-lang.dev/docs/learn/catch) and [Guard](https://rux-lang.dev/docs/learn/guard) — the tools this lesson combines - [Fallible main](https://rux-lang.dev/docs/learn/fallible-main) — what happens when `?` reaches `Main` - [Buffered I/O](https://rux-lang.dev/docs/learn/buffered-io) — fewer, larger reads and writes - [Atomic file](https://rux-lang.dev/docs/learn/atomic-file) — replacing a file so that no reader ever sees it half-written - [`loop`](https://rux-lang.dev/docs/lang/statements/loops#loop) and [`match`](https://rux-lang.dev/docs/lang/patterns/match) in the Rux Reference # Directory ::note **You'll need**: [File](https://rux-lang.dev/docs/learn/file), [Path join](https://rux-lang.dev/docs/learn/path-join), [Nested fallible](https://rux-lang.dev/docs/learn/nested-fallible), [Coalesce exit](https://rux-lang.dev/docs/learn/coalesce-exit) :: A directory holds names: files, and other directories. The `FileSystem` package makes one, lists what is in it and removes it, and this program does all three to a scratch directory of its own, `Bin/scratch`, inside the package's build folder. The interesting part is the listing, because a directory can hold a great many names, and reading it can fail part-way through. ## Four calls | Call | Does | Fails when | | ---------------------------------- | ------------------------------- | ---------------------------- | | `MakeDirectory(allocator, path)` | creates one directory | the name is already taken | | `ReadDirectory(allocator, path)` | starts a listing | the directory cannot be read | | `DeleteFile(allocator, path)` | removes one file | it is missing | | `DeleteDirectory(allocator, path)` | removes one **empty** directory | anything is still inside | All four return fallibles with `IoError` on the failure side, and none of them touches more than the one name it is given. The files go in with two small helpers. Each converts a name to an `OsString`, joins it onto the directory with [`Join`](https://rux-lang.dev/docs/learn/path-join), and acts on the result: ```rux func MakeFile(allocator: Allocator, directory: Path, name: char8[..]) -> ! IoError | TextError { var holder = OsString::FromText(allocator, name)?; let path = Join(allocator, directory, holder.View())?; var file = File::Open(allocator, path.AsPath(), OpenOptions::Writing())?; WriteAll(file, name)?; file.Close()?; } ``` ## Listing, one name at a time `ReadDirectory` does not return every name at once — that would mean holding them all at once. It returns a cursor, a `DirectoryIterator`, whose `Next` hands out one name per call: ```rux func Next(self: &var DirectoryIterator) -> OsString? ! IoError ``` That is the nested shape from [Nested fallible](https://rux-lang.dev/docs/learn/nested-fallible): two questions in one return type. The outer one is "could the directory be read?"; the inner one is "is there another name?". The loop answers both in one line: ```rux var listing = ReadDirectory(allocator, directory)?; var count = 0; loop { let name = listing.Next()? ?? break; PrintLine(" {}", name); count += 1; } ``` ```mermaid flowchart LR n["`listing.Next()`"] --> f{"failed?"} f -- "yes" --> p["`?` passes the `IoError` on:
`Main` ends with status `1`"] f -- "no" --> o{"a name, or `none`?"} o -- "`none`" --> b["`?? break`:
every name handed out"] o -- "a name" --> use["bind it to `name`,
print it, loop again"] use --> n ``` `?` strips the outer fallible, and [`?? break`](https://rux-lang.dev/docs/learn/coalesce-exit) strips the inner optional — leaving the loop when it is `none`. What is left is an `OsString`, a name in the system's own units, for the reason [Path](https://rux-lang.dev/docs/learn/path) gave. Three more things about a listing: - `.` and `..` are skipped; you get only real entries. - The order is whatever the filesystem keeps. This program happens to print `first.txt` before `second.txt`; do not rely on it. Sort the names if order matters. - The cursor holds a system handle. `listing.Release()` gives it back as soon as you are done, rather than at the end of the scope. ## Removal is strict `DeleteDirectory` refuses a directory that still has anything in it, so removing the scratch directory too early fails. This program expects that, and handles the failure rather than passing it on: ```rux DeleteDirectory(allocator, directory) catch { else => { PrintLine("refused: the directory is not empty"); } }; ``` `IoErrorKind` has no case for "not empty", so the failure arrives as `Other`, with the system's own code beside it. That is why this `catch` takes every failure with `else` rather than matching one kind. Then the files go first, and the empty directory after them: ```rux RemoveFile(allocator, directory, "first.txt")?; RemoveFile(allocator, directory, "second.txt")?; DeleteDirectory(allocator, directory)?; ``` Nothing here deletes a whole tree in one call. Removing a directory and everything below it means listing it, deleting each file, and descending into each subdirectory — which is exactly why it is not a single innocent-looking function. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Files/Directory){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // A directory is made, listed and removed through the `FileSystem` package, and this program does // all three to a scratch directory it owns: `Bin/scratch`, inside this package's build folder. // // Listing is the interesting part. `ReadDirectory` returns a cursor, and its `Next` hands out one // name at a time, because a directory can hold a great many and returning them all at once would // mean holding them all at once. `Next` has the nested shape from the Errors part: // // func Next(self: &var DirectoryIterator) -> OsString? ! IoError // // The outer failure means the directory could not be read. A success holds the next name, or // `none` once every name has been handed out. So `listing.Next()? ?? break` passes a failure on, // stops at the end, and otherwise binds a name. The names are `OsString`s, not text, for the // reason the Path lesson gave; `.` and `..` are skipped. The order is whatever the filesystem // keeps, so do not rely on it. // // Removal is strict. `MakeDirectory` fails if the name is taken, and `DeleteDirectory` refuses a // directory that still has anything in it, so the files go first. import Allocator::{ Allocator, SystemAllocator }; import FileSystem::{ DeleteDirectory, DeleteFile, File, MakeDirectory, OpenOptions, ReadDirectory }; import Io::{ IoError, PrintLine, WriteAll }; import Path::{ Join, OsString, Path }; import Text::TextError; // Writes a small file called `name` inside `directory`. func MakeFile(allocator: Allocator, directory: Path, name: char8[..]) -> ! IoError | TextError { var holder = OsString::FromText(allocator, name)?; let path = Join(allocator, directory, holder.View())?; var file = File::Open(allocator, path.AsPath(), OpenOptions::Writing())?; WriteAll(file, name)?; file.Close()?; } // Deletes the file called `name` inside `directory`. func RemoveFile(allocator: Allocator, directory: Path, name: char8[..]) -> ! IoError | TextError { var holder = OsString::FromText(allocator, name)?; let path = Join(allocator, directory, holder.View())?; DeleteFile(allocator, path.AsPath())?; } func Main() -> ! IoError | TextError { var system = SystemAllocator(); let allocator: Allocator = system; var holder = OsString::FromText(allocator, "Bin/scratch")?; let directory = Path::FromView(holder.View()); MakeDirectory(allocator, directory)?; MakeFile(allocator, directory, "first.txt")?; MakeFile(allocator, directory, "second.txt")?; PrintLine("made {} with two files", directory); var listing = ReadDirectory(allocator, directory)?; var count = 0; loop { let name = listing.Next()? ?? break; PrintLine(" {}", name); count += 1; } // The cursor holds a system handle; `Release` gives it back now rather than at scope end. listing.Release(); PrintLine("listed {} entries", count); // Removing it too early is refused, and this failure is handled rather than passed on. DeleteDirectory(allocator, directory) catch { else => { PrintLine("refused: the directory is not empty"); } }; RemoveFile(allocator, directory, "first.txt")?; RemoveFile(allocator, directory, "second.txt")?; DeleteDirectory(allocator, directory)?; PrintLine("removed {}", directory); } ``` Besides `Io`, its `Rux.toml` lists `Allocator`, `FileSystem`, `Path` and `Text` under `[Dependencies]`. ## Run it ```sh cd Examples/Files/Directory rux run ``` ```text made Bin/scratch with two files first.txt second.txt listed 2 entries refused: the directory is not empty removed Bin/scratch ``` ## Common mistakes ::mistake **Coalescing without the `?`.**:br`listing.Next() ?? break` fails, and the note explains why: ```text error: operator '??' cannot take 'OsString? ! IoError' coalescing tests one optional level and would silently discard an error ``` Deal with the failure first: `listing.Next()? ?? break`. :: ::mistake **Forgetting the `?? break`.**:br`let name = listing.Next()?;` leaves `name` an `OsString?`, and printing it fails with: ```text error: no matching overload for 'PrintLine' with argument types (char8[..], OsString?) ``` Without the `??`, nothing ends the loop either. :: ::mistake **A scratch directory left behind.**:br If a run stops part-way — a failure passed on with `?`, or a change of yours — `Bin/scratch` may still exist, and the next run fails at once at `MakeDirectory`, with exit status 1 and no output. Delete the folder by hand and run again. :: ::mistake **Relying on the listing order.**:br The names come back in whatever order the filesystem keeps them, which differs between systems and can change. Sort them when the order matters. :: ## Try it yourself 1. Add a third file, and a subdirectory made with `MakeDirectory`. What does the listing show for the subdirectory, and what must change before the scratch directory can be removed? 2. Call `MakeDirectory` twice on the same path and handle the second failure with a `match` that checks for `IoErrorKind::AlreadyExists`. 3. Convert each name to text with `name.View().ToText(allocator)?` before printing it. When could that conversion fail, when printing with `{}` never does? 4. List the package's own `Bin` folder instead of the scratch directory. ## Learn more - [Nested fallible](https://rux-lang.dev/docs/learn/nested-fallible) and [Coalesce exit](https://rux-lang.dev/docs/learn/coalesce-exit) — the two halves of `Next()? ?? break` - [Path join](https://rux-lang.dev/docs/learn/path-join) — building each file's path inside the directory - [Metadata](https://rux-lang.dev/docs/learn/metadata) — asking whether a name is a file or a directory - [Temporary file](https://rux-lang.dev/docs/learn/temporary-file) — scratch space that removes itself # Metadata ::note **You'll need**: [File](https://rux-lang.dev/docs/learn/file), [Enum](https://rux-lang.dev/docs/learn/enum), [Match expression](https://rux-lang.dev/docs/learn/match-expression) :: **Metadata** is what the filesystem knows about a name without reading the contents: what kind of thing it is, how long it is, whether it may be written and when it last changed. One call asks all of it, and the same call is how a program answers the most common question about a path — does it exist? ## One call ```rux func MetadataOf(allocator, path: Path, followLinks: bool) -> Metadata ! IoError ``` `followLinks` decides what a symbolic link at the end of the path means. `true` describes the file the link points to — usually what you want — and `false` describes the link itself, which is the only way you will ever see a `SymbolicLink` reported. An open `File` answers the same question through its own `Metadata` method. That answer is about the file the handle holds, even if the name has since been moved or replaced. ## The answer is a plain struct | Field | Type | Holds | | ------------- | ------------- | --------------------------------------------------- | | `kind` | `FileKind` | `File`, `Directory`, `SymbolicLink` or `Other` | | `size` | `uint64` | the length in bytes; zero for a directory | | `permissions` | `Permissions` | whether the owner may write: `IsWritable()` | | `modified` | `Timestamp` | when the contents last changed | | `accessed` | `Timestamp` | when the contents were last read | | `linkCount` | `uint64` | how many names the contents have; one on most files | A directory's `size` is zero because what it would mean differs from system to system. `Timestamp` comes from the `Time` package, which has its own lesson in [Date and time](https://rux-lang.dev/docs/learn/date-time). `kind` is an [enum](https://rux-lang.dev/docs/learn/enum), and a [match expression](https://rux-lang.dev/docs/learn/match-expression) turns it into words. Every case is covered, so the match needs no `else`: ```rux func KindName(kind: FileKind) -> char8[..] { return match kind { FileKind::File => "file", FileKind::Directory => "directory", FileKind::SymbolicLink => "symbolic link", FileKind::Other => "other" }; } ``` `Other` is a device, a socket, a pipe — anything the filesystem holds that is none of the other three. ## A time that changes on every run The file is written a moment before it is described, so its modification time is "just now" — a different number on every run. The program prints only whether that was within the last minute, so the output stays the same: ```rux let age = Timestamp::Now().UnixSeconds() - info.modified.UnixSeconds(); PrintLine(" recent {}", age < 60); ``` `UnixSeconds` counts seconds since the start of 1970, so subtracting two of them gives the age in seconds. ## "Not found" is an answer Asking about a name that is not there is not a crash, and not a struct full of zeros. It is a failure whose kind is `NotFound`, which is what makes `MetadataOf` the way to ask "does this exist?". `Describe` matches all three outcomes: ```rux match MetadataOf(allocator, path, true) { .Success(info) => { PrintLine("{}", path); PrintLine(" kind {}", KindName(info.kind)); // … }, .Failure(error) if error.kind == IoErrorKind::NotFound => PrintLine("{}: not found", path), .Failure(error) => fail error } ``` ```mermaid flowchart LR m["`MetadataOf(path)`"] --> s{"outcome"} s -- "`.Success(info)`" --> yes["it exists:
read `info.kind`, `info.size` …"] s -- "`.Failure`, kind `NotFound`" --> no["it does not exist"] s -- "any other `.Failure`" --> unk["we cannot tell:
pass the error on"] ``` The third arm matters. A `PermissionDenied` does not mean the file is missing — only that this program may not look. Treating every failure as "not there" would turn a permissions problem into a wrong answer. The program describes the file, then the `Bin` directory it lives in, then deletes the file and asks again, which takes the `NotFound` arm. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Files/Metadata){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // Metadata is what the filesystem knows about a name without reading the contents: what kind of // thing it is, how long it is, who may write it and when it last changed. One call asks: // // func MetadataOf(allocator, path: Path, followLinks: bool) -> Metadata ! IoError // // `followLinks` decides what a symbolic link at the end of the path means: `true` describes the // file the link points to, `false` the link itself. An open `File` answers the same question // through its `Metadata` method, about the file it holds even if the name has since moved. // // The answer is a plain struct. `kind` is a `FileKind` enum, `size` is in bytes (and zero for a // directory, where it means nothing portable), `permissions` says whether the owner may write, // and `modified` is a `Timestamp` from the `Time` package, which has its own lesson later on. // // Asking about a name that is not there is not a crash and not a zero-filled struct: it is a // failure whose kind is `NotFound`, which makes `MetadataOf` the way to ask "does this exist?". import Allocator::{ Allocator, SystemAllocator }; import FileSystem::{ DeleteFile, File, FileKind, MetadataOf, OpenOptions }; import Io::{ IoError, IoErrorKind, PrintLine, WriteAll }; import Path::{ OsString, Path }; import Text::TextError; import Time::Timestamp; func KindName(kind: FileKind) -> char8[..] { return match kind { FileKind::File => "file", FileKind::Directory => "directory", FileKind::SymbolicLink => "symbolic link", FileKind::Other => "other" }; } func Describe(allocator: Allocator, text: char8[..]) -> ! IoError | TextError { var holder = OsString::FromText(allocator, text)?; let path = Path::FromView(holder.View()); match MetadataOf(allocator, path, true) { .Success(info) => { PrintLine("{}", path); PrintLine(" kind {}", KindName(info.kind)); PrintLine(" size {} bytes", info.size); PrintLine(" writable {}", info.permissions.IsWritable()); // The seconds since the last change differ on every run, so only whether that was // within the last minute is shown. let age = Timestamp::Now().UnixSeconds() - info.modified.UnixSeconds(); PrintLine(" recent {}", age < 60); }, .Failure(error) if error.kind == IoErrorKind::NotFound => PrintLine("{}: not found", path), .Failure(error) => fail error } } func Main() -> ! IoError | TextError { var system = SystemAllocator(); let allocator: Allocator = system; var holder = OsString::FromText(allocator, "Bin/sample.txt")?; let path = Path::FromView(holder.View()); var file = File::Open(allocator, path, OpenOptions::Writing())?; WriteAll(file, "0123456789")?; file.Close()?; Describe(allocator, "Bin/sample.txt")?; Describe(allocator, "Bin")?; DeleteFile(allocator, path)?; Describe(allocator, "Bin/sample.txt")?; } ``` Besides `Io`, its `Rux.toml` lists `Allocator`, `FileSystem`, `Path`, `Text` and `Time` under `[Dependencies]`. ## Run it ```sh cd Examples/Files/Metadata rux run ``` ```text Bin/sample.txt kind file size 10 bytes writable true recent true Bin kind directory size 0 bytes writable true recent true Bin/sample.txt: not found ``` ## Common mistakes ::mistake **Leaving out a kind.**:br Drop the `FileKind::Other` arm and the match fails with: ```text error: match on 'FileKind' is not exhaustive; missing FileKind::Other ``` A file kind you have not thought of is still a file kind. :: ::mistake **Forgetting `followLinks`.**:br`MetadataOf(allocator, path)` fails with: ```text error: call to 'MetadataOf' expects 3 arguments, but 2 were provided ``` There is no default: say whether a link at the end of the path should be followed. :: ::mistake **Asking "does it exist?" with `?`.**:br`let info = MetadataOf(allocator, path, true)?;` works while the file is there, and ends the whole program with exit status 1 the moment it is not. When absence is an answer you expect, match the failure, as `Describe` does. :: ::mistake **Reading every failure as "missing".**:br A `.Failure(_) => PrintLine("not found")` arm also catches `PermissionDenied` and every other failure. Check `error.kind == IoErrorKind::NotFound`, and pass the rest on. :: ## Try it yourself 1. Print `info.linkCount` and `info.accessed.UnixSeconds()` for both paths. 2. Describe a path that does not exist at all, such as `Bin/nothing/here.txt`. Which arm runs? 3. Open the file and call its `Metadata` method instead of `MetadataOf`. What does it report for `size`? 4. Write `func Exists(allocator: Allocator, path: Path) -> bool ! IoError` that returns `false` for `NotFound`, `true` for success, and passes any other failure on. ## Learn more - [Enum](https://rux-lang.dev/docs/learn/enum) and [Match expression](https://rux-lang.dev/docs/learn/match-expression) — turning a `FileKind` into words - [Guard](https://rux-lang.dev/docs/learn/guard) — the `if` on a match arm that picks out `NotFound` - [Temporary file](https://rux-lang.dev/docs/learn/temporary-file) — which uses `MetadataOf` to check that a file is gone - [Date and time](https://rux-lang.dev/docs/learn/date-time) — `Timestamp` and what else it can do # Binary ::note **You'll need**: [File](https://rux-lang.dev/docs/learn/file), [Endian](https://rux-lang.dev/docs/learn/endian) :: A text file stores numbers as digits: 1200000 is seven characters, 3 is one. A **binary** file stores the bytes of the values themselves, so a `uint16` is always two bytes, a `uint32` four and a `float64` eight, however large the value. Every record has the same size, and a reader knows exactly how many bytes to expect — which also means it can tell when some are missing. ## A fixed-width record The lesson's record is three fields, fourteen bytes whatever the values are: | Bytes | Field | Type | Written with | Read with | | ----- | --------- | --------- | -------------- | ------------- | | 0–1 | `version` | `uint16` | `WriteUint16` | `ReadUint16` | | 2–5 | `count` | `uint32` | `WriteUint32` | `ReadUint32` | | 6–13 | `average` | `float64` | `WriteFloat64` | `ReadFloat64` | The `Io` package has a pair of functions like these for every fixed-width type, from `uint8` up to `int512` and both floats. Each takes an `Endian` naming the byte order — [Endian](https://rux-lang.dev/docs/learn/endian) explains why that must be stated. This format simply says little endian, and both sides must agree: ```rux var writing = File::Open(allocator, path, OpenOptions::Writing())?; WriteUint16(writing, Endian::Little, 3)?; WriteUint32(writing, Endian::Little, 1200000)?; WriteFloat64(writing, Endian::Little, 2.75)?; writing.Close()?; ``` Each literal takes its parameter's type — `3` becomes a `uint16`, `1200000` a `uint32` — the [Literal](https://rux-lang.dev/docs/learn/literal) rule at work. Reading is the same three calls in the same order: ```rux func ReadRecord(file: &var File) -> ! IoError { let version = ReadUint16(file, Endian::Little)?; let count = ReadUint32(file, Endian::Little)?; let average = ReadFloat64(file, Endian::Little)?; PrintLine(" version {}, count {}, average {}", version, count, average); } ``` Nothing in the file says where one field ends and the next begins. The format is the agreement between writer and reader, and the code on each side is its only record. ## A value is all of its bytes, or nothing [File](https://rux-lang.dev/docs/learn/file) showed that `File::Read` is one attempt that may return fewer bytes than asked. A number cannot be assembled from part of its bytes, so the fixed-width readers are built on `Io::ReadExact`, which keeps reading until every byte of the value has arrived — and the writers on `WriteAll`: ```mermaid flowchart LR r["`ReadUint32(file, …)`"] --> e["`ReadExact`:
4 bytes wanted"] e --> rd["`file.Read(…)`"] rd --> q{"what came back?"} q -- "some bytes,
more still needed" --> rd q -- "the last
bytes needed" --> v["assemble the `uint32`
in the stated byte order"] q -- "the end of the file" --> f["fail with an `IoError`
whose `IsEnd()` is `true`"] ``` If the stream ends part-way through a value, `ReadUint32` fails instead of building a number from the bytes it got plus whatever happened to be in memory. A short file is an error to report, never a value to guess. ## A record cut short The second half of the program simulates a crash part-way through writing. It opens the file with plain write permission — `OpenOptions()` with only `write` set, so the file is not emptied the way `Writing` would — and cuts it to ten bytes: ```rux var options = OpenOptions(); options.write = true; var cutting = File::Open(allocator, path, options)?; cutting.SetLength(10)?; cutting.Close()?; ``` Ten bytes hold the whole `version` and `count`, and four of the eight bytes of `average`. `ShowRecord` reads the record again and catches the end-of-file failure rather than passing it on: ```rux ReadRecord(reading) catch { error if error.IsEnd() => { PrintLine(" the file ends inside a field: record refused"); }, error => fail error }; ``` The first two fields read perfectly well, but the record as a whole is refused: one field that cannot be read whole fails `ReadRecord`, and the half-read values are never printed. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Files/Binary){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // A text file stores numbers as digits. A binary file stores the bytes of the values themselves: // a `uint16` is always two bytes, a `uint32` four and a `float64` eight, however large the // value. Every record has the same size, so a reader knows exactly how many bytes to expect. // // `Io` has a function pair for each fixed-width type, such as `WriteUint32` and `ReadUint32`. // Each takes an `Endian` naming the byte order; the Endian lesson explains why that must be // stated. Here the format simply says little endian, on both sides. // // The real lesson is about bytes that do not arrive. `File::Read` is one attempt and may return // fewer bytes than asked; at the end of a file it fails with `EndOfStream`. The fixed-width // functions are built on `ReadExact` and `WriteAll`, which keep calling until every byte of the // value has moved. If the stream ends part-way through a value, `ReadUint32` fails instead of // assembling a number from the bytes it got plus whatever was in memory. A short file is an // error to report, never a value to guess. // // The file lives in this package's `Bin/` folder, and the program deletes it at the end. import Allocator::{ Allocator, SystemAllocator }; import FileSystem::{ DeleteFile, File, OpenOptions }; import Io::{ Endian, IoError, PrintLine, ReadFloat64, ReadUint16, ReadUint32, WriteFloat64, WriteUint16, WriteUint32 }; import Path::{ OsString, Path }; import Text::TextError; // Reads one record. Any field that cannot be read whole fails the whole record. func ReadRecord(file: &var File) -> ! IoError { let version = ReadUint16(file, Endian::Little)?; let count = ReadUint32(file, Endian::Little)?; let average = ReadFloat64(file, Endian::Little)?; PrintLine(" version {}, count {}, average {}", version, count, average); } // Opens the file, reads a record from it, and reports a short file instead of passing it on. func ShowRecord(allocator: Allocator, path: Path) -> ! IoError { var reading = File::Open(allocator, path, OpenOptions::Reading())?; PrintLine("{} holds {} bytes", path, reading.Size()?); ReadRecord(reading) catch { error if error.IsEnd() => { PrintLine(" the file ends inside a field: record refused"); }, error => fail error }; reading.Close()?; } func Main() -> ! IoError | TextError { var system = SystemAllocator(); let allocator: Allocator = system; var holder = OsString::FromText(allocator, "Bin/record.bin")?; let path = Path::FromView(holder.View()); // 2 + 4 + 8 bytes: fourteen, whatever the values are. var writing = File::Open(allocator, path, OpenOptions::Writing())?; WriteUint16(writing, Endian::Little, 3)?; WriteUint32(writing, Endian::Little, 1200000)?; WriteFloat64(writing, Endian::Little, 2.75)?; writing.Close()?; ShowRecord(allocator, path)?; // Cut the file in the middle of the last field, as a crash part-way through writing might // have left it. Plain `write` permission, without `Writing`'s emptying of the file. var options = OpenOptions(); options.write = true; var cutting = File::Open(allocator, path, options)?; cutting.SetLength(10)?; cutting.Close()?; ShowRecord(allocator, path)?; DeleteFile(allocator, path)?; } ``` Besides `Io`, its `Rux.toml` lists `Allocator`, `FileSystem`, `Path` and `Text` under `[Dependencies]`. ## Run it ```sh cd Examples/Files/Binary rux run ``` ```text Bin/record.bin holds 14 bytes version 3, count 1200000, average 2.75 Bin/record.bin holds 10 bytes the file ends inside a field: record refused ``` ## Common mistakes ::mistake **A value that does not fit the field.**:br`WriteUint16(writing, Endian::Little, 70000)` fails with: ```text error: argument 3 to 'WriteUint16' has type 'int', but parameter 'value' requires 'uint16' ``` 70000 needs more than sixteen bits, so the literal cannot become a `uint16`. :: ::mistake **Writing an `int` variable.**:br With `let count = 1200000;`, `WriteUint32(writing, Endian::Little, count)` fails with: ```text has type 'int', but parameter 'value' requires 'uint32' ``` A variable already has its type. Declare it `let count: uint32 = 1200000;`, or convert it with `as uint32`. :: ::mistake **Reading the fields in a different order.**:br Swap the first two reads and the program still runs, printing `version 18, count 1333788675`: the bytes are read, just as the wrong fields. Nothing in a binary file can catch this; only the agreement between writer and reader can. :: ::mistake **Reading with the other byte order.**:br Read `count` with `Endian::Big` and it comes out as 2152665600 instead of 1200000 — the same four bytes, assembled backwards. The byte order is part of the format, and both sides must state the same one. :: ## Try it yourself 1. Add a fourth field, an `int8` temperature, to both the writer and `ReadRecord`. How many bytes is the record now? 2. Cut the file to 6 bytes instead of 10. Which field is the first one that cannot be read? 3. Write two records one after the other, and read them back in a loop until the end of the file. 4. Write the `uint32` 1200000 with `Endian::Big` and read it with `Endian::Big`. Is the file any different in size? ## Learn more - [Endian](https://rux-lang.dev/docs/learn/endian) — byte order, and why a format must state it - [File](https://rux-lang.dev/docs/learn/file) — `Read` as one attempt, and the end of a file as a failure - [Integer](https://rux-lang.dev/docs/learn/integer) and [Float](https://rux-lang.dev/docs/learn/float) — the widths behind each field's size - [Atomic file](https://rux-lang.dev/docs/learn/atomic-file) — how to avoid leaving a record cut short in the first place # Buffered I/O ::note **You'll need**: [File](https://rux-lang.dev/docs/learn/file), [Interface value](https://rux-lang.dev/docs/learn/interface-value), [Destructor](https://rux-lang.dev/docs/learn/destructor) :: Every `File::Write` is a request to the operating system, and a request costs about the same for ten bytes as for ten thousand. A program that writes a log line at a time pays that cost per line. `Io::BufferedWriter` stands in between: it gathers small writes in memory and sends them to the file in one large write when its buffer would overflow. The price is a new question — has this byte actually reached the file yet? — and this lesson makes the answer visible. ## A writer in front of the file ```rux var file = File::Open(allocator, path, OpenOptions::Writing())?; let sink: Writer = file.Stream(); var buffered = BufferedWriter::New(allocator, sink, 32)?; ``` A buffered writer keeps its destination for as long as it lives, so it needs a stored stream rather than a borrow. `file.Stream()` gives one: a `Writer` [interface value](https://rux-lang.dev/docs/learn/interface-value) that refers to `file`. That makes an ordering rule — **the file must outlive the writer**. The last argument is the buffer's size in bytes. The lesson uses a tiny 32 so it fills quickly; the usual choice is 0, which means the default of 8 KiB. The buffer is memory, so `New` takes an allocator and is fallible. ## Pending until the buffer fills Each entry is ten bytes. After every write the program prints how many bytes are **pending** in the buffer and how big the file really is: ```rux for i in 1..=6 { buffered.Write("entry ...\n")?; PrintLine("{:5} {:7} {:7}", i, buffered.Pending(), file.Size()?); } ``` | Write | Pending | In the file | What happened | | ----- | ------- | ----------- | ------------------------------------------- | | 1 | 10 | 0 | gathered | | 2 | 20 | 0 | gathered | | 3 | 30 | 0 | gathered | | 4 | 10 | 30 | 40 would not fit in 32: the 30 go out first | | 5 | 20 | 30 | gathered | | 6 | 30 | 30 | gathered | | flush | 0 | 60 | `Flush` sends the rest | Six writes reached the operating system as two. With a real 8 KiB buffer and short lines, it is hundreds to one. ```mermaid sequenceDiagram participant P as Program participant B as `BufferedWriter` participant F as `File` P->>B: `Write` (entries 1, 2, 3) Note over B: 30 bytes pending P->>B: `Write` (entry 4) B->>F: one `Write` of 30 bytes Note over B: entry 4 pending P->>B: `Write` (entries 5, 6) P->>B: `Flush()` B->>F: one `Write` of 30 bytes B-->>P: success, or the `IoError` P->>F: `Close()` ``` A single write as large as the whole buffer skips it: the writer sends what it holds, then passes the big write straight through, since gathering it would gain nothing. ## Flush, and where its failure goes A byte that is pending is not in the file, and nothing reading the file can see it. So call `Flush` when the data must be there: before closing the file, before telling anyone it is written, and before reading it back. ```rux buffered.Flush()?; PrintLine("flush {:7} {:7}", buffered.Pending(), file.Size()?); file.Close()?; ``` `Flush` returns `! IoError`, and that is where a failed send is reported. The writer's [destructor](https://rux-lang.dev/docs/learn/destructor) flushes too, as a safety net — but a destructor has nowhere to report a failure, so there it is discarded. The safety net catches forgetfulness; only an explicit `Flush` tells you whether the bytes arrived. Reading has a mirror image, `BufferedReader`: it fills its buffer with one large read and serves small reads from it, the same trade the other way round. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Files/BufferedIo){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // Every `File::Write` is a request to the operating system, and a request costs about the same // for ten bytes as for ten thousand. A program that writes many small pieces pays that cost per // piece. `Io::BufferedWriter` stands in between: it gathers small writes in memory and sends // them to the file in one large write when the buffer would overflow. `BufferedReader` does the // same for reading, filling its buffer with one large read and serving small reads from it. // // The price is that a written byte is not in the file yet. It is pending in the buffer until // the buffer fills or `Flush` sends it, and until then nothing reading the file can see it. So: // // - call `Flush` when the data must be in the file: before closing it, before telling anyone it // is written, and before reading it back; // - `Flush` returns `! IoError`, and that is where a failed send is reported. The writer's // destructor flushes too, as a safety net, but a destructor has nowhere to report a failure, // so it is discarded there. // // A buffered writer keeps its destination for as long as it lives, so it needs a stored stream // rather than a borrow: `file.Stream()` gives one. The file must outlive the writer. import Allocator::{ Allocator, SystemAllocator }; import FileSystem::{ DeleteFile, File, OpenOptions }; import Io::{ BufferedWriter, IoError, PrintLine, Writer }; import Path::{ OsString, Path }; import Text::TextError; func Main() -> ! IoError | TextError { var system = SystemAllocator(); let allocator: Allocator = system; var holder = OsString::FromText(allocator, "Bin/log.txt")?; let path = Path::FromView(holder.View()); var file = File::Open(allocator, path, OpenOptions::Writing())?; let sink: Writer = file.Stream(); // A tiny 32-byte buffer, so it fills quickly. The usual choice is 0, meaning 8 KiB. var buffered = BufferedWriter::New(allocator, sink, 32)?; PrintLine("write pending in file"); for i in 1..=6 { // Each entry is ten bytes. The fourth no longer fits, so the first three go out first. buffered.Write("entry ...\n")?; PrintLine("{:5} {:7} {:7}", i, buffered.Pending(), file.Size()?); } buffered.Flush()?; PrintLine("flush {:7} {:7}", buffered.Pending(), file.Size()?); file.Close()?; DeleteFile(allocator, path)?; } ``` Besides `Io`, its `Rux.toml` lists `Allocator`, `FileSystem`, `Path` and `Text` under `[Dependencies]`. ## Run it ```sh cd Examples/Files/BufferedIo rux run ``` ```text write pending in file 1 10 0 2 20 0 3 30 0 4 10 30 5 20 30 6 30 30 flush 0 60 ``` ## Common mistakes ::mistake **Handing over the file instead of its stream.**:br`BufferedWriter::New(allocator, file, 32)` fails with an error and a note: ```text error: move-only value 'file' requires an explicit '<-' in argument 'File' prohibits copying ``` The writer wants a `Writer` that refers to the file, not the file itself: pass `file.Stream()`. :: ::mistake **Closing the file before flushing.**:br Swap `Flush` and `Close` and the last 30 bytes never arrive: the file ends at 30 bytes, not 60. The explicit `Flush` after `Close` fails and ends the program with status 1; leave it out and the destructor's flush fails silently instead. Flush first, then close. :: ::mistake **Checking the file too early.**:br`file.Size()` reports what the operating system has, not what you have written. Until the buffer fills or is flushed, the file looks shorter than your program thinks it is. :: ## Try it yourself 1. Change the buffer size to 25, then to 0. Predict the "in file" column each time before you run it. 2. Write one entry of 40 bytes into the 32-byte buffer. What does `Pending` say straight afterwards? 3. Remove the `Flush` call and the `DeleteFile` at the end, run, and look at `Bin/log.txt`. Did the destructor's flush deliver the last entries? Think about when the destructor runs, and when the file was closed. 4. Replace `buffered.Write(…)` with `WriteAll(buffered, …)` and read the error. `BufferedWriter` has a `Write` and a `Flush` — so why is it not a `Writer`? (Hint: look back at how a type implements an interface in [Interface](https://rux-lang.dev/docs/learn/interface).) ## Learn more - [Interface value](https://rux-lang.dev/docs/learn/interface-value) — what `let sink: Writer = file.Stream();` holds - [Destructor](https://rux-lang.dev/docs/learn/destructor) — the safety-net flush, and why it cannot report - [File](https://rux-lang.dev/docs/learn/file) — `Write` as one attempt, and `Close` as a fallible step - [Atomic file](https://rux-lang.dev/docs/learn/atomic-file) — a different promise: that a reader never sees a file half-written # Atomic file ::note **You'll need**: [File](https://rux-lang.dev/docs/learn/file), [Binary](https://rux-lang.dev/docs/learn/binary) :: Overwriting a file in place has a dangerous moment. Opening it with `OpenOptions::Writing()` empties it at once, and until the last byte is written the file holds only part of the new contents. A crash, a full disk, or a reader arriving at the wrong time finds a broken file — and the old one is already gone. Settings files, saved games and databases all need a way round that moment, and the `FileSystem` package has one. ## Write elsewhere, then rename ```rux func WriteAtomically(allocator, target: Path, contents: char8[..]) -> ! IoError ``` `WriteAtomically` never touches the target until the new contents are complete. It writes them to a new temporary file in the **same directory** as the target, forces them to the disk, and then renames the temporary file onto the target's name in one step the filesystem cannot interrupt: ```mermaid flowchart LR b["create a temporary file
beside the target"] --> w["write the new
contents into it"] w --> s["sync it
to the disk"] s --> r["rename it onto
the target's name"] r --> n["from here on, readers
see the new contents"] ``` Until the last step the target is never opened, so anyone reading it meanwhile finds the complete old contents. The same directory matters: a rename is only atomic within one volume, and the system's temporary folder is often on another, where a "rename" silently becomes a copy and a delete. | | Writing in place | `WriteAtomically` | | ------------------------------- | -------------------------- | -------------------------------------- | | While writing, the target holds | part of the new contents | the complete old contents | | After a crash part-way | a broken file | the old file, untouched | | If writing fails | a broken file | the old file; the temporary is deleted | | A reader may see | old, empty, partial or new | old or new, never anything else | For a file whose whole contents are in hand, one call does it: ```rux WriteAtomically(allocator, path, "volume = 3")?; ``` ## The same steps by hand `WriteAtomically` is built on `AtomicWrite`, and the second half of the program uses it directly to look inside. `Begin` creates the temporary file; the value is a `Writer`, so `WriteAll` writes into it: ```rux var replacement = AtomicWrite::Begin(allocator, path)?; WriteAll(replacement, "volume = 11")?; Show(allocator, "while writing", path)?; ``` At this point the new contents exist — in the temporary file. `Show` opens the target and still finds `volume = 3`. Only `Commit` makes the switch: ```rux replacement.Commit(allocator)?; Show(allocator, "after commit", path)?; ``` `Commit` syncs the temporary file and renames it onto the target, and from then on the target reads `volume = 11`. ## A replacement you do not commit If you change your mind, `Abandon` deletes the temporary file and leaves the target alone. Simply dropping the value does the same: its destructor throws the partial file away. So an early return, or a `?` that passes a failure on part-way through writing, leaves the old contents exactly where they were — which is the behaviour that makes the type worth using. ## What it does not promise Atomic is not the same as durable. After `Commit`, the new contents are on the disk, but the rename itself — the directory entry — may not be: making that survive a power cut needs the directory synced too, which Windows does not offer. So after a crash at the wrong moment the target may still hold the old version. Old or new, but always whole. The `Show` helper reads the whole file into one buffer. Its 64 bytes are plenty for these settings; a file of unknown size would need a reading loop like the one in [File](https://rux-lang.dev/docs/learn/file). ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Files/AtomicFile){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // Overwriting a file in place has a dangerous moment. Opening it with `Writing` empties it, and // until the last byte is written the file holds part of the new contents. A crash, a full disk // or a reader arriving at the wrong time sees a broken file, and the old one is already gone. // // `FileSystem::WriteAtomically` avoids that moment: // // func WriteAtomically(allocator, target: Path, contents: char8[..]) -> ! IoError // // It writes the contents to a new temporary file in the same directory as the target, forces // them to the disk, and then renames the temporary file onto the target's name in one step. The // same directory matters, because a rename is only atomic within one volume. // // What it promises: anyone opening the target at any moment finds the complete old contents or // the complete new ones, never a mix, never an empty file and never a missing one. If it fails, // the target still holds the old contents, and the temporary file is deleted. // // What it does not promise: that the rename itself survives a power cut. That would need the // directory synced to disk too, which Windows does not offer, so after a crash at the wrong // moment the target may still hold the old version. Old or new, but always whole. // // The work is done by `AtomicWrite`, which the second half uses directly to look inside. import Allocator::{ Allocator, SystemAllocator }; import FileSystem::{ AtomicWrite, DeleteFile, File, OpenOptions, WriteAtomically }; import Io::{ IoError, PrintLine, ReadExact, WriteAll }; import Path::{ OsString, Path }; import Text::TextError; // Prints what the file holds right now. The files here are short, so one buffer is enough. func Show(allocator: Allocator, label: char8[..], path: Path) -> ! IoError { var file = File::Open(allocator, path, OpenOptions::Reading())?; let size = file.Size()? as uint; var buffer: char8[64]; ReadExact(file, buffer[..size])?; file.Close()?; PrintLine("{:16} {}", label, buffer[..size]); } func Main() -> ! IoError | TextError { var system = SystemAllocator(); let allocator: Allocator = system; var holder = OsString::FromText(allocator, "Bin/settings.txt")?; let path = Path::FromView(holder.View()); WriteAtomically(allocator, path, "volume = 3")?; Show(allocator, "first write", path)?; // The same steps by hand. While the new contents are being written they live in the // temporary file, and the target still holds the old ones. var replacement = AtomicWrite::Begin(allocator, path)?; WriteAll(replacement, "volume = 11")?; Show(allocator, "while writing", path)?; // `Commit` syncs the temporary file and renames it onto the target. replacement.Commit(allocator)?; Show(allocator, "after commit", path)?; DeleteFile(allocator, path)?; } ``` Besides `Io`, its `Rux.toml` lists `Allocator`, `FileSystem`, `Path` and `Text` under `[Dependencies]`. ## Run it ```sh cd Examples/Files/AtomicFile rux run ``` ```text first write volume = 3 while writing volume = 3 after commit volume = 11 ``` ## Common mistakes ::mistake **Forgetting `Commit`.**:br Leave out `replacement.Commit(allocator)?;` and the program still compiles and runs, but "after commit" prints `volume = 3`: the new contents went into the temporary file, and the destructor throws them away at the end of `Main`. Nothing reaches the target without `Commit`. :: ::mistake **Leaving `Commit` unchecked.**:br`replacement.Commit(allocator);` fails with: ```text error: fallible result of type '! IoError' is discarded ``` A commit that failed means the target still holds the old contents, and the program must know that. :: ::mistake **Declaring the replacement with `let`.**:br`let replacement = AtomicWrite::Begin(…)?;` makes `WriteAll(replacement, …)` fail with: ```text error: argument 1 to 'WriteAll' cannot borrow immutable 'replacement' as '&var Writer' ``` Writing changes it; declare it `var`. :: ::mistake **Building your own with a temporary folder elsewhere.**:br Writing to `FileSystem::TemporaryDirectory` and renaming onto the target looks the same, but when that folder is on another volume the rename is no longer atomic. `AtomicWrite` always creates its temporary file beside the target. :: ## Try it yourself 1. Replace `Commit` with `replacement.Abandon(allocator)?;` and check that the target still says `volume = 3`. 2. Write a `volume = 11` setting in place instead, with `File::Open` and `OpenOptions::Writing()`, and call `Show` between opening and writing. What does a reader see at that moment? 3. Use `AtomicWrite` to write the contents in three `WriteAll` calls — `volume`, `=`, `11` — and commit once. 4. Call `Show` on the target from a second `Show` call placed after `Begin` but before `WriteAll`. Is the target empty, as it would be with `Writing`? ## Learn more - [File](https://rux-lang.dev/docs/learn/file) — opening, writing and closing, and why `Close` is fallible - [Temporary file](https://rux-lang.dev/docs/learn/temporary-file) — the scratch file `AtomicWrite` is built on - [Destructor](https://rux-lang.dev/docs/learn/destructor) — how dropping an uncommitted replacement cleans up - [Binary](https://rux-lang.dev/docs/learn/binary) — the cut-short record that writing atomically prevents # Temporary file ::note **You'll need**: [Metadata](https://rux-lang.dev/docs/learn/metadata), [Destructor](https://rux-lang.dev/docs/learn/destructor), [Move](https://rux-lang.dev/docs/learn/move) :: A temporary file is scratch space with a name: somewhere to put data too big for memory, or a file to hand to another program. Two things make it harder than opening any file. The name must not clash with another file, and must not be guessable. And the file must not be left behind when the program is done with it — not even when the program leaves early through a failure. ## A name nobody can predict If another program could predict the name, it could create that name first — perhaps as a link to some other file — and this program would write straight through it. So `TemporaryFile::Create` builds the name from a prefix plus 16 random hex digits, and creates the file only if nothing by that name exists yet; a collision just means the next random name is tried. ```rux func Create(allocator, directory: Path, prefix: char8[..]) -> TemporaryFile ! IoError ``` ```rux var scratch = TemporaryFile::Create(allocator, directory, "draft-")?; WriteAll(scratch.file, "work in progress")?; PrintLine("created {}", scratch.AsPath().FileName() ?? OsStringView()); ``` The name comes out as `draft-` and sixteen hex digits, different on every run. `scratch.file` is an ordinary open `File`, opened for both reading and writing, and `AsPath` lends the full path. The directory is up to you. `FileSystem::TemporaryDirectory` returns the system's own folder for such files; this program uses the package's `Bin/` folder instead, so you can watch what happens there. ## Three ways to finish A `TemporaryFile` owns both the open file and its name, so it decides what happens to them: ```mermaid flowchart LR c["`TemporaryFile::Create`"] --> use["write, read,
hand on the name"] use --> close["`Close(allocator)?`"] use --> drop["dropped without `Close`:
an early return, a failure"] use --> keep["`Keep()?`"] close --> gone1["closed and deleted;
a failure is reported"] drop --> gone2["the destructor deletes it;
a failure goes unreported"] keep --> stays["closed, and the file stays;
the value gives up its name"] ``` | Ending | The file afterwards | A failed delete is… | | ------------------- | ------------------- | ------------------------- | | `Close(allocator)?` | deleted | reported, as an `IoError` | | dropped | deleted | silently ignored | | `Keep()?` | kept | — nothing is deleted | `Exists` checks the outcome. It asks for the file's [metadata](https://rux-lang.dev/docs/learn/metadata) and turns the fallible into a `bool` with `Core::Succeeded` — true for any success — met in [Generic outcome](https://rux-lang.dev/docs/learn/generic-outcome): ```rux func Exists(allocator: Allocator, path: Path) -> bool { return Succeeded(MetadataOf(allocator, path, true)); } ``` ## Closing: remember the name first After `Close`, the value no longer has a name — its `AsPath` is empty. To check that the file is gone, the program copies the name into a `PathBuffer` of its own before closing: ```rux var name = PathBuffer::FromPath(allocator, scratch.AsPath())?; scratch.Close(allocator)?; PrintLine("exists after Close {}", Exists(allocator, name.AsPath())); ``` `Close` closes the file, deletes it, and reports whether the deletion worked. ## Dropping: the destructor cleans up `Forgotten` creates a temporary file, writes to it, and returns without closing it: ```rux func Forgotten(allocator: Allocator, directory: Path) -> PathBuffer ! IoError | TextError { var scratch = TemporaryFile::Create(allocator, directory, "draft-")?; WriteAll(scratch.file, "never finished")?; var name = PathBuffer::FromPath(allocator, scratch.AsPath())?; return <-name; } ``` When `Forgotten` returns, `scratch` goes out of scope and its [destructor](https://rux-lang.dev/docs/learn/destructor) deletes the file. The same happens if any `?` in the function passes a failure on, which is the point: no path out of the function leaves the file behind. The name comes back as a `PathBuffer` moved out with `<-`, as in [Move](https://rux-lang.dev/docs/learn/move), and `Main` confirms the file no longer exists. The safety net has the same limit as the one in [Buffered I/O](https://rux-lang.dev/docs/learn/buffered-io): a destructor cannot report a failure, so a delete that fails there goes unnoticed. Call `Close` when you want to know. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Files/TemporaryFile){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // A temporary file is scratch space with a name: somewhere to put data that is too big for // memory, or a name to hand to another program. Two things make that harder than it sounds. // // The name must not clash, and must not be guessable. If another program could predict it, it // could create that name first, perhaps as a link to some other file, and this program would // write through it. `TemporaryFile::Create` builds the name from a prefix plus 16 random hex // digits, and creates the file only if nothing by that name exists yet. // // func Create(allocator, directory: Path, prefix: char8[..]) -> TemporaryFile ! IoError // // And the file must not be left behind. A `TemporaryFile` owns both the open file and its name. // `Close` closes and deletes it, and reports whether the deletion worked. If the value is // dropped without `Close`, its destructor deletes the file anyway, on early returns and failure // paths too, but a destructor cannot report a failure, so it stays quiet about one. `Keep` // closes the file and gives up the name, for a file that should outlive the value. // // `FileSystem::TemporaryDirectory` returns the system's folder for such files. This program // uses this package's own `Bin/` folder instead. The name is random, so it differs on every run. import Allocator::{ Allocator, SystemAllocator }; import Core::Succeeded; import FileSystem::{ MetadataOf, TemporaryFile }; import Io::{ IoError, PrintLine, WriteAll }; import Path::{ OsString, OsStringView, Path, PathBuffer }; import Text::TextError; func Exists(allocator: Allocator, path: Path) -> bool { return Succeeded(MetadataOf(allocator, path, true)); } // Creates a temporary file, writes to it, and returns without closing it. func Forgotten(allocator: Allocator, directory: Path) -> PathBuffer ! IoError | TextError { var scratch = TemporaryFile::Create(allocator, directory, "draft-")?; WriteAll(scratch.file, "never finished")?; var name = PathBuffer::FromPath(allocator, scratch.AsPath())?; return <-name; } func Main() -> ! IoError | TextError { var system = SystemAllocator(); let allocator: Allocator = system; var holder = OsString::FromText(allocator, "Bin")?; let directory = Path::FromView(holder.View()); var scratch = TemporaryFile::Create(allocator, directory, "draft-")?; // `file` is an ordinary open `File`, opened for reading and writing. WriteAll(scratch.file, "work in progress")?; PrintLine("created {}", scratch.AsPath().FileName() ?? OsStringView()); PrintLine("exists while held {}", Exists(allocator, scratch.AsPath())); // Remember the name, because after `Close` the value no longer has one. var name = PathBuffer::FromPath(allocator, scratch.AsPath())?; scratch.Close(allocator)?; PrintLine("exists after Close {}", Exists(allocator, name.AsPath())); let forgotten = Forgotten(allocator, directory)?; PrintLine("exists after drop {}", Exists(allocator, forgotten.AsPath())); } ``` Besides `Io`, its `Rux.toml` lists `Allocator`, `Core`, `FileSystem`, `Path` and `Text` under `[Dependencies]`. ## Run it ```sh cd Examples/Files/TemporaryFile rux run ``` ```text created draft-08bf264c6b30a0cc exists while held true exists after Close false exists after drop false ``` ## Common mistakes ::mistake **Returning the borrowed path.**:br If `Forgotten` returned `scratch.AsPath()` as a `Path`, it would compile — and crash when `Main` used it. A `Path` only borrows its units, and these belong to `scratch`, which is destroyed as the function returns. Copy the name into a `PathBuffer` that owns its units, as the lesson does. :: ::mistake **Returning a buffer without `<-`.**:br`return name;` fails with an error and a note: ```text error: move-only value 'name' requires an explicit '<-' in return 'PathBuffer' prohibits copying ``` Write `return <-name;`. :: ::mistake **Asking for the name after `Close`.**:br Once closed, the value has given its name up: `scratch.AsPath()` is an empty path. Copy the name first if you still need it. :: ::mistake **Declaring it with `let`.**:br`let scratch = TemporaryFile::Create(…)?;` makes writing fail, and `Close` too: ```text error: argument 1 to 'WriteAll' cannot borrow a part of immutable 'scratch' as '&var Writer' cannot call 'Close' on immutable 'scratch' ``` :: ## Try it yourself 1. Replace `scratch.Close(allocator)?` with `scratch.Keep()?`. Does the file survive the program? Look in `Bin/`, and delete it by hand afterwards. 2. Create the file in the system's folder instead: `var temporary = TemporaryDirectory(allocator)?;` gives a `PathBuffer`, and `temporary.AsPath()` is the directory. 3. Make `Forgotten` fail on purpose after writing — for example with `fail IoError::Of(IoErrorKind::Other);` — so that the program ends with status 1. Is a `draft-` file left in `Bin/` afterwards? 4. Create two temporary files with the same prefix and print both names. ## Learn more - [Destructor](https://rux-lang.dev/docs/learn/destructor) — what runs when `scratch` goes out of scope - [Move](https://rux-lang.dev/docs/learn/move) — returning the `PathBuffer` with `<-` - [Metadata](https://rux-lang.dev/docs/learn/metadata) — how `Exists` asks whether a file is there - [Atomic file](https://rux-lang.dev/docs/learn/atomic-file) — a temporary file put to work: replacing another file whole # Memory streams ::note **You'll need**: [Binary](https://rux-lang.dev/docs/learn/binary), [Buffered I/O](https://rux-lang.dev/docs/learn/buffered-io), [Interface parameter](https://rux-lang.dev/docs/learn/interface-parameter) :: Every lesson in this part so far has moved bytes between a program and a file. But the code that decides **which** bytes — a record format, a header, a message — has nothing to do with files. In [Binary](https://rux-lang.dev/docs/learn/binary), `ReadUint16` and `WriteUint16` take a `Reader` and a `Writer`, the interfaces any stream implements, and [Buffered I/O](https://rux-lang.dev/docs/learn/buffered-io) slipped a buffer in between without the writing code noticing. A **memory stream** is a `Reader` or a `Writer` whose bytes live in memory. With one, the same format code builds a message in memory, reads bytes that arrived some other way, and — most usefully — is tested without touching the disk: ```rux import Io::{ ByteReader, ByteWriter, Endian, IoError, Print, PrintLine, ReadInt16, ReadUint16, Reader, WriteInt16, WriteUint16, Writer }; ``` ## Code written against the interfaces The program's format is a count, then each reading's sensor and temperature, two bytes each, little endian. The function that writes it takes a `&var Writer` — an [interface parameter](https://rux-lang.dev/docs/learn/interface-parameter) — so it neither knows nor cares where the bytes go: ```rux func WriteReadings(out: &var Writer, readings: Reading[..]) -> ! IoError { WriteUint16(out, Endian::Little, readings.length as uint16)?; for reading in readings { WriteUint16(out, Endian::Little, reading.sensor)?; WriteInt16(out, Endian::Little, reading.tenths)?; } } ``` `ReadReadings` is the other half, from a `&var Reader`. Neither function names a file or a memory stream; `Main` decides, by what it passes: ```mermaid flowchart LR w["`WriteReadings`"] --> wi{"`&var Writer`"} wi --> bw["`ByteWriter`
bytes in memory"] wi --> fw["`File`
bytes on disk"] r["`ReadReadings`"] --> ri{"`&var Reader`"} ri --> br["`ByteReader`
over a slice"] ri --> fr["`File`"] ``` ## Writing into memory A `ByteWriter` keeps everything written in a block of memory that it grows as needed, doubling each time, so a long run of small writes stays cheap. It is made from an [allocator](https://rux-lang.dev/docs/learn/allocator), and `Bytes()` hands the bytes back as a `char8[..]` view: ```rux var memory = ByteWriter::New(allocator); WriteReadings(memory, readings[..])?; ``` Three readings make 14 bytes — the count, then three pairs — and the program prints them in hexadecimal: `03 00` is the count 3 with its low byte first, `d7 00` is 215, the 21.5 °C of sensor 1. | Method | Returns | Does | | --------- | ------------------ | -------------------------------------------------------- | | `New` | `ByteWriter` | an empty writer drawing on an allocator | | `Write` | `uint ! IoError` | appends, or overwrites after a seek back | | `Bytes` | `char8[..]` | everything written, valid until the next change | | `Length` | `uint` | how many bytes have been written | | `Seek` | `uint64 ! IoError` | moves where the next write lands, within what is written | | `Clear` | — | forgets the bytes, keeping the block for reuse | | `Release` | — | gives the block back; the destructor does this too | ## Reading from memory A `ByteReader` reads a slice of bytes you already have — here the writer's own — from the start. It borrows them, so they must outlive it, and it fails with `EndOfStream` once they are used up, exactly like a file: ```rux var reader = ByteReader::New(memory.Bytes()); ReadReadings(reader)?; ``` `Position()` tells how far it has read and `Remaining()` returns the bytes not yet read. ## The same code, a file `Main` then passes a `File` to the very same two functions. The file holds the same 14 bytes, and reads back the same three readings — the format code never changed. That is the point of a memory stream: the format is proved right in memory, where a test is fast and leaves nothing behind, and then trusted with a file. The last part of the program goes further. A damaged input — a stream that ends in the middle of a reading — normally means writing a file and cutting it short, as Binary did. With a `ByteReader`, it is just a shorter slice: ```rux var cut = ByteReader::New(memory.Bytes()[..9]); ``` The first reading comes through whole. The second has its sensor but only one byte of its temperature, so `ReadInt16` fails with `EndOfStream`, and the read is refused rather than finished with a made-up value. ## Seeking Both streams can `Seek` within what they hold. A writer that seeks back overwrites in place, which is how a format whose header holds a count or a length is written when that number is only known at the end: ```rux var memory = ByteWriter::New(allocator); WriteAll(memory, "count=0;a;b;c")?; // Go back and fix the count once it is known. memory.Seek(SeekFrom::Start, 6)?; WriteAll(memory, "3")?; PrintLine("{}", memory.Bytes()); ``` This prints `count=3;a;b;c`. A seek before the start or past the end of what is held fails with `IoErrorKind::InvalidInput`. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Files/MemoryStream){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // Code that reads and writes bytes is usually written against the `Reader` and `Writer` // interfaces rather than against `File`, and the Binary lesson's `ReadUint16` and `WriteUint16` // are written that way. A memory stream is a `Reader` or `Writer` whose bytes live in memory, so // the same code can run without a file at all: // // ByteWriter a `Writer` that keeps everything written in a block it grows as needed; // `Bytes()` hands the bytes back // ByteReader a `Reader` over a slice of bytes you already have; at the end it fails // with `EndOfStream`, like a file // // That is how a format is tested without touching the disk, how a message is built in memory // before it is sent in one piece, and how bytes that arrived some other way — over a network, // embedded in the program — are read with the code that reads files. // // The file this program also writes lives in its package's `Bin/` folder, and is deleted at // the end. import Allocator::{ Allocator, SystemAllocator }; import FileSystem::{ DeleteFile, File, OpenOptions }; import Io::{ ByteReader, ByteWriter, Endian, IoError, Print, PrintLine, ReadInt16, ReadUint16, Reader, WriteInt16, WriteUint16, Writer }; import Path::{ OsString, Path }; import Text::TextError; // A sensor's reading, in tenths of a degree: 215 is 21.5 °C. struct Reading { sensor: uint16; tenths: int16; } // The format: a count, then each reading's sensor and temperature, two bytes each, little endian. // It takes any `Writer`, so it neither knows nor cares where the bytes go. func WriteReadings(out: &var Writer, readings: Reading[..]) -> ! IoError { WriteUint16(out, Endian::Little, readings.length as uint16)?; for reading in readings { WriteUint16(out, Endian::Little, reading.sensor)?; WriteInt16(out, Endian::Little, reading.tenths)?; } } // The other half of the format, from any `Reader`. A stream that ends part-way fails it. func ReadReadings(input: &var Reader) -> ! IoError { let count = ReadUint16(input, Endian::Little)?; for _ in 0..count { let sensor = ReadUint16(input, Endian::Little)?; let tenths = ReadInt16(input, Endian::Little)?; PrintLine(" sensor {} {:.1} C", sensor, tenths as float64 / 10.0); } } func Main() -> ! IoError | TextError { var system = SystemAllocator(); let allocator: Allocator = system; let readings: Reading[3] = [Reading { sensor: 1, tenths: 215 }, Reading { sensor: 2, tenths: 198 }, Reading { sensor: 7, tenths: 230 }]; // Into memory. The writer grows its block as bytes arrive. var memory = ByteWriter::New(allocator); WriteReadings(memory, readings[..])?; Print("memory: {} bytes:", memory.Length()); for byte in memory.Bytes() { Print(" {:02x}", byte as uint8); } PrintLine(); // Back out of memory, with the code that would read a file. Reading moves the reader's // position along, so it must be `var`; a `let` reader is refused: // // error: argument 1 to 'ReadReadings' cannot borrow immutable 'reader' as // '&var rux/io::Reader' var reader = ByteReader::New(memory.Bytes()); ReadReadings(reader)?; // The same two functions, given a file. var holder = OsString::FromText(allocator, "Bin/readings.bin")?; let path = Path::FromView(holder.View()); var writing = File::Open(allocator, path, OpenOptions::Writing())?; WriteReadings(writing, readings[..])?; writing.Close()?; var reading = File::Open(allocator, path, OpenOptions::Reading())?; PrintLine("file: {} bytes", reading.Size()?); ReadReadings(reading)?; reading.Close()?; DeleteFile(allocator, path)?; // Damaged input, made without damaging a file: only the first 9 bytes of the 14. var cut = ByteReader::New(memory.Bytes()[..9]); PrintLine("cut: 9 bytes"); ReadReadings(cut) catch { error if error.IsEnd() => { PrintLine(" ended inside a reading: refused"); }, error => fail error }; } ``` Besides `Io`, its `Rux.toml` lists `Allocator`, `FileSystem`, `Path` and `Text` under `[Dependencies]`. ## Run it ```sh cd Examples/Files/MemoryStream rux run ``` ```text memory: 14 bytes: 03 00 01 00 d7 00 02 00 c6 00 07 00 e6 00 sensor 1 21.5 C sensor 2 19.8 C sensor 7 23.0 C file: 14 bytes sensor 1 21.5 C sensor 2 19.8 C sensor 7 23.0 C cut: 9 bytes sensor 1 21.5 C ended inside a reading: refused ``` ## Common mistakes ::mistake **A reader declared with `let`.**:br Reading moves the reader's position along, so it is passed as `&var`. With `let reader = ByteReader::New(memory.Bytes());`, the call fails with: ```text error: argument 1 to 'ReadReadings' cannot borrow immutable 'reader' as '&var rux/io::Reader' help: declare 'reader' with 'var' to make it mutable ``` :: ::mistake **Keeping `Bytes()` across a write.**:br The view points into the writer's block, which moves when the writer grows. A view taken before a write, a `Clear` or a `Release` may no longer show the writer's bytes. Take `Bytes()` after the last write, and keep the writer alive while a `ByteReader` reads them. :: ::mistake **Copying a writer.**:br A `ByteWriter` owns its block, so `let copy = memory;` fails with: ```text error: move-only value 'memory' requires an explicit '<-' in initialization ``` Pass it by reference, as `WriteReadings` takes it, or move it with `<-`. :: ::mistake **Seeking past the end.**:br A seek can only land within what is held. `memory.Seek(SeekFrom::Start, 100)` on a 13-byte writer fails with `IoErrorKind::InvalidInput`; it does not pad the gap with zeros. To extend, seek to the end and write. :: ## Try it yourself 1. Write the readings into a `ByteWriter`, then write the same count and readings a second time, and read both copies back with one `ByteReader`. 2. Give the format a header: write a placeholder count of 0, the readings, then `Seek` back to the start and write the real count, as in the seeking example. 3. Read from a `ByteReader` over only the first two bytes, `memory.Bytes()[..2]`: a count of 3 with no readings after it. Which call fails, and with what? 4. Change `Endian::Little` to `Endian::Big` in both functions and compare the printed bytes. ## Learn more - [Binary](https://rux-lang.dev/docs/learn/binary) — `ReadUint16`, `WriteUint16` and fixed-width records - [Buffered I/O](https://rux-lang.dev/docs/learn/buffered-io) — another stream that stands in front of a file - [Interface parameter](https://rux-lang.dev/docs/learn/interface-parameter) — taking `&var Writer` instead of a concrete type - [Io API](https://rux-lang.dev/docs/api/io) — `ByteReader`, `ByteWriter` and the stream interfaces - [Reader](https://rux-lang.dev/docs/api/io/reader), [Writer](https://rux-lang.dev/docs/api/io/writer) and [Seeker](https://rux-lang.dev/docs/api/io/seeker) in the Io API - [Interface values](https://rux-lang.dev/docs/lang/interfaces/interface-values) in the Rux Reference # Part 20: Utilities The small standard packages that almost every real program reaches for sooner or later: `Time` for spans, clocks and calendar dates, `TimeZone` for the local time in a place, `Random` and `Entropy` for numbers you cannot predict — or deliberately can — `Hash` for fingerprints, and `Uuid` and `NanoId` for names nobody else will pick. Each lesson is short and stands on its own, and together they show how the standard library speaks about failure: a step that may not fit returns an optional, and a request the system may refuse returns a fallible. ## What you will learn - Spans of time with `Duration`, where every step that could overflow says so in its type. - Measuring elapsed time with `Instant`, the clock that never goes backwards. - Calendar dates and the leap-year rule, and reading dates with errors that point at the faulty byte. - Moments in time: a `DateTime` with a `UtcOffset`, RFC 3339 text, and comparing moments through `Timestamp`. - Time zones built from POSIX rules, and the local times that happen twice, or never, when the clocks change. - Seeded generators that replay the same numbers, and distributions that shape them into dice, shuffles and bell curves. - Unpredictable bytes from the operating system, and why a failure there must never be papered over. - Fast, non-cryptographic hashes and checksums, all at once or piece by piece. - Creating, printing and strictly parsing UUIDs, and shorter, URL-safe Nano IDs from any alphabet. ## The part at a glance ```mermaid flowchart LR u(["Utilities"]) --> t["Time"] u --> r["Randomness"] u --> id["Fingerprints and names"] t --> span["How long?
Duration, Stopwatch"] t --> when["When?
Date, Date and time"] t --> where["Where?
Time zone"] r --> rep["Repeatable
Random, Distribution"] r --> unp["Unguessable
Entropy"] id --> h["From data
Hash"] id --> uu["From nothing
UUID, Nano ID"] unp -. "seeds" .-> rep unp -. "random bits" .-> uu ``` ## Lessons | | Lesson | What you will learn | | ----- | ------------------------------------------------------------ | ------------------------------------------------------------ | | 20.1 | [Duration](https://rux-lang.dev/docs/learn/duration) | lengths of time, and arithmetic on them | | 20.2 | [Stopwatch](https://rux-lang.dev/docs/learn/stopwatch) | measure how long something takes | | 20.3 | [Date](https://rux-lang.dev/docs/learn/date) | calendar dates, parsing them, and leap years | | 20.4 | [Date and time](https://rux-lang.dev/docs/learn/date-time) | a date with a time and an offset, in RFC 3339 | | 20.5 | [Random](https://rux-lang.dev/docs/learn/random) | a reproducible random number generator | | 20.6 | [Distribution](https://rux-lang.dev/docs/learn/distribution) | draw from a range, shuffle, and sample a normal distribution | | 20.7 | [Entropy](https://rux-lang.dev/docs/learn/entropy) | unpredictable bytes from the operating system | | 20.8 | [Hash](https://rux-lang.dev/docs/learn/hash) | fast non-cryptographic hashes and checksums | | 20.9 | [UUID](https://rux-lang.dev/docs/learn/uuid) | create, print and parse UUIDs | | 20.10 | [Nano ID](https://rux-lang.dev/docs/learn/nano-id) | short, URL-safe random identifiers | | 20.11 | [Time zone](https://rux-lang.dev/docs/learn/time-zone) | turn a moment into local time in a time zone, and back | ## Before you start This part leans on the native outcomes: [Part 8: Optionals](https://rux-lang.dev/docs/learn/optionals) for every `Duration?` and `Date?`, and [Part 9: Errors](https://rux-lang.dev/docs/learn/errors) for parsing and for requests the system may refuse. The randomness lessons pass generators as [mutable references](https://rux-lang.dev/docs/learn/mutable-reference) and call [generic](https://rux-lang.dev/docs/learn/generic) functions, and Entropy and Hash hand bytes over through [pointers](https://rux-lang.dev/docs/learn/pointer) from [Part 15: Memory](https://rux-lang.dev/docs/learn/memory). Each lesson's package is in the Examples repository's `Utilities/` folder: ```sh cd Examples/Utilities/Duration rux run ``` A few lessons print something different on every run — a random key, a die roll, a fresh UUID or Nano ID. Their pages say which lines to expect to change. ## After this part [Part 21: Data formats](https://rux-lang.dev/docs/learn/data-formats) reads and writes JSON and TOML, the formats programs use to exchange and configure data. Before moving on, try the checkpoint projects. [Guess](https://rux-lang.dev/docs/learn/guess) is a number-guessing game whose secret comes from a generator seeded with entropy; [Age](https://rux-lang.dev/docs/learn/age) works out an age in years, months and days from two dates; [Password](https://rux-lang.dev/docs/learn/password) draws a password straight from the system's entropy without favouring any character; and [Launch](https://rux-lang.dev/docs/learn/launch) counts down to a rocket launch with `SleepFor`. For the language rules this part relies on, see [Structs](https://rux-lang.dev/docs/lang/structs/overview), [Enums](https://rux-lang.dev/docs/lang/enums/overview) and [Pointers](https://rux-lang.dev/docs/lang/pointers/overview) in the Rux Reference. # Duration ::note **You'll need**: [Presence](https://rux-lang.dev/docs/learn/presence), [Coalesce](https://rux-lang.dev/docs/learn/coalesce), [Optional propagate](https://rux-lang.dev/docs/learn/optional-propagate) :: A *duration* is a span of time — how long, not when. A lap of 83.4 seconds, a timeout of five minutes and a working week are all durations, and the `Time` package gives them one type, `Duration`, so they add, subtract and print the same way whatever unit they started in. This lesson also puts [optionals](https://rux-lang.dev/docs/learn/optional) to work. Some steps on a duration can overflow, and the package says so in their types: they return `Duration?`, and the program decides what to do when the answer is `none`. The program imports the type and lists `Time` as a dependency: ```rux import Time::Duration; ``` ## Building a duration A `Duration` keeps whole seconds plus a nanosecond remainder. Small units are converted exactly, and `{}` prints the result as decimal seconds: ```rux let lap = Duration::FromMilliseconds(83400); PrintLine("one lap {}", lap); PrintLine("in parts {} s and {} ns", lap.WholeSeconds(), lap.SubsecondNanoseconds()); ``` 83 400 ms prints as `83.4s`; underneath it is 83 whole seconds and 400 000 000 nanoseconds. Every count of seconds, milliseconds, microseconds or nanoseconds fits, so those constructors always succeed. Minutes and hours are different: an `int64` count of hours, times 3600, can be too large for an `int64` count of seconds. | Constructor | Returns | Why | | ------------------------------------------------------------------------ | ----------- | -------------------------------------- | | `FromSeconds`, `FromMilliseconds`, `FromMicroseconds`, `FromNanoseconds` | `Duration` | every count of these fits | | `FromMinutes`, `FromHours` | `Duration?` | multiplying up to seconds can overflow | | `Zero()` | `Duration` | the empty span | ## Arithmetic that can overflow `Plus`, `Minus` and `Times` can overflow the same way, so they answer `Duration?` too. Where an overflow would be a surprise, [`??`](https://rux-lang.dev/docs/learn/coalesce) supplies a fallback and the program carries on with a plain `Duration`: ```rux let race = lap.Times(12) ?? Duration::Zero(); PrintLine("twelve laps {}", race); PrintLine("in ms {}", race.TotalMilliseconds() ?? -1); ``` Asking for the total in milliseconds is a question that can overflow as well — a huge duration has more milliseconds than an `int64` holds — so `TotalMilliseconds` returns `int64?`. Going below zero is **not** an overflow. A duration may be negative, and `IsNegative` tells you so: ```rux let limit = Duration::FromSeconds(1000); match limit.Minus(race) { margin? => PrintLine("limit - race {} negative: {}", margin, margin.IsNegative()), none => PrintLine("too far apart to subtract") } ``` The race took 1000.8 s against a limit of 1000 s, so the margin is `-0.8s`. ## Several steps, one question A clock reading such as 1 h 30 min 15 s takes four steps, and three of them may overflow. Inside a function that itself returns `Duration?`, [`?`](https://rux-lang.dev/docs/learn/optional-propagate) handles each one: the first `none` ends the function with `none`, and otherwise the value is unwrapped and the next step runs. ```rux func Span(hours: int64, minutes: int64, seconds: int64) -> Duration? { let fromHours = Duration::FromHours(hours)?; let fromMinutes = Duration::FromMinutes(minutes)?; let both = fromHours.Plus(fromMinutes)?; return both.Plus(Duration::FromSeconds(seconds)); } ``` ```mermaid flowchart LR h["`FromHours`"] -- "value" --> m["`FromMinutes`"] m -- "value" --> p1["`Plus`"] p1 -- "value" --> p2["`Plus` seconds"] p2 --> r(["`Duration?`"]) h -- "`none`" --> n(["`none`"]) m -- "`none`" --> n p1 -- "`none`" --> n ``` The last line needs no `?`: `Plus` already returns `Duration?`, which is exactly what `Span` returns. ## When it does not fit The largest `int64` is about 9.2 × 10¹⁸. As a count of hours that is around a million billion years, and converted to seconds it does not fit, so `FromHours` answers `none` rather than a wrong number: ```rux match Duration::FromHours(9223372036854775807) { huge? => PrintLine("huge = {}", huge), none => PrintLine("9223372036854775807 hours does not fit, so FromHours gave none") } ``` ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Utilities/Duration){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // A duration is a span of time: how long, not when. The Time package keeps one as whole seconds // plus a nanosecond remainder, so a millisecond and a working week are the same type, add // exactly, and print with `{}` as decimal seconds. // // Building one from seconds, milliseconds or nanoseconds always works, because every count of // those fits. Building one from minutes or hours does not: an `int64` count of hours times 3600 // can overflow an `int64` count of seconds. So `FromMinutes` and `FromHours` return `Duration?`, // and so do `Plus`, `Minus` and `Times`, which can overflow the same way. A step that might not // fit says so in its type, and the program decides what to do about it. import Io::PrintLine; import Time::Duration; // A clock reading such as 1 h 30 min 15 s as one duration. Each step may overflow, so each is // followed by `?`, and the first one that does makes the whole answer `none`. func Span(hours: int64, minutes: int64, seconds: int64) -> Duration? { let fromHours = Duration::FromHours(hours)?; let fromMinutes = Duration::FromMinutes(minutes)?; let both = fromHours.Plus(fromMinutes)?; return both.Plus(Duration::FromSeconds(seconds)); } func Main() -> int { // Small units never fail, so they return a plain `Duration`. let lap = Duration::FromMilliseconds(83400); PrintLine("one lap {}", lap); PrintLine("in parts {} s and {} ns", lap.WholeSeconds(), lap.SubsecondNanoseconds()); // Arithmetic answers an optional; `??` supplies a fallback for the overflow nobody expects. let race = lap.Times(12) ?? Duration::Zero(); PrintLine("twelve laps {}", race); PrintLine("in ms {}", race.TotalMilliseconds() ?? -1); // Going below zero is not an overflow: a duration may be negative. let limit = Duration::FromSeconds(1000); match limit.Minus(race) { margin? => PrintLine("limit - race {} negative: {}", margin, margin.IsNegative()), none => PrintLine("too far apart to subtract") } // Building from hours, the case the lesson is about. match Span(1, 30, 15) { span? => PrintLine("1 h 30 min 15 s = {}", span), none => PrintLine("1 h 30 min 15 s does not fit") } // As a count of hours, the largest `int64` is about a million billion years, and as seconds it // does not fit. match Duration::FromHours(9223372036854775807) { huge? => PrintLine("huge = {}", huge), none => PrintLine("9223372036854775807 hours does not fit, so FromHours gave none") } return 0; } ``` Besides `Io`, its `Rux.toml` lists `Time` under `[Dependencies]`. ## Run it ```sh cd Examples/Utilities/Duration rux run ``` ```text one lap 83.4s in parts 83 s and 400000000 ns twelve laps 1000.8s in ms 1000800 limit - race -0.8s negative: true 1 h 30 min 15 s = 5415s 9223372036854775807 hours does not fit, so FromHours gave none ``` ## Common mistakes ::mistake **Using the optional as a duration.**:br`FromHours` returns `Duration?`, not `Duration`. Writing `let fromHours: Duration = Duration::FromHours(hours);` fails with: ```text error: cannot assign 'Duration?' to 'Duration' ``` Unwrap it first — with `?`, `??` or a `match`. :: ::mistake **Printing an answer that may be missing.**:br Without the `??`, `race` is a `Duration?`, and printing it fails with: ```text error: no matching overload for 'PrintLine' with argument types (char8[..], Duration?) ``` Methods are refused too: ```text type 'Duration?' has no field 'TotalMilliseconds' ``` :: ::mistake **Using `?` in a function that cannot pass `none` on.**:br`?` hands the absence to the caller, so the enclosing function must return an optional. In `Main`, which returns `int`, `Duration::FromMinutes(17)?` fails with: ```text error: '?' propagates the absence of 'Duration?', but the enclosing function returns 'int' ``` Use `??` there, or move the steps into a function like `Span`. :: ::mistake **Fractional seconds.**:br The constructors count whole units, so `Duration::FromSeconds(1.5)` fails with: ```text error: argument 1 to 'Duration::FromSeconds' has type 'float64', but parameter 'seconds' requires 'int64' ``` Pick a smaller unit instead: `Duration::FromMilliseconds(1500)`. :: ## Try it yourself 1. Print `race` with `{:.3}` and then with `{:.0}`. A precision names how many digits of the fraction to write — does it round or cut off? 2. Call `Span(0, 90, 0)`. How many seconds are 90 minutes? 3. Import `ParseDuration`, read the text `"1000.8s"`, and check with `Equals` that it is the same duration as `race`. 4. Turn the negative `margin` round with `Negated()`, which also returns `Duration?`. ## Learn more - [Optional](https://rux-lang.dev/docs/learn/optional), [Coalesce](https://rux-lang.dev/docs/learn/coalesce) and [Optional propagate](https://rux-lang.dev/docs/learn/optional-propagate) — the three tools this lesson uses on every `Duration?` - [Checked arithmetic](https://rux-lang.dev/docs/learn/checked-arithmetic) — the same idea, overflow reported instead of wrapped, on plain integers - [Stopwatch](https://rux-lang.dev/docs/learn/stopwatch) — measuring a duration with a clock - [Launch](https://rux-lang.dev/docs/learn/launch) — a checkpoint project that counts down with durations # Stopwatch ::note **You'll need**: [Duration](https://rux-lang.dev/docs/learn/duration), [Catch](https://rux-lang.dev/docs/learn/catch) :: To find out how long something takes, read a clock before it, read it again after, and subtract. The interesting question is *which* clock. This lesson uses `Instant`, a clock made for exactly this job, and shows the one way the subtraction can go wrong. Timing is also the first thing in this course whose output is different on every run. The program deals with that honestly: it prints only facts that hold every time, never the measured numbers themselves. ```rux import Time::{ Duration, Instant, SleepFor }; ``` ## Two kinds of clock A computer has two clocks, and they answer different questions. | | `Instant` (monotonic) | `Timestamp` (wall clock) | | ------------------------- | ------------------------------------------- | ----------------------------------------- | | Answers | how much time passed | what time it is | | Can go backwards | never | yes — when someone or the network sets it | | Means anything on its own | no: it counts from an origin picked at boot | yes: seconds since 1970-01-01 UTC | | Printable with `{}` | no | yes, as RFC 3339 text | The wall clock is the wrong tool for timing: if it is set back an hour in the middle of a measurement, the measurement comes out an hour short. An `Instant` only ever moves forward, so the difference between two readings is always the time that passed. You will meet `Timestamp` properly in [Date and time](https://rux-lang.dev/docs/learn/date-time). ## Elapsed time `Instant::Now()` takes a reading, and `Elapsed()` is the time from that reading until now. Here it times a 50 ms sleep: ```rux let nap = Duration::FromMilliseconds(50); let started = Instant::Now(); ``` `SleepFor` returns `! TimeError`, because the system may refuse to wait. A bare call would be an error, so the program [catches](https://rux-lang.dev/docs/learn/catch) the failure and gives up — with nothing slept, there is nothing to measure: ```rux SleepFor(nap) catch { else => { PrintLine("the system refused to sleep"); return 1; } }; let napped = started.Elapsed(); ``` A sleep lasts *at least* as long as asked, plus whatever it took the system to wake the program up again. So `napped` is a little over 50 ms, by an amount that changes every run. The program prints the fact that holds every time instead of the number: ```rux let oversleep = napped.Minus(nap) ?? Duration::Zero(); PrintLine("asked to sleep for {}", nap); PrintLine("slept at least that long: {}", !oversleep.IsNegative()); ``` ## Timing a piece of work The usual pattern is two readings around the work: ```rux let before = Instant::Now(); var sum: uint64 = 0; for i in 0..1000000 { sum += i as uint64; } let after = Instant::Now(); ``` `later.Since(earlier)` gives the `Duration` between them. It answers `Duration?`, and that is the safety catch: given the readings the wrong way round, it returns `none` rather than a huge or negative number. ```rux match after.Since(before) { took? => PrintLine("the loop took more than no time: {}", !took.IsZero()), none => PrintLine("the clock went backwards") } match before.Since(after) { took? => PrintLine("reversed: {}", took), none => PrintLine("reversed: none, because the argument was the later reading") } ``` ```mermaid flowchart LR b(["`before = Instant::Now()`"]) --> w["the work"] --> a(["`after = Instant::Now()`"]) a --> s1["`after.Since(before)`"] --> d["`Duration`"] a --> s2["`before.Since(after)`"] --> n["`none`"] ``` `start.Elapsed()` is shorthand for `Instant::Now().Since(start)` that can never be the wrong way round, which is why it returns a plain `Duration`. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Utilities/Stopwatch){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // To time something, read a clock before and after and subtract. The clock to read is `Instant`: // a monotonic clock, which only ever moves forward. The wall clock is the wrong tool, because // someone (or the network) can set it back an hour in the middle of the measurement. // // An `Instant` has no meaning on its own. It counts from an origin the system picked at boot, // so it cannot be printed as a time of day; it is only good for comparing with another reading // from the same run. `later.Since(earlier)` gives the `Duration` between two readings, and // `start.Elapsed()` is shorthand for "since start, until now". // // How long anything takes depends on the machine and on what else it is doing, so a measured // number changes from run to run. This program prints only what is true on every run: that a // sleep of 50 ms took at least 50 ms, and that readings never go backwards. import Io::PrintLine; import Time::{ Duration, Instant, SleepFor }; func Main() -> int { let nap = Duration::FromMilliseconds(50); let started = Instant::Now(); // Sleeping can fail if the system refuses to wait. Then there is nothing to measure. SleepFor(nap) catch { else => { PrintLine("the system refused to sleep"); return 1; } }; let napped = started.Elapsed(); // `napped` is a little over 50 ms, by an amount that differs every run, so compare it rather // than print it. Subtracting the request leaves the oversleep, which is never negative. let oversleep = napped.Minus(nap) ?? Duration::Zero(); PrintLine("asked to sleep for {}", nap); PrintLine("slept at least that long: {}", !oversleep.IsNegative()); // Timing some work: take a reading, do the work, take another. let before = Instant::Now(); var sum: uint64 = 0; for i in 0..1000000 { sum += i as uint64; } let after = Instant::Now(); PrintLine("sum of 0..1000000 = {}", sum); // `Since` wants the earlier reading as its argument. Asked the wrong way round it gives // `none` instead of a huge or negative duration, so a swapped pair cannot go unnoticed. match after.Since(before) { took? => PrintLine("the loop took more than no time: {}", !took.IsZero()), none => PrintLine("the clock went backwards") } match before.Since(after) { took? => PrintLine("reversed: {}", took), none => PrintLine("reversed: none, because the argument was the later reading") } return 0; } ``` Besides `Io`, its `Rux.toml` lists `Time` under `[Dependencies]`. ## Run it ```sh cd Examples/Utilities/Stopwatch rux run ``` ```text asked to sleep for 0.05s slept at least that long: true sum of 0..1000000 = 499999500000 the loop took more than no time: true reversed: none, because the argument was the later reading ``` The measured times differ on every run, so the program prints only facts about them that hold every time. Every line is the same on every run, because none of them prints a measured time. ## Common mistakes ::mistake **Printing an `Instant`.**:br An instant has no meaning outside the run that took it, so it cannot be printed at all. `PrintLine("started at {}", started)` fails with: ```text error: no matching overload for 'PrintLine' with argument types (char8[..], Instant) ``` Print the `Duration` between two instants instead. :: ::mistake **Ignoring a failed sleep.**:br Calling `SleepFor(nap);` on its own fails with: ```text error: fallible result of type '! TimeError' is discarded ``` Decide what a refused sleep means: `catch` it, as the program does, or pass it on with `?`. :: ::mistake **Treating `Since` as a duration.**:br`let took: Duration = after.Since(before);` fails with: ```text error: cannot assign 'Duration?' to 'Duration' ``` The `none` case is the swapped pair, and a `match` or `??` has to say what to do about it. :: ::mistake **Timing with the wall clock.**:br`Timestamp` has a `Since` method too, so timing with two wall-clock readings compiles and usually gives a sensible answer — until the clock is adjusted mid-measurement. Use `Instant` for anything that measures. :: ## Try it yourself 1. In the first `match`, print `took` with `{:.6}`. Run the program several times and watch the number change. 2. Change the loop to count to 10 000 000. Does the time grow by about ten times? 3. Print `oversleep` itself, in milliseconds, with `TotalMilliseconds`. How much does your system oversleep? 4. Import `Timestamp` and print `Timestamp::Now()` — the wall clock. Its text is in UTC; how far is it from your own clock? ## Learn more - [Duration](https://rux-lang.dev/docs/learn/duration) — the type every measurement here produces - [Catch](https://rux-lang.dev/docs/learn/catch) — handling the failure of `SleepFor` - [Date and time](https://rux-lang.dev/docs/learn/date-time) — the wall clock, and moments that mean something on their own - [Launch](https://rux-lang.dev/docs/learn/launch) — a checkpoint project that counts down with `SleepFor` # Date ::note **You'll need**: [Stopwatch](https://rux-lang.dev/docs/learn/stopwatch), [Outcome](https://rux-lang.dev/docs/learn/outcome), [Catch](https://rux-lang.dev/docs/learn/catch), [Variant match](https://rux-lang.dev/docs/learn/variant-match) :: A `Date` is a day on the calendar: a year, a month and a day, with no time of day and no time zone. Unlike a duration it is not just a number, because the calendar is irregular — months have 28 to 31 days, and February has a 29th only in a leap year. That irregularity is what makes dates interesting to read. The text `2023-02-29` is perfectly well-formed, and still wrong: 2023 had no 29 February. A program that reads dates has to tell those cases apart and say which one it found. ```rux import Time::{ DaysInMonth, IsLeapYear, ParseDate, TimeParseError }; ``` ## Reading a date `ParseDate` reads the ISO 8601 form `YYYY-MM-DD` and returns `Date ! TimeParseError`. A [`match`](https://rux-lang.dev/docs/learn/outcome) on the outcome handles both sides: ```rux func Show(text: char8[..]) { match ParseDate(text) { .Success(date) => PrintLine("{} ok, day {} of the year", date, date.DayOfYear()), .Failure(error) => PrintLine("{} {}, at byte {}", text, Reason(error), error.Offset()) } } ``` A `Date` prints with `{}` in the same `YYYY-MM-DD` form, and `DayOfYear` counts from 1 on 1 January — so 29 February is day 60. ## What went wrong, and where `TimeParseError` is a [variant](https://rux-lang.dev/docs/learn/variant-match): each case names a different mistake, and each carries the byte of the text where the parser found it. `Offset()` reads that byte whatever the case, and `Reason` turns the case into words: ```rux func Reason(error: TimeParseError) -> char8[..] { return match error { .InvalidSyntax(_) => "not shaped like YYYY-MM-DD", .InvalidMonth(_) => "no such month", .NonexistentDay(_) => "no such day in that month", .InvalidTime(_) => "time out of range", .ExcessiveFraction(_) => "too many fraction digits", .InvalidOffset(_) => "offset out of range" }; } ``` | Text | Case | Byte | Points at | | ------------ | ---------------- | ---- | ------------------------------------------ | | `2023-02-29` | `NonexistentDay` | 8 | the day, which February 2023 does not have | | `2024-13-01` | `InvalidMonth` | 5 | the month | | `2024/02/01` | `InvalidSyntax` | 4 | the `/` where a `-` belongs | | `2024-2-1` | `InvalidSyntax` | 6 | the `-` where a second month digit belongs | The last three cases never happen for a date alone. The whole `Time` package shares one error type — the next lesson reads times and offsets with it — so the `match` still covers them all. A program that knows the byte can do better than "invalid date": it can point at the character that is wrong. ## The leap-year rule ```mermaid flowchart LR y(["A year"]) --> d4{"Divisible by 4?"} d4 -- "no" --> c["Common year
February has 28 days"] d4 -- "yes" --> d100{"Divisible by 100?"} d100 -- "no" --> l["Leap year
February has 29 days"] d100 -- "yes" --> d400{"Divisible by 400?"} d400 -- "yes" --> l d400 -- "no" --> c ``` `IsLeapYear` applies the rule, and `DaysInMonth` uses it. The program tries one year of each kind — an ordinary year, a fourth year, and the two kinds of century: ```rux let years: int32[4] = [2023, 2024, 1900, 2000]; for year in years { PrintLine("{} leap: {}, February has {} days", year, IsLeapYear(year), DaysInMonth(year, 2)); } ``` The array is written `int32[4]` on purpose: both functions take the year as an `int32`, and an array of plain literals would be an array of `int`. ## Calendar arithmetic Date arithmetic follows the calendar, so the day after 28 February depends on the year: ```rux for text in ["2023-02-28", "2024-02-28"] { let date = ParseDate(text) catch { else => continue }; match date.PlusDays(1) { next? => PrintLine("the day after {} is {}", date, next), none => PrintLine("the day after {} is out of range", date) } } ``` `PlusDays` returns `Date?`, because a date far enough out leaves the range the package supports: years that four digits can write, up to 9999. The `catch { else => continue }` skips any text that is not a date; here both are. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Utilities/Date){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // A `Date` is a day on the calendar: a year, a month and a day, with no time and no time zone. // Unlike a duration it is not just a number, because the calendar is irregular. Months have 28 // to 31 days, and February has a 29th only in a leap year: every fourth year, except a century // year, except a century divisible by 400. So 2000 was a leap year and 1900 was not. // // That makes text such as "2023-02-29" well-formed but wrong. `ParseDate` reads the ISO 8601 // form `YYYY-MM-DD` and returns `Date ! TimeParseError`, and the error says which mistake it // was (a bad shape, a month that does not exist, a day the month does not have) and at which // byte of the text, so a program can point at the problem rather than just reject it. import Io::PrintLine; import Time::{ DaysInMonth, IsLeapYear, ParseDate, TimeParseError }; func Reason(error: TimeParseError) -> char8[..] { return match error { .InvalidSyntax(_) => "not shaped like YYYY-MM-DD", .InvalidMonth(_) => "no such month", .NonexistentDay(_) => "no such day in that month", .InvalidTime(_) => "time out of range", .ExcessiveFraction(_) => "too many fraction digits", .InvalidOffset(_) => "offset out of range" }; } func Show(text: char8[..]) { match ParseDate(text) { .Success(date) => PrintLine("{} ok, day {} of the year", date, date.DayOfYear()), .Failure(error) => PrintLine("{} {}, at byte {}", text, Reason(error), error.Offset()) } } func Main() -> int { Show("2024-02-29"); Show("2023-02-29"); Show("2024-13-01"); Show("2024/02/01"); Show("2024-2-1"); PrintLine(""); // The leap-year rule: an ordinary year, a fourth year, and the two kinds of century. let years: int32[4] = [2023, 2024, 1900, 2000]; for year in years { PrintLine("{} leap: {}, February has {} days", year, IsLeapYear(year), DaysInMonth(year, 2)); } PrintLine(""); // Date arithmetic follows the calendar, so the day after 28 February depends on the year. // `PlusDays` returns `Date?`, because a date far enough out leaves the supported range. for text in ["2023-02-28", "2024-02-28"] { let date = ParseDate(text) catch { else => continue }; match date.PlusDays(1) { next? => PrintLine("the day after {} is {}", date, next), none => PrintLine("the day after {} is out of range", date) } } return 0; } ``` Besides `Io`, its `Rux.toml` lists `Time` under `[Dependencies]`. ## Run it ```sh cd Examples/Utilities/Date rux run ``` ```text 2024-02-29 ok, day 60 of the year 2023-02-29 no such day in that month, at byte 8 2024-13-01 no such month, at byte 5 2024/02/01 not shaped like YYYY-MM-DD, at byte 4 2024-2-1 not shaped like YYYY-MM-DD, at byte 6 2023 leap: false, February has 28 days 2024 leap: true, February has 29 days 1900 leap: false, February has 28 days 2000 leap: true, February has 29 days the day after 2023-02-28 is 2023-03-01 the day after 2024-02-28 is 2024-02-29 ``` ## Common mistakes ::mistake **Leaving out an error case.**:br A `match` on `TimeParseError` must be exhaustive, even for the cases a date cannot produce. Drop the `.InvalidOffset` arm and the compiler says: ```text error: match on 'TimeParseError' is not exhaustive; missing TimeParseError::InvalidOffset ``` :: ::mistake **Using the outcome as a date.**:br`ParseDate` returns `Date ! TimeParseError`, which has no date methods. `let leap = ParseDate("2024-02-29");` followed by `leap.DayOfYear()` fails with: ```text error: type 'Date ! TimeParseError' has no field 'DayOfYear' ``` Take the date out with `match` or `catch` first. :: ::mistake **Years as plain integers.**:br`let years = [2023, 2024, 1900, 2000];` makes an array of `int`, and passing one on fails with: ```text error: argument 1 to 'IsLeapYear' has type 'int', but parameter 'year' requires 'int32' ``` Give the array its type, as the program does. :: ## Try it yourself 1. Add `Show("2100-02-29")` and `Show("2400-02-29")`. Work out the answers with the diagram before you run them. 2. Parse `2024-01-31` and call `PlusMonths(1)`. 31 February does not exist — what does the package do instead? 3. Print `DayOfWeek()` for a date you know. It counts from 0 for Sunday to 6 for Saturday. 4. Parse two dates and print how many days apart they are with `later.DaysSince(earlier)`. ## Learn more - [Outcome](https://rux-lang.dev/docs/learn/outcome) and [Catch](https://rux-lang.dev/docs/learn/catch) — the two ways the program handles `Date ! TimeParseError` - [Variant match](https://rux-lang.dev/docs/learn/variant-match) — matching the cases of a variant and their payloads - [Date and time](https://rux-lang.dev/docs/learn/date-time) — adding a time of day and an offset - [Age](https://rux-lang.dev/docs/learn/age) — a checkpoint project that counts years, months and days between two dates # Date and time ::note **You'll need**: [Date](https://rux-lang.dev/docs/learn/date), [Outcome](https://rux-lang.dev/docs/learn/outcome), [Coalesce](https://rux-lang.dev/docs/learn/coalesce) :: A date and a time of day together make a `DateTime`, such as 2026-10-04T09:30:00. It looks like a moment, but it is not one yet: 09:30 in Kyiv and 09:30 in New York are seven hours apart. What it lacks is an **offset** — how far the local clock was ahead of or behind UTC, the world's reference clock. This lesson adds the offset, writes the result in RFC 3339 — the date-and-time format of logs, JSON and HTTP — and shows how to tell whether two texts name the same moment. ```rux import Time::{ DateTime, OffsetDateTime, ParseDateTime, ParseRfc3339, UtcOffset }; ``` ## Four types for four questions | Type | Holds | Example | Is it one moment? | | ---------------- | ------------------------------ | --------------------------- | --------------------------- | | `Date` | year, month, day | `2026-10-04` | no — a whole day, somewhere | | `DateTime` | a date and a time of day | `2026-10-04T09:30:00` | no — 09:30 where? | | `OffsetDateTime` | a `DateTime` and a `UtcOffset` | `2026-10-04T09:30:00+03:00` | yes | | `Timestamp` | seconds since 1970-01-01 UTC | `1791095400` | yes, with one spelling | ## A local date and time `ParseDateTime` reads a date, a `T` and a time. Like `ParseDate` in the [previous lesson](https://rux-lang.dev/docs/learn/date), it returns an outcome with a `TimeParseError`, and here a [`catch`](https://rux-lang.dev/docs/learn/catch) ends the program if the text is not a date and time: ```rux let meeting = ParseDateTime("2026-10-04T09:30:00") catch { else => { PrintLine("not a date and time"); return 1; } }; PrintLine("local {}", meeting); ``` There is no offset in the text and none in the value: it prints back as `2026-10-04T09:30:00`. ## Adding an offset `OffsetDateTime(dateTime, offset)` pairs a reading with the offset it was taken in. `UtcOffset::Of(hours, minutes)` makes the offset, and returns `UtcOffset?` because not every pair is one — no clock is 30 hours ahead of UTC: ```rux let kyiv = OffsetDateTime(meeting, UtcOffset::Of(3, 0) ?? UtcOffset::Utc()); let newYork = OffsetDateTime(meeting, UtcOffset::Of(-4, 0) ?? UtcOffset::Utc()); ``` They print as `2026-10-04T09:30:00+03:00` and `2026-10-04T09:30:00-04:00`: the same clock reading, in two places, so two different moments. To measure between moments, turn each into a `Timestamp` with `ToTimestamp()`. A timestamp counts seconds since the start of 1970 in UTC, so it has no offset left to disagree about: ```rux let apart = newYork.ToTimestamp().UnixSeconds() - kyiv.ToTimestamp().UnixSeconds(); PrintLine("apart by {} s", apart); ``` New York is seven hours behind Kyiv, so its 09:30 comes 25 200 seconds later. ```mermaid flowchart LR dt["`DateTime`
`09:30:00`"] --> odt["`OffsetDateTime`
`09:30:00+03:00`"] off["`UtcOffset`
`+03:00`"] --> odt odt -- "`ToTimestamp()`" --> ts["`Timestamp`
one moment, in UTC"] ts -- "`DateTime::FromTimestamp(ts, offset)`" --> local["`DateTime`
the reading at another offset"] ``` ## RFC 3339 RFC 3339 is an `OffsetDateTime` written as text: the date, a `T`, the time, and then either `Z` for UTC or a signed `+HH:MM`. `ParseRfc3339` reads it and returns `OffsetDateTime ! TimeParseError`; printing an `OffsetDateTime` with `{}` writes it back. This text is the Kyiv meeting again, written in UTC — different text, same moment: ```rux match ParseRfc3339("2026-10-04T06:30:00Z") { .Success(utc) => { PrintLine("parsed {}", utc); let same = utc.ToTimestamp().UnixSeconds() == kyiv.ToTimestamp().UnixSeconds(); PrintLine("same moment as the Kyiv meeting: {}", same); // Converting the moment to another offset gives the local reading there. let tokyo = UtcOffset::Of(9, 0) ?? UtcOffset::Utc(); let there = DateTime::FromTimestamp(utc.ToTimestamp(), tokyo); PrintLine("in Tokyo {}", OffsetDateTime(there, tokyo)); }, .Failure(error) => PrintLine("rejected at byte {}", error.Offset()) } ``` The comparison is between timestamps, which have one spelling per moment, so `same` is `true`. Going the other way, `DateTime::FromTimestamp` takes a moment and an offset and gives the local reading there: the meeting is at 15:30 in Tokyo. RFC 3339 requires the offset. Without it the text is only a local reading, so `ParseRfc3339("2026-10-04T09:30:00")` is refused at byte 19 — the end of the text, where the offset should start. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Utilities/DateTime){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // A date and a time of day together make a `DateTime`, such as 2026-10-04T09:30:00. On its own // that is not yet a moment: 09:30 in Kyiv and 09:30 in New York are seven hours apart. What it // lacks is an offset, how far the clock was ahead of or behind UTC, the world's reference clock. // // `OffsetDateTime` is a `DateTime` plus a `UtcOffset`, and that is enough to name one moment. Its // text form is RFC 3339, the format of logs, JSON and HTTP: the date, a `T`, the time, then `Z` // for UTC or a signed `+HH:MM`. `ParseRfc3339` reads it and returns // `OffsetDateTime ! TimeParseError`, and printing an `OffsetDateTime` with `{}` writes it back. // // Two texts can name the same moment in different offsets. To compare moments, turn each into a // `Timestamp`, a count of seconds since 1970-01-01 in UTC, which has one spelling per moment. import Io::PrintLine; import Time::{ DateTime, OffsetDateTime, ParseDateTime, ParseRfc3339, UtcOffset }; func Main() -> int { // A local date and time. There is no offset in it, and none in its text either. let meeting = ParseDateTime("2026-10-04T09:30:00") catch { else => { PrintLine("not a date and time"); return 1; } }; PrintLine("local {}", meeting); // The same reading in two places. `UtcOffset::Of` returns `UtcOffset?`, since 30 hours ahead // is not an offset any clock can have. let kyiv = OffsetDateTime(meeting, UtcOffset::Of(3, 0) ?? UtcOffset::Utc()); let newYork = OffsetDateTime(meeting, UtcOffset::Of(-4, 0) ?? UtcOffset::Utc()); PrintLine("in Kyiv {}", kyiv); PrintLine("in New York {}", newYork); // Two different moments, 7 hours (25200 seconds) apart. let apart = newYork.ToTimestamp().UnixSeconds() - kyiv.ToTimestamp().UnixSeconds(); PrintLine("apart by {} s", apart); // RFC 3339 from text. This one is the Kyiv meeting written in UTC: other text, same moment. match ParseRfc3339("2026-10-04T06:30:00Z") { .Success(utc) => { PrintLine("parsed {}", utc); let same = utc.ToTimestamp().UnixSeconds() == kyiv.ToTimestamp().UnixSeconds(); PrintLine("same moment as the Kyiv meeting: {}", same); // Converting the moment to another offset gives the local reading there. let tokyo = UtcOffset::Of(9, 0) ?? UtcOffset::Utc(); let there = DateTime::FromTimestamp(utc.ToTimestamp(), tokyo); PrintLine("in Tokyo {}", OffsetDateTime(there, tokyo)); }, .Failure(error) => PrintLine("rejected at byte {}", error.Offset()) } // RFC 3339 requires the offset. Without it, the text stops being a moment. match ParseRfc3339("2026-10-04T09:30:00") { .Success(moment) => PrintLine("parsed {}", moment), .Failure(error) => PrintLine("no offset rejected at byte {}", error.Offset()) } return 0; } ``` Besides `Io`, its `Rux.toml` lists `Time` under `[Dependencies]`. ## Run it ```sh cd Examples/Utilities/DateTime rux run ``` ```text local 2026-10-04T09:30:00 in Kyiv 2026-10-04T09:30:00+03:00 in New York 2026-10-04T09:30:00-04:00 apart by 25200 s parsed 2026-10-04T06:30:00Z same moment as the Kyiv meeting: true in Tokyo 2026-10-04T15:30:00+09:00 no offset rejected at byte 19 ``` ## Common mistakes ::mistake **Passing the optional offset straight in.**:br`UtcOffset::Of` returns `UtcOffset?`. Writing `OffsetDateTime(meeting, UtcOffset::Of(3, 0))` fails with: ```text error: argument 2 to 'OffsetDateTime' has type 'UtcOffset?', but parameter 'offset' requires 'UtcOffset' ``` Supply a fallback with `??`, or `match` the `none`. :: ::mistake **Comparing moments with `==`.**:br`utc == kyiv` compiles, and is `false`. It compares the two values field by field — the clock reading and the offset — and those differ even though the moment is the same. Compare their timestamps instead. :: ::mistake **Offsets with mixed signs.**:br Both parts of an offset carry its sign, so −03:30 is `UtcOffset::Of(-3, -30)`. `UtcOffset::Of(-3, 30)` is `none`, and behind a `?? UtcOffset::Utc()` fallback that quietly becomes UTC. :: ::mistake **RFC 3339 text without an offset.**:br`ParseRfc3339` refuses it. If the text really is a local reading, read it with `ParseDateTime`, and decide which offset it is in yourself. :: ## Try it yourself 1. Add a line for Mumbai, five and a half hours ahead of UTC: `UtcOffset::Of(5, 30)`. 2. Parse `2026-10-04T09:30:00.250+03:00`. Is it the same moment as `kyiv`? How does it print? 3. Import `Timestamp`, then print the current time in Kyiv: `DateTime::FromTimestamp(Timestamp::Now(), offset)` paired with that offset. 4. Change the Kyiv offset to `UtcOffset::Of(30, 0)`. What does the program print, and why is a fallback to UTC risky in a real program? ## Learn more - [Date](https://rux-lang.dev/docs/learn/date) — the calendar half of a `DateTime`, and `TimeParseError` - [Coalesce](https://rux-lang.dev/docs/learn/coalesce) — the `??` that supplies each offset's fallback - [Structural equality](https://rux-lang.dev/docs/learn/structural-equality) — what `==` compares on a struct - [Stopwatch](https://rux-lang.dev/docs/learn/stopwatch) — why measuring time uses a different clock from this one # Random ::note **You'll need**: [Mutable reference](https://rux-lang.dev/docs/learn/mutable-reference), [Copy](https://rux-lang.dev/docs/learn/copy), [Generic](https://rux-lang.dev/docs/learn/generic), [Format](https://rux-lang.dev/docs/learn/format) :: Arithmetic alone cannot produce randomness. What a random number generator produces is a sequence that *looks* random but follows entirely from where it started — its **seed**. Give it the same seed and you get the same numbers, in the same order, on every machine and every run. That sounds like a weakness, and it is the opposite. A simulation can be rerun exactly, a test that draws random data can be repeated, and a bug that only showed up for one particular draw can be reproduced — all by remembering one number. The program imports the `Random` package's general-purpose generator and one way of drawing from it: ```rux import Random::{ Pcg64Dxsm, UniformBelow }; ``` ## A generator is a struct `Pcg64Dxsm(seed)` builds a generator. It is an ordinary [struct](https://rux-lang.dev/docs/learn/struct) whose fields are its state, and every draw advances that state. `UniformBelow(generator, bound)` draws a number from 0 up to, but not including, `bound` — so `100` gives 0 to 99: ```rux func Draw(label: char8[..], generator: &var Pcg64Dxsm) { Print("{}", label); for i in 0..6 { Print(" {:2}", UniformBelow(generator, 100)); } PrintLine(); } ``` Because a draw changes the generator, `Draw` takes it as a [mutable reference](https://rux-lang.dev/docs/learn/mutable-reference), `&var Pcg64Dxsm`: the six draws advance the caller's generator, not a copy of it. The `{:2}` pads each number to two columns, as in [Format](https://rux-lang.dev/docs/learn/format). `UniformBelow` is [generic](https://rux-lang.dev/docs/learn/generic) over any generator, which is why the call names the type in angle brackets. The compiler can also work it out from the argument; the program spells it out so you can see which generator is drawing. ## Same seed, same numbers ```rux var first = Pcg64Dxsm(2026); Draw("seed 2026 ", first); var second = Pcg64Dxsm(2026); Draw("seed 2026 again", second); var other = Pcg64Dxsm(2027); Draw("seed 2027 ", other); ``` The first two lines of output are identical: `23 73 75 87 37 28`, twice. The third has nothing in common with them, even though 2027 is right next to 2026 — a seed is a label for a sequence, not a starting value that nearby seeds start close to. ## Drawing continues Calling `Draw` on `first` again does not start over. It carries on from where the first six draws left the state, and gives six new numbers. ## A copy replays the future Copying a generator copies its state, as [copying](https://rux-lang.dev/docs/learn/copy) any struct copies its fields. The copy then produces exactly what the original is about to produce: ```rux var copy = first; Draw("2026 continued ", first); Draw("its copy ", copy); ``` ```mermaid flowchart LR seed(["seed `2026`"]) --> s0["state after
12 draws"] s0 -- "`var copy = first`" --> c["`copy`:
same state"] s0 -- "`Draw(first)`" --> f["`16 12 33 48 2 29`"] c -- "`Draw(copy)`" --> g["`16 12 33 48 2 29`"] ``` That is useful on purpose — saving a generator and rewinding to it — and a trap by accident, when two parts of a program each hold a copy and draw "different" numbers that are the same. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Utilities/Random){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // Arithmetic alone cannot produce randomness. What a random number generator produces is a // sequence that *looks* random but follows entirely from where it started, its seed. Give it // the same seed and you get the same numbers, in the same order, on every machine, every run. // // That is a feature. A simulation can be rerun exactly, a test that draws random data can be // repeated, and a bug that depended on the draw can be reproduced, all by remembering one number. // // The Random package's general-purpose generator is `Pcg64Dxsm`. `Pcg64Dxsm(seed)` builds one, // and `UniformBelow(generator, bound)` draws a number from 0 up to, not including, // `bound`. The generator is an ordinary struct whose fields are its state: each draw advances // it, which is why it is passed as `&var`. And like any struct, copying it copies the state, // so a copy replays exactly what the original is about to produce. import Io::{ Print, PrintLine }; import Random::{ Pcg64Dxsm, UniformBelow }; func Draw(label: char8[..], generator: &var Pcg64Dxsm) { Print("{}", label); for i in 0..6 { Print(" {:2}", UniformBelow(generator, 100)); } PrintLine(); } func Main() -> int { var first = Pcg64Dxsm(2026); Draw("seed 2026 ", first); // A second generator from the same seed: the same run, exactly. var second = Pcg64Dxsm(2026); Draw("seed 2026 again", second); // A neighbouring seed gives an unrelated run. Seeds are labels, not starting values. var other = Pcg64Dxsm(2027); Draw("seed 2027 ", other); // Drawing again continues where the generator stopped; it does not start over. Draw("2026 continued ", first); // A copy holds the same state, so it produces the same next numbers as the original. var copy = first; Draw("2026 continued ", first); Draw("its copy ", copy); return 0; } ``` Besides `Io`, its `Rux.toml` lists `Random` under `[Dependencies]`. ## Run it ```sh cd Examples/Utilities/Random rux run ``` ```text seed 2026 23 73 75 87 37 28 seed 2026 again 23 73 75 87 37 28 seed 2027 73 1 34 5 0 38 2026 continued 67 36 72 16 94 29 2026 continued 16 12 33 48 2 29 its copy 16 12 33 48 2 29 ``` ## Common mistakes ::mistake **A generator declared with `let`.**:br Every draw changes the generator, so it must be mutable. With `let first = Pcg64Dxsm(2026);` the call `Draw("seed 2026 ", first)` fails, and the help says what to do: ```text error: argument 2 to 'Draw' cannot borrow immutable 'first' as '&var Pcg64Dxsm' declare 'first' with 'var' to make it mutable ``` :: ::mistake **Taking the generator by value.**:br Declare the parameter as `generator: Pcg64Dxsm` and the draw inside fails with: ```text error: argument 1 to 'UniformBelow' cannot borrow immutable 'generator' as '&var Pcg64Dxsm' ``` Even if the function copied it into a `var` local, every call would draw from a copy, and the caller's generator would never move on. Pass it as `&var`. :: ::mistake **Seeding again for every draw.**:br A function that builds `Pcg64Dxsm(2026)` each time it is called returns the same numbers on every call. Make one generator, seed it once, and pass it to everything that draws. :: ## Try it yourself 1. Change the seed to your birth year. Do the first two lines still match each other? 2. `Pcg64Dxsm::WithStream(2026, 1)` builds a generator with the same seed on a different *stream*. Draw from it and compare with `seed 2026`. 3. Import `Xoshiro256`, a second generator, and draw from `Xoshiro256(2026)` with `UniformBelow`. Same seed, different generator — same numbers? 4. Import `Bernoulli` and flip ten coins with `Bernoulli(generator, 0.5)`, which returns a `bool`. ## Learn more - [Distribution](https://rux-lang.dev/docs/learn/distribution) — shaping raw draws into dice, shuffles and bell curves - [Entropy](https://rux-lang.dev/docs/learn/entropy) — seeds that nobody can guess - [Mutable reference](https://rux-lang.dev/docs/learn/mutable-reference) and [Copy](https://rux-lang.dev/docs/learn/copy) — the two ideas that explain how a generator behaves - [Generic](https://rux-lang.dev/docs/learn/generic) — why `UniformBelow` works with any generator # Distribution ::note **You'll need**: [Random](https://rux-lang.dev/docs/learn/random), [Writable slice](https://rux-lang.dev/docs/learn/writable-slice), [Format number](https://rux-lang.dev/docs/learn/format-number) :: A generator hands out raw 64-bit numbers. What a program wants is almost never that: it wants a die roll from 1 to 6, a deck in a random order, or a height that is usually near the average and only rarely far from it. A **distribution** turns raw numbers into those values, and decides how likely each one is. Each of these is easy to get subtly wrong by hand, and the mistakes do not show in a quick test. The `Random` package has exact versions, and this lesson tours three of them: ```rux import Random::{ NormalWith, Pcg64Dxsm, Shuffle, UniformInRange }; ``` The generator has a fixed seed, `Pcg64Dxsm(7)`, so — as in [Random](https://rux-lang.dev/docs/learn/random) — every run prints the same results. ## Uniform: every value equally likely `UniformInRange(generator, low, high)` makes every value from `low` to `high` equally likely, **both ends included**. A die is therefore `1, 6`: ```rux var faces: uint[6] = [0; 6]; for i in 0..6000 { let face = UniformInRange(generator, 1, 6); faces[face - 1] += 1; } ``` Six thousand rolls land close to 1000 per face — `1013 956 939 1048 1026 1018` — and never exactly. That is what fair looks like: equally likely is not equally often. Why not take a raw number and write `raw % 6`? Because 2⁶⁴ is not a multiple of 6. The raw numbers split into six groups that are almost, but not quite, the same size, and the low faces come up very slightly more often. `UniformInRange` corrects for that; `%` does not. | Function | Draws | Ends | | ----------------------------------- | -------------------------------- | ---------------- | | `UniformBelow(g, bound)` | `0` to `bound - 1` | `bound` excluded | | `UniformInRange(g, low, high)` | `low` to `high` | both included | | `UniformFloatInRange(g, low, high)` | a `float64` from `low` to `high` | `high` excluded | ## Shuffle: every order equally likely `Shuffle` puts a slice in a random order, in place, where every one of the possible arrangements is equally likely: ```rux var cards: char8[..][8] = ["A", "2", "3", "4", "5", "6", "7", "8"]; Shuffle(generator, cards[..]); ``` The cards are rearranged where they are, so `Shuffle` needs a [writable slice](https://rux-lang.dev/docs/learn/writable-slice) of them: `cards` is a `var` array and `cards[..]` views all of it. The second type argument, `char8[..]`, is the type of one element. The tempting home-made shuffle — swap each position with a random one anywhere in the slice — does not make every order equally likely: some arrangements come up more often than others. `Shuffle` uses Fisher and Yates' method, which swaps each position only with one at or before it, and is exactly uniform. ## Normal: the bell curve Many measured quantities — heights, errors, reaction times — cluster around an average and thin out on either side. `NormalWith(generator, mean, deviation)` draws from that bell curve. About 68% of its values fall within one deviation of the mean: ```rux let draws = 10000; var total = 0.0; var withinOne = 0; for i in 0..draws { let height = NormalWith(generator, 170.0, 10.0); total += height; if height >= 160.0 && height <= 180.0 { withinOne += 1; } } ``` The average of ten thousand draws is `170.1` — close to the mean of 170, not equal to it — and `68.3%` of them land between 160 and 180. `{:.1}` prints both to one decimal place, as in [Format number](https://rux-lang.dev/docs/learn/format-number). ```mermaid flowchart LR g(["`Pcg64Dxsm`
raw 64-bit numbers"]) --> u["`UniformInRange`
`1, 2, 3, 4, 5, 6` —
all equally likely"] g --> s["`Shuffle`
every order
equally likely"] g --> n["`NormalWith`
near the mean likely,
far from it rare"] ``` ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Utilities/Distribution){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // A generator hands out raw 64-bit numbers. A distribution turns them into the numbers a program // actually wants, and decides how likely each one is. // // `UniformInRange(generator, low, high)` makes every value from `low` to `high` equally likely, // both ends included, so a die is `1, 6`. `Shuffle` puts a slice in a random order in which // every arrangement is equally likely. `NormalWith(generator, mean, deviation)` draws from the // bell curve: values cluster around the mean, about 68% of them within one deviation of it. // // Each of these is easy to get subtly wrong by hand. `raw % 6` favours the low faces a little, // and swapping random pairs a few times does not make every order equally likely. The library // versions are exact, so use them. The generator here has a fixed seed, so every run prints // the same results. import Io::{ Print, PrintLine }; import Random::{ NormalWith, Pcg64Dxsm, Shuffle, UniformInRange }; func Main() -> int { var generator = Pcg64Dxsm(7); // Uniform: 6000 rolls of a die land close to 1000 per face, never exactly. var faces: uint[6] = [0; 6]; for i in 0..6000 { let face = UniformInRange(generator, 1, 6); faces[face - 1] += 1; } Print("6000 die rolls "); for count in faces { Print(" {}", count); } PrintLine(); // Shuffle: the slice is rearranged in place, so it needs a writable view. var cards: char8[..][8] = ["A", "2", "3", "4", "5", "6", "7", "8"]; Shuffle(generator, cards[..]); Print("shuffled cards "); for card in cards { Print(" {}", card); } PrintLine(); // Normal: heights with a mean of 170 cm and a deviation of 10 cm. let draws = 10000; var total = 0.0; var withinOne = 0; for i in 0..draws { let height = NormalWith(generator, 170.0, 10.0); total += height; if height >= 160.0 && height <= 180.0 { withinOne += 1; } } PrintLine("average height {:.1} cm", total / (draws as float64)); PrintLine("within 160..180 {:.1}%", (withinOne as float64) * 100.0 / (draws as float64)); return 0; } ``` Besides `Io`, its `Rux.toml` lists `Random` under `[Dependencies]`. ## Run it ```sh cd Examples/Utilities/Distribution rux run ``` ```text 6000 die rolls 1013 956 939 1048 1026 1018 shuffled cards 2 7 3 8 4 A 6 5 average height 170.1 cm within 160..180 68.3% ``` ## Common mistakes ::mistake **Forgetting that both ends are included.**:br`UniformInRange(generator, 1, 6)` can return 6. Counting into `faces[face]` instead of `faces[face - 1]` compiles, and then, the first time a 6 is rolled, stops the program with: ```text Panic: index out of range ``` :: ::mistake **Shuffling something that cannot change.**:br Declare the array with `let` and the call fails with: ```text error: argument 2 to 'Shuffle' has type 'char8[..][..]', but parameter 'items' requires 'var char8[..][..]' ``` Passing the array itself rather than a slice of it fails too: ```text error: no matching overload for 'Shuffle' ``` Shuffle `cards[..]` of a `var` array. :: ::mistake **Whole numbers for a float distribution.**:br`NormalWith` takes `float64` arguments, and an integer literal is not converted on its own: `NormalWith(generator, 170, 10)` fails with: ```text error: argument 2 to 'NormalWith' has type 'int', but parameter 'mean' requires 'float64' ``` Write `170.0` and `10.0`. :: ## Try it yourself 1. Roll two dice 6000 times and count each total from 2 to 12. Which total is most common, and why is this not a uniform distribution? 2. Import `UniformFloatInRange` and draw ten temperatures between −5.0 and 25.0. 3. Import `WeightedIndex` and make a loaded die: weights `[1.0, 1.0, 1.0, 1.0, 1.0, 5.0]` as a `float64` slice. How often does the last face come up now? 4. Change the deviation to 5.0. What share of heights land between 160 and 180 now? ## Learn more - [Random](https://rux-lang.dev/docs/learn/random) — the generator these functions draw from - [Writable slice](https://rux-lang.dev/docs/learn/writable-slice) — the `var T[..]` that `Shuffle` rearranges - [Format number](https://rux-lang.dev/docs/learn/format-number) — the `{:.1}` used for the results - [Guess](https://rux-lang.dev/docs/learn/guess) — a checkpoint project that picks its secret number with `UniformInRange` # Entropy ::note **You'll need**: [Distribution](https://rux-lang.dev/docs/learn/distribution), [Catch](https://rux-lang.dev/docs/learn/catch), [Enum](https://rux-lang.dev/docs/learn/enum), [Pointer](https://rux-lang.dev/docs/learn/pointer) :: A seeded generator is predictable by design: anyone who learns the seed can replay every number it will ever produce. For a simulation that is a feature. For a session token, a password salt or an encryption key it is a disaster — those numbers must be ones nobody can guess, so they cannot come from arithmetic inside the program. They come from outside it. The operating system collects unpredictability — **entropy** — from hardware and from the timing of events, and the `Entropy` package asks it for some: ```rux import Entropy::{ EntropyError, Fill, NextUint64 }; import Random::{ Pcg64Dxsm, PcgFromEntropy, UniformBelow }; ``` The output is different on every run, and that is exactly what this lesson is about. ## Every request can fail Asking the system can fail: it may have no source, the request may be interrupted, or the system may simply refuse. So every function here is fallible, with an `EntropyError` [enum](https://rux-lang.dev/docs/learn/enum) saying why: | Function | Returns | Gives you | | ------------------ | -------------------------- | -------------------------------------------- | | `NextUint64()` | `uint64 ! EntropyError` | one unpredictable 64-bit number | | `Fill(buffer, n)` | `! EntropyError` | `n` unpredictable bytes, written to `buffer` | | `PcgFromEntropy()` | `Pcg64Dxsm ! EntropyError` | a generator with an unguessable seed | The whole point of these numbers is that nobody can guess them. A failure quietly replaced by some fixed value — a `catch` that answers `0` — would produce a "random" key that is the same on every machine. So the program checks every call and stops if one fails. `Describe` turns the reason into words, and `IsTransient` says whether asking again might help: ```rux func Describe(error: EntropyError) { let why = match error { EntropyError::Unsupported => "this system has no entropy source", EntropyError::Interrupted => "the request was interrupted", EntropyError::Failed => "the system refused", EntropyError::TooLarge => "too many bytes in one request" }; // `IsTransient` says whether asking again might help. Only an interruption is worth a retry. PrintLine("no entropy: {} (worth retrying: {})", why, error.IsTransient()); } ``` ## One number `NextUint64` is the simplest request. A `match` on its outcome prints the value, or describes the failure and ends the program with status 1: ```rux match NextUint64() { .Success(value) => PrintLine("a 64-bit value {:#018x}", value), .Failure(error) => { Describe(error); return 1; } } ``` `{:#018x}` prints it in hexadecimal with a `0x` prefix, padded with zeros to 18 characters — the prefix and all 16 digits. ## A buffer of bytes A key is usually a run of bytes rather than one number. `Fill` writes as many bytes as you ask for into memory you provide, so it takes a [pointer](https://rux-lang.dev/docs/learn/pointer) to the first byte and a count: ```rux var key: byte[16] = [0; 16]; Fill(@key[0] as *var opaque, 16) catch { error => { Describe(error); return 1; } }; ``` `@key[0]` is the address of the first byte. `Fill` takes the buffer as `*var opaque` — a writable pointer to bytes of any type — because it neither knows nor cares what the bytes will be used for. It also cannot see how big the buffer is: the count you pass is all it has, so it must match the array. The [`catch`](https://rux-lang.dev/docs/learn/catch) here names the error, `error => { … }`, so the arm can pass it to `Describe`. ## The common use: an unguessable seed Every request for entropy is a call into the operating system, while a generator makes a number in a few instructions — and a program rarely needs all its numbers to be unguessable. The usual pattern takes a little entropy once, as a seed, and then draws from a fast generator as in [Distribution](https://rux-lang.dev/docs/learn/distribution): ```rux var generator = PcgFromEntropy() catch { error => { Describe(error); return 1; } }; PrintLine("a die roll {}", UniformBelow(generator, 6) + 1); ``` ```mermaid flowchart LR os(["Operating system
hardware and timing"]) -- "`NextUint64`, `Fill`" --> v["Unguessable values:
keys, tokens, salts"] os -- "`PcgFromEntropy`" --> g["`Pcg64Dxsm` with an
unguessable seed"] g -- "`UniformBelow`, `Shuffle`, …" --> d["Fast draws that
differ every run"] ``` Every run now rolls differently — and the program has given up the ability to replay a run, because nobody knows the seed. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Utilities/Entropy){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // A seeded generator is predictable by design: anyone who learns the seed can replay it. When // the numbers must be unguessable, such as a session token, a password salt, or the seed for a // simulation that should differ every run, they have to come from outside the program. // // The operating system collects unpredictability from hardware and timing, and the Entropy // package asks it for some. `NextUint64()` returns `uint64 ! EntropyError` and `Fill` fills a // buffer, returning `! EntropyError`. Asking can fail (a system may have no source, or the // request may be interrupted), and since the whole point is that the bytes are unguessable, a // failure must never be quietly replaced by some fixed value. So every call here is checked. // // The output is different on every run, which is exactly what this lesson is about. import Entropy::{ EntropyError, Fill, NextUint64 }; import Io::{ Print, PrintLine }; import Random::{ Pcg64Dxsm, PcgFromEntropy, UniformBelow }; func Describe(error: EntropyError) { let why = match error { EntropyError::Unsupported => "this system has no entropy source", EntropyError::Interrupted => "the request was interrupted", EntropyError::Failed => "the system refused", EntropyError::TooLarge => "too many bytes in one request" }; // `IsTransient` says whether asking again might help. Only an interruption is worth a retry. PrintLine("no entropy: {} (worth retrying: {})", why, error.IsTransient()); } func Main() -> int { // One unpredictable 64-bit number. match NextUint64() { .Success(value) => PrintLine("a 64-bit value {:#018x}", value), .Failure(error) => { Describe(error); return 1; } } // Sixteen unpredictable bytes, written into a buffer through a pointer. var key: byte[16] = [0; 16]; Fill(@key[0] as *var opaque, 16) catch { error => { Describe(error); return 1; } }; Print("a 16-byte key "); for b in key { Print(" {:02x}", b); } PrintLine(); // The common use: seed a fast generator once from entropy, then draw from it as usual. // `PcgFromEntropy` returns `Pcg64Dxsm ! EntropyError`, so the seeding is checked too. var generator = PcgFromEntropy() catch { error => { Describe(error); return 1; } }; PrintLine("a die roll {}", UniformBelow(generator, 6) + 1); return 0; } ``` Besides `Io`, its `Rux.toml` lists `Entropy` and `Random` under `[Dependencies]`. ## Run it ```sh cd Examples/Utilities/Entropy rux run ``` ```text a 64-bit value 0x0739b89787c9e4f2 a 16-byte key 2f ec 37 79 c3 31 0e 0f ba 9a a0 34 15 17 b9 b7 a die roll 6 ``` This is a sample: every value is different on each run. This is a sample: every value is different on each run, and so is the die roll. ## Common mistakes ::mistake **Using the outcome as the number.**:br`NextUint64` returns `uint64 ! EntropyError`. Writing `let raw: uint64 = NextUint64();` fails with: ```text error: cannot assign 'uint64 ! EntropyError' to 'uint64' ``` Handle the failure first. :: ::mistake **Passing the array instead of its address.**:br`Fill(key, 16)` fails with: ```text error: argument 1 to 'Fill' has type 'uint8[16]', but parameter 'buffer' requires '*var opaque' ``` Pass the address of the first byte: `@key[0]`. :: ::mistake **Covering a failure with a fixed value.**:br A `catch` that answers a constant compiles, and turns a missing entropy source into a key everyone knows. When unpredictability is the point, stop, retry if `IsTransient()` says it may help, or report the failure — never invent the bytes. :: ::mistake **A seeded generator where secrets are needed.**:br`Pcg64Dxsm` is fast and good for simulations, but it is not designed to resist someone who is trying to predict it, even with an unguessable seed. Draw passwords, tokens and keys straight from `Fill` or `NextUint64`, as the [Password](https://rux-lang.dev/docs/learn/password) project does. :: ## Try it yourself 1. Run the program three times. Which lines change? 2. Make the key 32 bytes long. What else has to change besides the array's size? 3. Replace `PcgFromEntropy()` with `Pcg64Dxsm(2026)` (no `catch` needed — it cannot fail) and run twice. What happens to the die roll? 4. Leave out one arm of the `match` in `Describe` and read the compiler's message. ## Learn more - [Random](https://rux-lang.dev/docs/learn/random) and [Distribution](https://rux-lang.dev/docs/learn/distribution) — the generator that `PcgFromEntropy` seeds - [Pointer](https://rux-lang.dev/docs/learn/pointer) — the address `Fill` writes through - [Catch](https://rux-lang.dev/docs/learn/catch) — recovering from a failure, and naming it with `error =>` - [Password](https://rux-lang.dev/docs/learn/password) — a checkpoint project that builds a password from entropy - [UUID](https://rux-lang.dev/docs/learn/uuid) — random identifiers made from the same source # Hash ::note **You'll need**: [Pointer](https://rux-lang.dev/docs/learn/pointer), [String literal](https://rux-lang.dev/docs/learn/string-literal), [Format number](https://rux-lang.dev/docs/learn/format-number) :: A **hash function** boils any amount of data down to one fixed-size number. The same bytes always give the same number, on every machine and every run, while bytes that differ even slightly almost always give a different one. That makes a hash a cheap fingerprint. A [hash map](https://rux-lang.dev/docs/learn/hash-map) files its keys by their hashes; a download site prints a checksum next to each file so you can tell whether your copy arrived intact; a program stores a hash beside its cache to notice when the data under it has changed. This lesson tours the `Hash` package's fast, everyday hashes: ```rux import Hash::{ Crc32Of, Fnv1a64, Fnv1a64Of, XxHash64Of }; ``` ## Three algorithms Each `…Of` function takes a pointer to the bytes and their count, and returns the hash in one call: | Function | Algorithm | Size | Good for | | ------------ | --------- | ------- | ---------------------------------------- | | `Fnv1a64Of` | FNV-1a | 64 bits | tiny and fast; short keys in hash tables | | `XxHash64Of` | xxHash | 64 bits | very fast on long inputs; fingerprints | | `Crc32Of` | CRC-32 | 32 bits | the checksum in ZIP, PNG and Ethernet | They work on **bytes**, not on text, so `Show` takes the address of the string's first character as a byte pointer: ```rux func Show(text: char8[..]) { let bytes = text.data as *byte; PrintLine("{:<12} fnv1a64 {:016x} xxhash64 {:016x} crc32 {:08x}", text, Fnv1a64Of(bytes, text.length), XxHash64Of(bytes, text.length), Crc32Of(bytes, text.length)); } ``` A [string literal](https://rux-lang.dev/docs/learn/string-literal) is a `char8[..]`: `text.data` points at its first character and `text.length` counts its bytes. `as *byte` reads the same memory as plain bytes, which is what the hash functions take. `{:016x}` prints the hash in hexadecimal padded to 16 digits, and `{:08x}` to 8, as in [Format number](https://rux-lang.dev/docs/learn/format-number) — the 64-bit and 32-bit sizes written out in full. ## Same bytes, same hash; one byte changed, a different hash ```rux Show("hello world"); Show("hello world"); Show("hello worle"); Show(""); ``` The first two lines are identical, as they must be. The third changes one letter, and every hash changes with it. xxHash and CRC-32 change throughout: `45ab6734b21e6968` becomes `06a208d921a7827a`. FNV-1a is simpler, and a change in the *last* byte leaves much of its old value standing — `779a65e7023cd2e7` against `779a64e7023cd134`. That is fine for a hash map, which only needs keys spread out, and a reason to prefer xxHash for fingerprints. Even no bytes at all have a hash. For FNV-1a it is the algorithm's starting value, `cbf29ce484222325`, and for CRC-32 it is zero. ## Hashing in pieces Data often arrives in pieces — read from a file a block at a time, or sent over a network. Each algorithm also has a **hasher** struct for that: make one, `Write` each piece, then `Finish`: ```rux let first = "hello "; let second = "world"; var hasher = Fnv1a64(); hasher.Write(first.data as *byte, first.length); hasher.Write(second.data as *byte, second.length); PrintLine("in two pieces fnv1a64 {:016x}", hasher.Finish()); ``` The answer, `779a65e7023cd2e7`, is the same as hashing `hello world` in one call: a hasher does not care where the pieces were split. ```mermaid flowchart LR new(["`Fnv1a64()`"]) --> w1["`Write 'hello '`"] --> w2["`Write 'world'`"] --> f["`Finish()`"] --> h(["`779a65e7023cd2e7`"]) one(["`Fnv1a64Of('hello world')`"]) --> h ``` ## Not for secrets None of these hashes is **cryptographic**. Someone who wants to can find two different inputs with the same hash on purpose. So they detect accidents — a flipped bit, a truncated download — but never tampering, and they must never be used to store or check passwords. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Utilities/Hash){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // A hash function boils any amount of data down to one fixed-size number. The same bytes always // give the same number, on every machine and every run, while bytes that differ even slightly // almost always give a different one. That makes a hash a cheap fingerprint: a hash map files // keys by it, and a checksum stored next to data shows whether the data changed. // // The Hash package has several well-known algorithms. Each `...Of` function takes a pointer to // the bytes and their count, and returns the hash: // // Fnv1a64Of FNV-1a, 64 bits: tiny and fast, good for hash tables // XxHash64Of xxHash, 64 bits: very fast on long inputs // Crc32Of CRC-32, 32 bits: the checksum in ZIP, PNG and Ethernet // // None of these is cryptographic. Someone who wants to can find two inputs with the same hash on // purpose, so they detect accidents, never tampering, and must not protect passwords. import Hash::{ Crc32Of, Fnv1a64, Fnv1a64Of, XxHash64Of }; import Io::PrintLine; func Show(text: char8[..]) { let bytes = text.data as *byte; PrintLine("{:<12} fnv1a64 {:016x} xxhash64 {:016x} crc32 {:08x}", text, Fnv1a64Of(bytes, text.length), XxHash64Of(bytes, text.length), Crc32Of(bytes, text.length)); } func Main() -> int { // The same bytes, the same hashes. Show("hello world"); Show("hello world"); // One letter changed. xxHash and CRC-32 change throughout. FNV-1a is simpler, and a change // in the last byte leaves much of its old value standing: fine for a hash map, but a reason // to prefer xxHash for fingerprints. Show("hello worle"); // Even no bytes at all have a hash. Show(""); // Data that arrives in pieces can be hashed piece by piece: make a hasher, `Write` each // piece, then `Finish`. The answer is the same as hashing all the bytes at once. let first = "hello "; let second = "world"; var hasher = Fnv1a64(); hasher.Write(first.data as *byte, first.length); hasher.Write(second.data as *byte, second.length); PrintLine("in two pieces fnv1a64 {:016x}", hasher.Finish()); return 0; } ``` Besides `Io`, its `Rux.toml` lists `Hash` under `[Dependencies]`. ## Run it ```sh cd Examples/Utilities/Hash rux run ``` ```text hello world fnv1a64 779a65e7023cd2e7 xxhash64 45ab6734b21e6968 crc32 0d4a1185 hello world fnv1a64 779a65e7023cd2e7 xxhash64 45ab6734b21e6968 crc32 0d4a1185 hello worle fnv1a64 779a64e7023cd134 xxhash64 06a208d921a7827a crc32 7a4d2113 fnv1a64 cbf29ce484222325 xxhash64 ef46db3751d8e999 crc32 00000000 in two pieces fnv1a64 779a65e7023cd2e7 ``` ## Common mistakes ::mistake **Passing the text instead of a pointer.**:br The hash functions take a pointer and a count. `Fnv1a64Of(text, text.length)` fails with: ```text error: argument 1 to 'Fnv1a64Of' has type 'char8[..]', but parameter 'bytes' requires '*uint8' ``` :: ::mistake **A character pointer where a byte pointer is wanted.**:br`text.data` on its own is a `*char8`, and passing it fails with: ```text error: argument 1 to 'Fnv1a64Of' has type '*char8', but parameter 'bytes' requires '*uint8' ``` Convert it: `text.data as *byte`. :: ::mistake **A hasher declared with `let`.**:br`Write` and `Finish` change the hasher, so with `let hasher = Fnv1a64();` the first call fails with: ```text error: cannot call 'Write' on immutable 'hasher' ``` Declare it with `var`. :: ::mistake **Protecting passwords with a fast hash.**:br FNV-1a, xxHash and CRC-32 are built to be fast, and that is exactly what helps someone trying billions of guesses. Passwords need a deliberately slow, salted password hash, which is a different tool altogether. :: ## Try it yourself 1. Hash your name with all three functions. Then change one letter in the middle rather than at the end, and compare how much of the FNV-1a value survives this time. 2. Import `Fnv1a32Of` and `Crc32cOf` and add them to `Show`. Both are 32 bits, so print them with `{:08x}`. 3. Hash `hello world` in two pieces with an `XxHash64` hasher, and check the answer against `XxHash64Of`. 4. `XxHash64SeededOf(bytes, length, seed)` mixes a seed into the hash. Hash the same text with two different seeds. ## Learn more - [Pointer](https://rux-lang.dev/docs/learn/pointer) — the `*byte` every hash function takes - [String literal](https://rux-lang.dev/docs/learn/string-literal) — `data` and `length`, the two halves of a string - [Hash map](https://rux-lang.dev/docs/learn/hash-map) — where hashes do their everyday work - [UUID](https://rux-lang.dev/docs/learn/uuid) — the next lesson: identifiers that are unique rather than derived from data # UUID ::note **You'll need**: [Entropy](https://rux-lang.dev/docs/learn/entropy), [Outcome](https://rux-lang.dev/docs/learn/outcome), [Catch fallback](https://rux-lang.dev/docs/learn/catch-fallback), [Variant match](https://rux-lang.dev/docs/learn/variant-match) :: A **UUID** — universally unique identifier — is 16 bytes used as a name that nobody else will pick. Databases key rows by them, upload services name files with them, and logs tag every request with one, so the entries of a single request can be found among millions. What makes them useful is that nobody hands them out. Two programs that never talk to each other can each make UUIDs, and in practice they will never make the same one. This lesson makes one, reads and writes the text form, and compares two: ```rux import Uuid::{ Parse, Random, Uuid, UuidParseError }; ``` ## The text form A UUID is written as 32 hexadecimal digits in groups of 8, 4, 4, 4 and 12, separated by hyphens: ```text 123e4567-e89b-42d3-a456-426614174000 ^ ^ | variant: a = the standard layout version 4: random ``` The usual kind, **version 4**, is 122 random bits plus 6 fixed bits that record the version and the layout. 122 random bits is about 5 × 10³⁶ possibilities — enough that a collision between honestly made UUIDs is, in practice, never going to happen. ## Reading one `Parse` reads the text form and returns `Uuid ! UuidParseError`. Like `ParseDate` in [Date](https://rux-lang.dev/docs/learn/date), the error is a variant whose every case carries the byte where the text went wrong: ```rux func Reason(error: UuidParseError) -> char8[..] { return match error { .WrongLength(_) => "wrong length", .Misplaced(_) => "hyphen in the wrong place", .NotHexadecimal(_) => "not a hexadecimal digit", .BadPrefix(_) => "not a urn:uuid: prefix" }; } func Show(text: char8[..]) { match Parse(text) { .Success(id) => PrintLine("{:<45} -> {}", text, id), .Failure(error) => PrintLine("{:<45} -> {} at byte {}", text, Reason(error), error.Offset()) } } ``` `Parse` is strict. It accepts the hyphenated form, in either case, with or without the `urn:uuid:` prefix — and refuses everything else: | Text | Result | | ----------------------------------------------- | ---------------------------------------------- | | `123e4567-e89b-42d3-a456-426614174000` | accepted — the canonical form | | `123E4567-E89B-42D3-A456-426614174000` | accepted — upper case means the same | | `urn:uuid:123e4567-e89b-42d3-a456-426614174000` | accepted — the standard URN prefix | | `123e4567e89b42d3a456426614174000` | wrong length — the hyphens are not optional | | `123e4567-e89b-42d3-a456-42661417400g` | not a hexadecimal digit, at byte 35 | | `{123e4567-e89b-42d3-a456-426614174000}` | wrong length — braces are not part of the form | A strict reader is the safe default: text that is almost a UUID is more likely a mistake than a UUID, and refusing it with a position makes the mistake easy to find. ## Writing and comparing Printing with `{}` always writes the one canonical form, in lower case. So all three accepted spellings above print identically, and comparison is on the 16 bytes, not on the text: ```rux let lower = Parse("123e4567-e89b-42d3-a456-426614174000") catch { else => Uuid::Nil() }; let upper = Parse("123E4567-E89B-42D3-A456-426614174000") catch { else => Uuid::Nil() }; PrintLine("same identifier: {}", lower.Equals(upper)); PrintLine("the nil UUID: {}", Uuid::Nil()); ``` The [`catch` with a fallback](https://rux-lang.dev/docs/learn/catch-fallback) is safe here because both texts are known to be valid. The fallback, `Uuid::Nil()`, is the special UUID with every bit zero — useful as a "no identifier" placeholder, and never produced by `Random`. ## Making one `Random()` makes a version 4 UUID from the operating system's entropy, so like every request for entropy in [Entropy](https://rux-lang.dev/docs/learn/entropy) it can fail, and returns `Uuid ! EntropyError`: ```rux match Random() { .Success(id) => PrintLine("a new one: {} version {}", id, id.Version()), .Failure(_) => PrintLine("no entropy for a new UUID") } ``` `Version()` reads the version digit back: 4. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Utilities/Uuid){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // A UUID (universally unique identifier) is 16 bytes used as a name that nobody else will pick: // a database row, an uploaded file, a request in a log. Its text form is 32 hexadecimal digits // in groups of 8-4-4-4-12, such as 123e4567-e89b-42d3-a456-426614174000. // // The usual kind, version 4, is 122 random bits plus 6 bits marking the version and layout. With // that many random bits, two programs that never talk to each other will still, in practice, // never produce the same one. `Random()` makes one from the operating system's entropy, so like // any request for entropy it returns `Uuid ! EntropyError`. // // `Parse` reads the text form and returns `Uuid ! UuidParseError`. It is strict: upper case is // accepted, since it means the same, but braces, missing hyphens or stray characters are // refused, with the byte where the text went wrong. Printing with `{}` always writes the one // canonical form, in lower case. import Io::PrintLine; import Uuid::{ Parse, Random, Uuid, UuidParseError }; func Reason(error: UuidParseError) -> char8[..] { return match error { .WrongLength(_) => "wrong length", .Misplaced(_) => "hyphen in the wrong place", .NotHexadecimal(_) => "not a hexadecimal digit", .BadPrefix(_) => "not a urn:uuid: prefix" }; } func Show(text: char8[..]) { match Parse(text) { .Success(id) => PrintLine("{:<45} -> {}", text, id), .Failure(error) => PrintLine("{:<45} -> {} at byte {}", text, Reason(error), error.Offset()) } } func Main() -> int { Show("123e4567-e89b-42d3-a456-426614174000"); Show("123E4567-E89B-42D3-A456-426614174000"); Show("urn:uuid:123e4567-e89b-42d3-a456-426614174000"); Show("123e4567e89b42d3a456426614174000"); Show("123e4567-e89b-42d3-a456-42661417400g"); Show("{123e4567-e89b-42d3-a456-426614174000}"); // Two spellings, one identifier: comparison is on the 16 bytes, not on the text. let lower = Parse("123e4567-e89b-42d3-a456-426614174000") catch { else => Uuid::Nil() }; let upper = Parse("123E4567-E89B-42D3-A456-426614174000") catch { else => Uuid::Nil() }; PrintLine("same identifier: {}", lower.Equals(upper)); PrintLine("the nil UUID: {}", Uuid::Nil()); // A fresh random one, different on every run. match Random() { .Success(id) => PrintLine("a new one: {} version {}", id, id.Version()), .Failure(_) => PrintLine("no entropy for a new UUID") } return 0; } ``` Besides `Io`, its `Rux.toml` lists `Uuid` under `[Dependencies]`. ## Run it ```sh cd Examples/Utilities/Uuid rux run ``` ```text 123e4567-e89b-42d3-a456-426614174000 -> 123e4567-e89b-42d3-a456-426614174000 123E4567-E89B-42D3-A456-426614174000 -> 123e4567-e89b-42d3-a456-426614174000 urn:uuid:123e4567-e89b-42d3-a456-426614174000 -> 123e4567-e89b-42d3-a456-426614174000 123e4567e89b42d3a456426614174000 -> wrong length at byte 32 123e4567-e89b-42d3-a456-42661417400g -> not a hexadecimal digit at byte 35 {123e4567-e89b-42d3-a456-426614174000} -> wrong length at byte 36 same identifier: true the nil UUID: 00000000-0000-0000-0000-000000000000 a new one: 12c16353-3376-4e49-a1ec-403586becf8d version 4 ``` Every line is the same on each run except the last, which is a sample: a new random UUID each time. ## Common mistakes ::mistake **Using the outcome as an identifier.**:br`let id: Uuid = Random();` fails with: ```text error: cannot assign 'Uuid ! EntropyError' to 'Uuid' ``` Making a UUID can fail when the system has no entropy, so handle that first. :: ::mistake **Comparing UUIDs as text.**:br`123e4567-…` and `123E4567-…` are different strings and the same identifier. Parse both and compare the values — with `Equals` or `==` — rather than the text. :: ::mistake **A fallback on input you do not control.**:br`catch { else => Uuid::Nil() }` is fine for a literal the program knows is valid. On user input it turns every typo into the nil UUID, which then looks like a real value. Report the `UuidParseError` instead. :: ::mistake **Leaving out an error case.**:br The `match` in `Reason` must name every case. Drop `.BadPrefix` and the compiler says: ```text error: match on 'UuidParseError' is not exhaustive; missing UuidParseError::BadPrefix ``` :: ## Try it yourself 1. Show a UUID with its last two digits missing, and one with a hyphen one place too far right. Which reasons and bytes do you get? 2. Print `Uuid::Max()`, the UUID with every bit set. 3. Import `TimeOrdered` and make a version 7 UUID, which starts with the current time. Make two and compare their first groups. 4. Make five random UUIDs in a loop and print them. Do any two share even their first group? ## Learn more - [Entropy](https://rux-lang.dev/docs/learn/entropy) — where the random bits come from, and why it can fail - [Variant match](https://rux-lang.dev/docs/learn/variant-match) — matching the cases of `UuidParseError` - [Catch fallback](https://rux-lang.dev/docs/learn/catch-fallback) — `catch { else => … }` and when it is safe - [Hash](https://rux-lang.dev/docs/learn/hash) — fingerprints derived from data, the opposite of an identifier made from nothing # Nano ID ::note **You'll need**: [UUID](https://rux-lang.dev/docs/learn/uuid), [Writable slice](https://rux-lang.dev/docs/learn/writable-slice) :: A [UUID](https://rux-lang.dev/docs/learn/uuid) names a thing in 36 characters, and four of those are hyphens. When the identifier ends up in a URL, a file name or a short link — `example.com/s/V1StGXR8_Z5jdHi6B-myT` — something shorter that needs no escaping is welcome. A **Nano ID** is exactly that: 21 characters, each one of the 64 that are safe in a URL, and still more random bits than a UUID. This lesson makes one, reads one back, and then fills a buffer of its own length from an alphabet of its own choosing — six digits for a confirmation code: ```rux import NanoId::{ GenerateNanoId, NanoId, NanoIdAlphabet, NanoIdLength, NanoIdParseError, ValidateAlphabet }; ``` ## Short and random The default alphabet is `A`–`Z`, `a`–`z`, `0`–`9`, `_` and `-`: 64 characters, so each one carries exactly six random bits. | | UUID version 4 | Nano ID | | -------------- | -------------- | ------- | | Characters | 36 | 21 | | Random bits | 122 | 126 | | Safe in a URL | yes | yes | | Fixed hyphens | four | none | | Case-sensitive | no | yes | The last row matters: in a UUID `A` and `a` are the same digit, but in a Nano ID they are different characters, and `V1St…` and `v1st…` are two different identifiers. ## Making one `NanoId::Generate()` draws 21 random bytes from the operating system, as [Entropy](https://rux-lang.dev/docs/learn/entropy) does, and so returns `NanoId ! EntropyError`: ```rux let id = NanoId::Generate() catch { else => { PrintLine("no entropy for a new identifier"); return 1; } }; PrintLine("a new one: {}", id); ``` If the system has no entropy there is no identifier at all — never a predictable one. A `NanoId` is a small `Copy` value holding its 21 characters inline; `{}` prints them, and `Text()` lends them out as a `char8[..]`. ## Reading one back `NanoId::Parse` is as strict as the UUID parser: exactly 21 bytes, every one from the default alphabet. The error says why and, through `Offset()`, where: ```rux func Reason(error: NanoIdParseError) -> char8[..] { return match error { .WrongLength(_) => "wrong length", .InvalidCharacter(_) => "not in the alphabet" }; } ``` | Text | Result | | ------------------------- | ---------------------------------------- | | `V1StGXR8_Z5jdHi6B-myT` | accepted | | `V1StGXR8_Z5jdHi6B` | wrong length, at byte 17 — the text ends | | `V1StGXR8_Z5jdHi6B-myT42` | wrong length, at byte 21 — the form ends | | `V1StGXR8+Z5jdHi6B-myT` | not in the alphabet, at byte 8 | Whatever `Generate` returns, its text parses back to an equal value. `Equals` compares every byte whatever it finds, so the time it takes says nothing about how much of a guessed identifier was right — which matters when the identifier is a secret, such as a session token. ## Your own length and alphabet `GenerateNanoId` fills a buffer you provide, of any length, from the default alphabet or from one you pass: ```rux var code: char8[6]; GenerateNanoId(code[..], "0123456789") catch { else => { PrintLine("no entropy for a code"); return 1; } }; ``` The buffer is a [writable slice](https://rux-lang.dev/docs/learn/writable-slice) of a local array, and the code is as long as the buffer. With an alphabet, the call returns `! NanoIdError`, which adds the ways an alphabet can be unusable to the entropy failure. The point of the rules is that every character must be equally likely. Each character starts as one random byte, masked down to the smallest power of two that covers the alphabet. For ten digits that is 0–15; a value from 10 to 15 is thrown away and another byte is used: ```mermaid flowchart LR b["random byte"] --> m["keep the low bits:
0 to 15"] m --> q{"below 10?"} q -- "yes" --> c["that digit"] q -- "no" --> b ``` Folding 10–15 back with a remainder instead would make `0` to `5` likelier than `6` to `9`. For the same reason an alphabet must have between 2 and 256 characters, all distinct and all ASCII. `ValidateAlphabet` checks that, and the generators call it before spending any entropy: | Alphabet | Verdict | | ------------------ | ----------------------------------------------- | | `0123456789abcdef` | usable | | `x` | too few characters — one carries no information | | `abcabc` | a duplicate at byte 3, which would be likelier | | `abé` | not ASCII at byte 2 — `é` is two bytes in UTF-8 | ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Utilities/NanoId){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // A Nano ID is a short random identifier, such as V1StGXR8_Z5jdHi6B-myT. It does the job of a // UUID in less space: twenty-one characters drawn from the sixty-four that are safe in a URL or a // file name, A-Z, a-z, 0-9, `_` and `-`. Each character carries six random bits, so a standard // identifier carries 126, more than a version 4 UUID, in twenty-one characters instead of 36. // // `NanoId::Generate()` makes one from the operating system's entropy and returns // `NanoId ! EntropyError`. `NanoId::Parse` reads the text form back, strictly: exactly twenty-one // characters, every one from the default alphabet. // // `GenerateNanoId` fills a buffer you provide instead, of any length and from any alphabet, such // as six digits for a confirmation code. An alphabet must be two to 256 distinct ASCII // characters, so that every character is equally likely; `ValidateAlphabet` says which rule a bad // one breaks, before any entropy is spent. import Io::PrintLine; import NanoId::{ GenerateNanoId, NanoId, NanoIdAlphabet, NanoIdLength, NanoIdParseError, ValidateAlphabet }; func Reason(error: NanoIdParseError) -> char8[..] { return match error { .WrongLength(_) => "wrong length", .InvalidCharacter(_) => "not in the alphabet" }; } func Show(text: char8[..]) { match NanoId::Parse(text) { .Success(id) => PrintLine("{:<23} -> {}", text, id), .Failure(error) => PrintLine("{:<23} -> {} at byte {}", text, Reason(error), error.Offset()) } } func Check(alphabet: char8[..]) { match ValidateAlphabet(alphabet) { .Success(_) => PrintLine("{:<16} -> usable", alphabet), .Failure(error) => match error { .AlphabetTooSmall => PrintLine("{:<16} -> too few characters", alphabet), .AlphabetTooLarge => PrintLine("{:<16} -> too many characters", alphabet), .DuplicateCharacter(at) => PrintLine("{:<16} -> a duplicate at byte {}", alphabet, at), .NonAsciiCharacter(at) => PrintLine("{:<16} -> not ASCII at byte {}", alphabet, at), .Entropy(_) => PrintLine("{:<16} -> no entropy", alphabet) } } } // Whether every character of `text` appears in `alphabet`. func AllFrom(text: char8[..], alphabet: char8[..]) -> bool { for c in text { var found = false; for member in alphabet { if member == c { found = true; } } if !found { return false; } } return true; } func Main() -> int { PrintLine("default alphabet: {} characters, {} per identifier", NanoIdAlphabet.length, NanoIdLength); // Reading the text form. The first is the example from Nano ID's own documentation. Show("V1StGXR8_Z5jdHi6B-myT"); Show("V1StGXR8_Z5jdHi6B"); Show("V1StGXR8_Z5jdHi6B-myT42"); Show("V1StGXR8+Z5jdHi6B-myT"); // A new identifier, different on every run. Generating can fail when the system has no // entropy, and then there is no identifier at all, never a predictable one. So the outcome is // not the identifier itself: // // let id: NanoId = NanoId::Generate(); // error: cannot assign 'NanoId ! EntropyError' to 'NanoId' let id = NanoId::Generate() catch { else => { PrintLine("no entropy for a new identifier"); return 1; } }; PrintLine("a new one: {}", id); // Whatever it is, its shape is fixed: twenty-one characters that parse back to the same value. match NanoId::Parse(id.Text()) { .Success(back) => PrintLine("length {}, parses back to itself: {}", id.Text().length, back.Equals(id)), .Failure(_) => PrintLine("does not parse back") } // A six-digit code from a custom alphabet, in a buffer of exactly the length wanted. This // call returns `! NanoIdError`, since the alphabet could be unusable, and that failure must be // handled too: // // GenerateNanoId(code[..], "0123456789"); // error: fallible result of type '! NanoIdError' is discarded var code: char8[6]; GenerateNanoId(code[..], "0123456789") catch { else => { PrintLine("no entropy for a code"); return 1; } }; PrintLine("a code: {}", code[..]); PrintLine("length {}, digits only: {}", code.length, AllFrom(code[..], "0123456789")); // Alphabets that would make some characters likelier than others are refused. Check("0123456789abcdef"); Check("x"); Check("abcabc"); Check("abé"); return 0; } ``` Besides `Io`, its `Rux.toml` lists `NanoId` under `[Dependencies]`. ## Run it ```sh cd Examples/Utilities/NanoId rux run ``` ```text default alphabet: 64 characters, 21 per identifier V1StGXR8_Z5jdHi6B-myT -> V1StGXR8_Z5jdHi6B-myT V1StGXR8_Z5jdHi6B -> wrong length at byte 17 V1StGXR8_Z5jdHi6B-myT42 -> wrong length at byte 21 V1StGXR8+Z5jdHi6B-myT -> not in the alphabet at byte 8 a new one: wjQ9BAvSAUonmlZf6TfIw length 21, parses back to itself: true a code: 198099 length 6, digits only: true 0123456789abcdef -> usable x -> too few characters abcabc -> a duplicate at byte 3 abé -> not ASCII at byte 2 ``` The `a new one` and `a code` lines are samples: each run draws a new identifier and a new code. Every other line is the same on each run. ## Common mistakes ::mistake **Using the outcome as the identifier.**:br`let id: NanoId = NanoId::Generate();` fails with: ```text error: cannot assign 'NanoId ! EntropyError' to 'NanoId' ``` Generating can fail when the system has no entropy; handle that first. :: ::mistake **Ignoring the result of `GenerateNanoId`.**:br The call fills the buffer, so it is tempting to write it as a statement on its own. It fails with: ```text error: fallible result of type '! NanoIdError' is discarded ``` If it failed, the buffer holds no code — never even the start of one — so the failure must be handled. :: ::mistake **Keeping a custom code in a `NanoId`.**:br A `NanoId` is the standard form only. `NanoId::Parse("198099")` is refused as the wrong length at byte 6. A code of another length or alphabet stays in its own buffer. :: ::mistake **Treating Nano IDs as case-insensitive.**:br Lower-casing an identifier, or storing it in a column that ignores case, merges different identifiers. Compare them exactly. :: ## Try it yourself 1. Make a ten-character identifier from the default alphabet: `GenerateNanoId` without an alphabet fills a `char8[10]` and returns `! EntropyError`. 2. Make a 32-character code from `"0123456789abcdef"`. How many random bits does it carry, and how does that compare with a UUID? 3. Show `"V1StGXR8 Z5jdHi6B-myT"`, with a space. Which reason and byte do you get? 4. Check the alphabet `"01"`. Is it usable? How long must an identifier from it be to carry 126 bits? ## Learn more - [NanoId API](https://rux-lang.dev/docs/api/nanoid) — every function and error case - [UUID](https://rux-lang.dev/docs/learn/uuid) — the longer, case-insensitive identifier with a fixed layout - [Entropy](https://rux-lang.dev/docs/learn/entropy) — where the random bytes come from, and why asking can fail - [Writable slice](https://rux-lang.dev/docs/learn/writable-slice) — a function filling a buffer it was lent - [Password](https://rux-lang.dev/docs/learn/password) — a checkpoint project that draws characters from entropy without bias - [Slices](https://rux-lang.dev/docs/lang/slices/overview) in the Rux Reference # Time zone ::note **You'll need**: [Date and time](https://rux-lang.dev/docs/learn/date-time), [Allocator](https://rux-lang.dev/docs/learn/allocator), [Move](https://rux-lang.dev/docs/learn/move), [Enum](https://rux-lang.dev/docs/learn/enum) :: An offset such as `+03:00`, from [Date and time](https://rux-lang.dev/docs/learn/date-time), describes a clock at one moment. It does not describe a place. Kyiv keeps `+02:00` in winter and `+03:00` in summer; New York keeps `-05:00` and `-04:00`, and changes on different dates. To say "09:00 in Kyiv" on a date you have not looked up yet, you need the place's **rules** — a time zone. A `TimeZone` turns a moment into the local time there, and a local time back into a moment. The second direction is the interesting one, because once a year a local time happens twice, and once a year it does not happen at all: ```rux import TimeZone::{ LocalTimeKind, TimeZone, TimeZoneError }; ``` ## Where a zone comes from | Function | Builds a zone from | | -------------------- | --------------------------------------------------------- | | `TimeZone::Utc` | nothing — UTC never changes | | `TimeZone::FromRule` | a POSIX `TZ` rule, such as `EET-2EEST,M3.5.0/3,M10.5.0/4` | | `TimeZone::Load` | the tz database, by name, such as `Europe/Kyiv` | | `TimeZone::Local` | the computer's own setting | | `TimeZone::FromTzif` | the bytes of a tz database file you read yourself | `Load` is what most programs on Linux and macOS use, since the tz database holds every change a zone has ever made. But Windows keeps no tz database, so there `Load` finds nothing unless the program points the `TZDIR` environment variable at a copy. This lesson builds its zones from rules, which work the same everywhere, and leaves `Local` out because its answer depends on the machine. Each of them allocates and can fail, so each returns `TimeZone ! TimeZoneError`, and each takes an [allocator](https://rux-lang.dev/docs/learn/allocator): ```rux let utc = TimeZone::Utc(allocator) catch { else => return 1 }; let kyiv = TimeZone::FromRule(allocator, "Kyiv", "EET-2EEST,M3.5.0/3,M10.5.0/4") catch { else => return 1 }; ``` A zone owns that memory, so it is [move-only](https://rux-lang.dev/docs/learn/move), and the functions in this program borrow it as `&TimeZone`. ## Reading a POSIX rule A rule packs a whole year into one line. Kyiv's reads: | Part | Means | | ----------- | ------------------------------------------------------------------------------ | | `EET` | the standard time's abbreviation | | `-2` | its offset — **minus means east of UTC**, so this is `+02:00` | | `EEST` | the daylight time's abbreviation, an hour ahead unless an offset follows it | | `M3.5.0/3` | daylight time starts in month 3, week 5 (the last), on day 0 (Sunday), at 3:00 | | `M10.5.0/4` | and ends in month 10, on the last Sunday, at 4:00 daylight time | New York's `EST5EDT,M3.2.0,M11.1.0` reads the same way: five hours west, with daylight time from the second Sunday in March to the first Sunday in November, at the default 2:00. A malformed rule, such as `X5`, whose name is too short, fails with `TimeZoneError::InvalidRule`. ## From a moment to local time `StateAt` says what the zone keeps at a moment — its offset, its abbreviation and whether it is daylight time — and `ToLocal` gives the local date and time as an `OffsetDateTime`: ```rux func ShowMoment(zone: &TimeZone, moment: Timestamp) { let state = zone.StateAt(moment); PrintLine(" {:<8} {:<4} daylight {:<5} {}", zone.Name(), state.abbreviation, state.daylight, zone.ToLocal(moment)); } ``` This direction always has exactly one answer. The program reads noon UTC on 15 January and on 1 July on three clocks: Kyiv moves from `+02:00` to `+03:00`, New York from `-05:00` to `-04:00`, and UTC stays where it is. ## From local time to a moment Going back is where clocks get awkward. On the last Sunday of March, Kyiv's clocks jump from 03:00 straight to 04:00; on the last Sunday of October they go back from 04:00 to 03:00: ```mermaid flowchart LR q["a local time
in Kyiv"] --> r{"`Resolve`"} r -- "an ordinary day" --> u["`Unique`:
one moment"] r -- "29 March, 03:30" --> s["`Skipped`:
no moment"] r -- "25 October, 03:30" --> a["`Ambiguous`:
two moments"] ``` So `Resolve` does not return one `Timestamp`. It returns a `LocalTime`: a `kind`, which is a `LocalTimeKind`, and two candidate moments, `earlier` and `later`: ```rux let found = zone.Resolve(local); match found.kind { LocalTimeKind::Unique => PrintLine(" {} happens once: {}", text, zone.ToLocal(found.earlier)), LocalTimeKind::Ambiguous => PrintLine(" {} happens twice: {} then {}", text, zone.ToLocal(found.earlier), zone.ToLocal(found.later)), LocalTimeKind::Skipped => PrintLine(" {} never happens: taken as {}", text, zone.ToLocal(found.later)) } ``` | Kind | `earlier` | `later` | | ----------- | ------------------------------------------- | ------------------------------------------- | | `Unique` | the moment | the same moment | | `Ambiguous` | the first time, still in summer time | the second time, an hour later | | `Skipped` | 03:30 at the new offset: 02:30 on the clock | 03:30 at the old offset: 04:30 on the clock | For a skipped time, `later` is what most programs want: an alarm set for 03:30 rings at 04:30, an hour after 02:30, just as it would have without the change. For a repeated time there is no right answer in general — a nightly job should usually run only on the first, a meeting may mean either — so the choice is left to you. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Utilities/TimeZone){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // An offset such as +03:00 says how far a clock is from UTC at one moment. A time zone says which // offset a place uses at every moment: Kyiv keeps +02:00 in winter and +03:00 in summer, and // moves between them on dates its rules fix. So a time zone turns a moment into the local time // there, and back. // // `TimeZone::FromRule` builds a zone from a POSIX `TZ` rule, a short text that names the // standard time, its offset, the daylight time and when it starts and ends. Kyiv's is // `EET-2EEST,M3.5.0/3,M10.5.0/4`: EET, two hours east of UTC (POSIX writes east as minus), and // EEST from 03:00 on the last Sunday of March (M3.5.0/3) until 04:00 on the last Sunday of // October (M10.5.0/4). `TimeZone::Load` reads a zone's whole history from the tz database by // name instead, but Windows has no such database, so this program builds its zones from rules. // // `StateAt` gives the offset, the abbreviation and whether it is daylight time at a moment, and // `ToLocal` the local date and time. `Resolve` goes the other way, from a local date and time to // the moment, and says whether that local time happened once, twice as clocks fell back over it, // or never as they sprang forward over it. import Allocator::{ Allocator, SystemAllocator }; import Io::PrintLine; import Time::{ ParseDateTime, ParseRfc3339, Timestamp }; import TimeZone::{ LocalTimeKind, TimeZone, TimeZoneError }; func Reason(error: TimeZoneError) -> char8[..] { return match error { TimeZoneError::NotFound => "no zone of that name", TimeZoneError::InvalidName => "not a zone name", TimeZoneError::InvalidData => "not a tz database file", TimeZoneError::InvalidRule => "not a POSIX TZ rule", TimeZoneError::Unreadable => "the zone file could not be read", TimeZoneError::OutOfMemory => "out of memory" }; } // The local time in `zone` at `moment`, with what the zone calls it. func ShowMoment(zone: &TimeZone, moment: Timestamp) { let state = zone.StateAt(moment); PrintLine(" {:<8} {:<4} daylight {:<5} {}", zone.Name(), state.abbreviation, state.daylight, zone.ToLocal(moment)); } // Which moments the local date and time `text` stands for in `zone`. func ShowLocal(zone: &TimeZone, text: char8[..]) { let local = ParseDateTime(text) catch { else => { PrintLine("{} is not a date and time", text); return; } }; let found = zone.Resolve(local); match found.kind { LocalTimeKind::Unique => PrintLine(" {} happens once: {}", text, zone.ToLocal(found.earlier)), LocalTimeKind::Ambiguous => PrintLine(" {} happens twice: {} then {}", text, zone.ToLocal(found.earlier), zone.ToLocal(found.later)), LocalTimeKind::Skipped => PrintLine(" {} never happens: taken as {}", text, zone.ToLocal(found.later)) } } func Main() -> int { var system = SystemAllocator(); let allocator: Allocator = system; // Building a zone allocates, and a rule can be malformed, so each returns // `TimeZone ! TimeZoneError`. A zone owns that memory, so it is never copied by accident: // // let copy = kyiv; // error: move-only value 'kyiv' requires an explicit '<-' in initialization // // The functions below borrow it instead, as `&TimeZone`. let utc = TimeZone::Utc(allocator) catch { else => return 1 }; let kyiv = TimeZone::FromRule(allocator, "Kyiv", "EET-2EEST,M3.5.0/3,M10.5.0/4") catch { else => return 1 }; let newYork = TimeZone::FromRule(allocator, "New York", "EST5EDT,M3.2.0,M11.1.0") catch { else => return 1 }; // One moment in winter and one in summer, each read on three clocks. The offsets change with // the season, and by a different amount on different dates in each place. let winter = ParseRfc3339("2026-01-15T12:00:00Z") catch { else => return 1 }; let summer = ParseRfc3339("2026-07-01T12:00:00Z") catch { else => return 1 }; PrintLine("{}", winter); ShowMoment(utc, winter.ToTimestamp()); ShowMoment(kyiv, winter.ToTimestamp()); ShowMoment(newYork, winter.ToTimestamp()); PrintLine("{}", summer); ShowMoment(utc, summer.ToTimestamp()); ShowMoment(kyiv, summer.ToTimestamp()); ShowMoment(newYork, summer.ToTimestamp()); // From local time back to a moment. On 29 March 2026 Kyiv's clocks jump from 03:00 to 04:00, // so 03:30 never happens; on 25 October they go back from 04:00 to 03:00, so 03:30 happens // twice, an hour apart. That is why `Resolve` returns a `LocalTime`, with the kind and both // candidate moments, and not one `Timestamp`: // // let moment: Timestamp = kyiv.Resolve(local); // error: cannot assign 'LocalTime' to 'Timestamp' PrintLine("Kyiv local times:"); ShowLocal(kyiv, "2026-07-01T15:00:00"); ShowLocal(kyiv, "2026-03-29T03:30:00"); ShowLocal(kyiv, "2026-10-25T03:30:00"); // A rule must name its standard time with at least three letters, then give its offset. match TimeZone::FromRule(allocator, "Nowhere", "X5") { .Success(_) => PrintLine("rule X5 accepted"), .Failure(error) => PrintLine("rule X5 refused: {}", Reason(error)) } return 0; } ``` Besides `Io`, its `Rux.toml` lists `Allocator`, `Time` and `TimeZone` under `[Dependencies]`. ## Run it ```sh cd Examples/Utilities/TimeZone rux run ``` ```text 2026-01-15T12:00:00Z UTC UTC daylight false 2026-01-15T12:00:00Z Kyiv EET daylight false 2026-01-15T14:00:00+02:00 New York EST daylight false 2026-01-15T07:00:00-05:00 2026-07-01T12:00:00Z UTC UTC daylight false 2026-07-01T12:00:00Z Kyiv EEST daylight true 2026-07-01T15:00:00+03:00 New York EDT daylight true 2026-07-01T08:00:00-04:00 Kyiv local times: 2026-07-01T15:00:00 happens once: 2026-07-01T15:00:00+03:00 2026-03-29T03:30:00 never happens: taken as 2026-03-29T04:30:00+03:00 2026-10-25T03:30:00 happens twice: 2026-10-25T03:30:00+03:00 then 2026-10-25T03:30:00+02:00 rule X5 refused: not a POSIX TZ rule ``` ## Common mistakes ::mistake **Treating a local time as one moment.**:br`let moment: Timestamp = kyiv.Resolve(local);` fails with: ```text error: cannot assign 'LocalTime' to 'Timestamp' ``` Look at `kind` first, then choose between `earlier` and `later`. :: ::mistake **The sign of a POSIX offset.**:br POSIX counts hours *west* of UTC, so Kyiv is `EET-2`, not `EET+2`. The wrong sign is not an error: with `EET+2EEST,M3.5.0/3,M10.5.0/4`, noon UTC on 1 July becomes `2026-07-01T11:00:00-01:00`. :: ::mistake **Loading by name everywhere.**:br On Windows, `TimeZone::Load(allocator, "Europe/Kyiv")` fails with `TimeZoneError::NotFound`, because there is no tz database to read. Handle the failure, ship a copy of the database and set `TZDIR`, or build the zone from a rule. :: ::mistake **Copying a zone.**:br`let copy = kyiv;` fails with: ```text error: move-only value 'kyiv' requires an explicit '<-' in initialization ``` Pass the zone by reference, as `ShowMoment` does. :: ## Try it yourself 1. Resolve `2026-03-08T02:30:00` and `2026-11-01T01:30:00` in New York. Which kind is each? 2. Add Sydney, `AEST-10AEDT,M10.1.0,M4.1.0/3`, and read both moments on its clock. Which of them is in daylight time, and why? 3. For the skipped time, also print `found.earlier` on Kyiv's clock. What does it read? 4. Print how many seconds apart the two moments of the repeated 03:30 are, with `UnixSeconds()`. ## Learn more - [TimeZone API](https://rux-lang.dev/docs/api/timezone) — every function, including `Load`, `Local` and `FromTzif` - [Date and time](https://rux-lang.dev/docs/learn/date-time) — `DateTime`, `UtcOffset`, `OffsetDateTime` and RFC 3339 - [Enum](https://rux-lang.dev/docs/learn/enum) — matching the cases of `LocalTimeKind` - [Move](https://rux-lang.dev/docs/learn/move) — why a zone is passed by reference - [Age](https://rux-lang.dev/docs/learn/age) — a checkpoint project that works out an age from two calendar dates - [Enums](https://rux-lang.dev/docs/lang/enums/overview) and [Copy and move](https://rux-lang.dev/docs/lang/ownership/copy-and-move) in the Rux Reference # Part 21: Data formats Sooner or later a program has to talk to something that is not itself — a web service, a configuration file, another program written in another language. This part reads and writes the two text formats you will meet most: **JSON**, for exchanging data, and **TOML**, for configuration. Both packages work the same way: text becomes a tree of values, a program asks each value what it is before taking it apart, and a document that is wrong is refused with the place it went wrong. Three more lessons cover what travels inside and around such documents: bytes written as text with **Base64** and its relatives, the **URLs** that point at everything, and **compressed** data in the gzip and zlib formats. ## What you will learn - Parsing JSON into a tree of six kinds of value, and reading typed values out of it through pointers and out-parameters. - Building a JSON tree by hand, writing it compact or pretty, and checking a round trip. - Reading JSON as a stream of events, for documents too large to hold at once. - Reading TOML, whose values have real types: integers, floats, dates and tables. - Changing a TOML document and writing it back — and what a round trip keeps and loses. - Reporting a bad document by byte, or by line and column, so a person can find the mistake. - Writing bytes as hexadecimal, Base64, Base32 or Base58 text, and decoding them back strictly. - Parsing, normalizing and resolving URLs, and reading and building their queries. - Compressing data in memory or as a stream, in the raw, zlib and gzip formats. ## The part at a glance ```mermaid flowchart LR jt(["JSON text"]) -- "`Parse`" --> jv["`JsonValue` tree"] jv -- "`WriteValue`" --> jt jt -- "`JsonEventReader`" --> ev["Events, one at a time"] tt(["TOML text"]) -- "`TomlParse`" --> tv["`TomlValue` tree"] tv -- "`TomlWriteDocument`" --> tt jt -- "malformed" --> err["Refused, with
where and why"] tt -- "malformed" --> err ``` ## Lessons | | Lesson | What you will learn | | ---- | ------------------------------------------------------------------- | ------------------------------------------------------------------ | | 21.1 | [JSON](https://rux-lang.dev/docs/learn/json) | parse JSON into a value and walk it | | 21.2 | [Writing JSON](https://rux-lang.dev/docs/learn/json-write) | write a value out as JSON | | 21.3 | [Streaming JSON](https://rux-lang.dev/docs/learn/json-stream) | read JSON as a stream of events | | 21.4 | [TOML](https://rux-lang.dev/docs/learn/toml) | parse a TOML document and read its values | | 21.5 | [Writing TOML](https://rux-lang.dev/docs/learn/toml-write) | write a TOML document | | 21.6 | [Base64 and friends](https://rux-lang.dev/docs/learn/base-encoding) | bytes as hexadecimal, Base64, Base32 and Base58 text | | 21.7 | [URL](https://rux-lang.dev/docs/learn/url) | parse, resolve and build URLs and their queries | | 21.8 | [Compress](https://rux-lang.dev/docs/learn/compress) | compress and decompress data in the Deflate, zlib and gzip formats | ## Before you start Documents are held in memory from an [allocator](https://rux-lang.dev/docs/learn/allocator), and values are read through [pointers](https://rux-lang.dev/docs/learn/pointer) and [out-parameters](https://rux-lang.dev/docs/learn/out-parameter), all from [Part 15: Memory](https://rux-lang.dev/docs/learn/memory). Text is handled with the `String`, `StringView` and `StringBuilder` of [Part 14: Text](https://rux-lang.dev/docs/learn/text), trees are move-only values as in [Part 11: Ownership](https://rux-lang.dev/docs/learn/ownership), and failures come in [error sums](https://rux-lang.dev/docs/learn/error-sum) from Part 9. The TOML lesson also reads a `Date` from [Part 20: Utilities](https://rux-lang.dev/docs/learn/utilities). The base encodings write into buffers you provide, as [writable slices](https://rux-lang.dev/docs/learn/writable-slice), and Compress streams into a [file](https://rux-lang.dev/docs/learn/file) through the `Writer` and `Reader` of [Part 19: Files](https://rux-lang.dev/docs/learn/files). Each lesson's package is in the Examples repository's `DataFormats/` folder: ```sh cd Examples/DataFormats/Json rux run ``` ## After this part [Part 22: Packages](https://rux-lang.dev/docs/learn/packages) steps back from single programs to how code is organised and shared — modules, packages, libraries and the `Rux.toml` that describes them, which you can now read as the TOML it is. Before moving on, try the checkpoint project [Notes](https://rux-lang.dev/docs/learn/notes): a to-do list kept as JSON in a file, saved, loaded back, added to, and protected against a damaged or missing file. It puts this part together with [Part 19: Files](https://rux-lang.dev/docs/learn/files). For the language rules this part relies on, see [Pointers](https://rux-lang.dev/docs/lang/pointers/overview), [null pointers](https://rux-lang.dev/docs/lang/pointers/overview#null) and [Interfaces](https://rux-lang.dev/docs/lang/interfaces/overview) in the Rux Reference, and the [manifest](https://rux-lang.dev/docs/packaging/manifest) for the TOML file every package has. # JSON ::note **You'll need**: [Allocator](https://rux-lang.dev/docs/learn/allocator), [Pointer](https://rux-lang.dev/docs/learn/pointer), [Out parameter](https://rux-lang.dev/docs/learn/out-parameter), [Outcome](https://rux-lang.dev/docs/learn/outcome), [String view](https://rux-lang.dev/docs/learn/string-view) :: JSON is how programs that share nothing else — not a language, not a machine, not an owner — agree on what a value is. A web API answers in it, a browser stores settings in it, and a log line often is one. This lesson reads a JSON document with the `Json` package, takes typed values out of it, and shows how a broken document is refused. ```rux import Allocator::{ Allocator, SystemAllocator }; import Json::{ JsonKind, JsonValue, Parse }; import Text::StringView; ``` ## Parsing a document `Parse` reads the whole text into a tree of values: ```text Parse(allocator, text) -> JsonValue ! JsonParseError ``` The tree needs memory — a document can be any size — so `Parse` takes an [allocator](https://rux-lang.dev/docs/learn/allocator) to get it from. `Main` makes the system allocator and hands out an `Allocator` view of it: ```rux var system = SystemAllocator(); let allocator: Allocator = system; ``` The result is an [outcome](https://rux-lang.dev/docs/learn/outcome): either the whole document, as its root value, or the reason there is none. There is never half a document. ```rux match Parse(allocator, document) { .Success(root) => Inspect(root), .Failure(reason) => PrintLine("refused at byte {}: {}", reason.Offset(), reason) } ``` The document is one long string literal, with every `"` inside it escaped as `\"`: ```json { "name": "Rux", "year": 2026, "tags": ["fast", "small"], "flags": { "beta": true } } ``` ## A tree of six kinds Every value in the tree is one of six kinds, and `Kind()` says which. Containers hold more values, so the document above parses into this tree: ```mermaid flowchart TD root["object"] -- "`name`" --> n["text: `Rux`"] root -- "`year`" --> y["number: `2026`"] root -- "`tags`" --> t["array"] root -- "`flags`" --> f["object"] t -- "`0`" --> t0["text: `fast`"] t -- "`1`" --> t1["text: `small`"] f -- "`beta`" --> b["boolean: `true`"] ``` Reading the tree always means asking a value what it is before taking it apart: | Kind | Ask with | Answers | | --------- | ---------------------------- | ------------------------------------------------ | | `Object` | `Find(name)`, `Length()` | a pointer to the member, null when it is missing | | `Array` | `At(index)`, `Length()` | a pointer to the element, null past the end | | `Text` | `AsText()` | a `StringView`, empty for any other kind | | `Number` | `AsNumber()`, then `AsInt64` | `false` when the number is not that type | | `Boolean` | `AsBoolean(@flag)` | `false` when the value is not a boolean | | `Null` | `IsNull()` | `true` for `null` | `KindName` turns a kind into a word for printing, with `else` covering the last one, `Null`. ## Finding a member Member names are text, so `Find` takes a [`StringView`](https://rux-lang.dev/docs/learn/string-view). The small `Member` helper makes one from a literal: ```rux func Member(object: &JsonValue, name: char8[..]) -> *JsonValue { return object.Find(StringView::FromValidated(name)); } ``` `Find` answers a [pointer](https://rux-lang.dev/docs/learn/pointer) that is null when there is no such member. So the program checks before reading through it: ```rux let name = Member(root, "name"); if name != null { PrintLine("name {}", (*name).AsText()); } PrintLine("license present: {}", Member(root, "license") != null); ``` The document has no `license`, and the program says so instead of crashing. ## Numbers keep their text JSON has one kind of number, and it does not say how big or how precise a number may be. So a `JsonNumber` keeps the text it was written with, and converting it is a question that may be answered `false` — the text may have a fraction, or not fit the type asked for. The answer comes back through an [out-parameter](https://rux-lang.dev/docs/learn/out-parameter): ```rux var year: int64 = 0; let number = (*Member(root, "year")).AsNumber(); let fits = (*number).AsInt64(@year); PrintLine("year {} (text \"{}\", fits an int64: {})", year, (*number).Text(), fits); ``` `AsNumber` returns a pointer to the number — null if the value were some other kind — and `AsInt64(@year)` writes into `year` and reports whether it could. ## Arrays and nested objects An array is walked by index, and each element is asked its kind like any other value. A nested object is just another value with members of its own: ```rux let tags = Member(root, "tags"); for i in 0..(*tags).Length() { let tag = (*tags).At(i); PrintLine("tags[{}] {} {}", i, KindName((*tag).Kind()), (*tag).AsText()); } var beta = false; let flags = Member(root, "flags"); let isBoolean = (*Member(*flags, "beta")).AsBoolean(@beta); ``` Notice that `year`, `tags` and `flags` are read without the null check that `name` got. That is safe here only because the document is a literal in the program and they are known to be there. For a document from outside, check every pointer. ## Malformed input JSON is strict, and `Parse` refuses anything that is not exactly JSON. The failure says why, and at which byte the parser stopped: | Document | Refused at | Because | | ----------------- | ---------- | ----------------------------------------- | | `[1, 2, 3,]` | byte 10 | a trailing comma: `]` cannot follow `,` | | `{'name': 'Rux'}` | byte 1 | single quotes begin no token in JSON | | `{"open": [1, 2}` | byte 15 | `}` cannot close an array | | `{"a": 1} extra` | byte 9 | text after the end of the document | | *(empty)* | byte 0 | the document ended before any value began | A message that names the byte lets a person go straight to the mistake. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/DataFormats/Json){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // JSON is how programs that share nothing else agree on what a value is. The Json package reads // a document into a tree of `JsonValue`s, and every value in the tree is one of six kinds: text, // number, boolean, null, array or object. // // Parse(allocator, text) -> JsonValue ! JsonParseError // // Parsing hands back a whole document or the reason there is none, never half of one. Reading the // tree then means asking a value what it is before taking it apart: `Find` and `At` answer a // pointer that is null when the member or element is not there, and the conversions answer // `false`, through an out-parameter, when the value is some other kind. import Allocator::{ Allocator, SystemAllocator }; import Io::PrintLine; import Json::{ JsonKind, JsonValue, Parse }; import Text::StringView; func KindName(kind: JsonKind) -> char8[..] { return match kind { JsonKind::Text => "text", JsonKind::Number => "number", JsonKind::Boolean => "boolean", JsonKind::Array => "array", JsonKind::Object => "object", else => "null" }; } // Member names are compared as text, so `Find` takes a `StringView`. func Member(object: &JsonValue, name: char8[..]) -> *JsonValue { return object.Find(StringView::FromValidated(name)); } func Inspect(root: &JsonValue) { PrintLine("root {} of {} members", KindName(root.Kind()), root.Length()); // A member that is not there is a null pointer, so check before reading through it. let name = Member(root, "name"); if name != null { PrintLine("name {}", (*name).AsText()); } PrintLine("license present: {}", Member(root, "license") != null); // A number keeps the text it was written with, and converting it is a question that can // be answered `false`: the text may have a fraction, or not fit the type asked for. var year: int64 = 0; let number = (*Member(root, "year")).AsNumber(); let fits = (*number).AsInt64(@year); PrintLine("year {} (text \"{}\", fits an int64: {})", year, (*number).Text(), fits); // An array is walked by index, and each element is asked its kind like any other value. let tags = Member(root, "tags"); for i in 0..(*tags).Length() { let tag = (*tags).At(i); PrintLine("tags[{}] {} {}", i, KindName((*tag).Kind()), (*tag).AsText()); } // A nested object is just another value with members of its own. var beta = false; let flags = Member(root, "flags"); let isBoolean = (*Member(*flags, "beta")).AsBoolean(@beta); PrintLine("beta boolean: {}, value: {}", isBoolean, beta); } func Check(allocator: Allocator, document: char8[..]) { match Parse(allocator, document) { .Success(root) => PrintLine("{:18} parsed as {}", document, KindName(root.Kind())), .Failure(reason) => PrintLine("{:18} refused at byte {}: {}", document, reason.Offset(), reason) } } func Main() -> int { var system = SystemAllocator(); let allocator: Allocator = system; let document = "{\"name\":\"Rux\",\"year\":2026,\"tags\":[\"fast\",\"small\"],\"flags\":{\"beta\":true}}"; match Parse(allocator, document) { .Success(root) => Inspect(root), .Failure(reason) => PrintLine("refused at byte {}: {}", reason.Offset(), reason) } // Malformed input. The failure says why, and the byte where the parser stopped, so a message // to a person can point at the problem. JSON is strict: no trailing commas, no single quotes. PrintLine(""); Check(allocator, "[1, 2, 3]"); Check(allocator, "[1, 2, 3,]"); Check(allocator, "{'name': 'Rux'}"); Check(allocator, "{\"open\": [1, 2}"); Check(allocator, "{\"a\": 1} extra"); Check(allocator, ""); return 0; } ``` Besides `Io`, its `Rux.toml` lists `Allocator`, `Json` and `Text` under `[Dependencies]`. ## Run it ```sh cd Examples/DataFormats/Json rux run ``` ```text root object of 4 members name Rux license present: false year 2026 (text "2026", fits an int64: true) tags[0] text fast tags[1] text small beta boolean: true, value: true [1, 2, 3] parsed as array [1, 2, 3,] refused at byte 10: token that cannot appear here {'name': 'Rux'} refused at byte 1: byte that begins no token {"open": [1, 2} refused at byte 15: token that cannot appear here {"a": 1} extra refused at byte 9: text after the end of the document refused at byte 0: document ended in the middle of a value ``` ## Common mistakes ::mistake **Looking up a member with a plain literal.**:br`Find` compares names as text, and takes a `StringView`. `object.Find(name)` with a `char8[..]` fails with: ```text error: argument 1 to 'Find' has type 'char8[..]', but parameter 'name' requires 'StringView' ``` Wrap it: `StringView::FromValidated(name)`. :: ::mistake **Passing the variable instead of its address.**:br The conversions write their answer through a pointer. `(*number).AsInt64(year)` fails with: ```text error: argument 1 to 'AsInt64' has type 'int64', but parameter 'result' requires '*var int64' ``` Write `@year`. :: ::mistake **Reading through a missing member.**:br`Find` returns null for a name that is not there, and reading through null crashes the program. `(*Member(root, "license")).AsText()` compiles, and then stops the program dead. Compare the pointer with `null` first, as the program does for `name`. :: ::mistake **Forgetting the allocator.**:br`Parse(document)` fails with: ```text error: call to 'Parse' expects 2 arguments, but 1 was provided ``` The tree's memory has to come from somewhere, and the allocator says where. :: ## Try it yourself 1. Add `"license": null` to the document. Check it with `IsNull()`. 2. Add `"version": 1.5`. What do `AsInt64` and `AsFloat64` each answer for it? 3. Pass `{"a": 1, "a": 2}` to `Check`. JSON does not forbid a repeated name — but what does this parser do with one? 4. List every member of the root object with `MemberAt(i)`, printing each one's `name` and the kind of its `value`. ## Learn more - [JSON write](https://rux-lang.dev/docs/learn/json-write) — building a tree and writing it back out as text - [JSON stream](https://rux-lang.dev/docs/learn/json-stream) — reading a document without building the tree - [Pointer](https://rux-lang.dev/docs/learn/pointer) and [Out-parameter](https://rux-lang.dev/docs/learn/out-parameter) — how `Find`, `At` and the conversions answer - [Allocator](https://rux-lang.dev/docs/learn/allocator) — where the tree's memory comes from - [Null pointers](https://rux-lang.dev/docs/lang/pointers/overview#null) in the Rux Reference # Writing JSON ::note **You'll need**: [JSON](https://rux-lang.dev/docs/learn/json), [String builder](https://rux-lang.dev/docs/learn/string-builder), [Display](https://rux-lang.dev/docs/learn/display), [Move](https://rux-lang.dev/docs/learn/move), [Error sum](https://rux-lang.dev/docs/learn/error-sum) :: Writing JSON is the [parse lesson](https://rux-lang.dev/docs/learn/json) run backwards: a tree of `JsonValue`s goes in, text comes out. The tree can come from `Parse`, or — as here — be built by hand, one value at a time. This lesson builds a small document, writes it two ways, and proves the writing is faithful by reading the output back. ```rux import Json::{ JsonStyle, JsonValue, Parse, WriteValue }; import Text::{ FormatError, String, StringBuilder, TextError, TextWriter }; ``` ## Building a tree by hand Each kind has a constructor: `JsonValue::Text`, `Number`, `Boolean`, `Null`, `Array` and `Object`. Containers start empty; `Push` appends to an array and `Insert` adds a member to an object: ```rux var tags = JsonValue::Array(allocator); tags.Push(JsonValue::Text(allocator, "fast")?); tags.Push(JsonValue::Number(allocator, "2.50")?); var root = JsonValue::Object(allocator); root.Insert(String::FromBytes(allocator, "name")?, JsonValue::Text(allocator, "Rux")?); root.Insert(String::FromBytes(allocator, "quote")?, JsonValue::Text(allocator, "say \"hi\"\n")?); root.Insert(String::FromBytes(allocator, "tags")?, <-tags); root.Insert(String::FromBytes(allocator, "license")?, JsonValue::Null(allocator)); ``` Three things to notice: - **Text is copied into the tree.** `Text`, `Number` and `String::FromBytes` copy their bytes into memory from the allocator, and that can fail with a `TextError` — hence the `?` after each. - **A number is given as text.** `"2.50"` stays `2.50`, exactly as written, the same way a parsed number keeps its text. - **Values are move-only.** A `JsonValue` owns everything under it, so it cannot be copied. `Push` and `Insert` take ownership of what they are given, and handing over the finished `tags` array is an explicit [move](https://rux-lang.dev/docs/learn/move): `<-tags`. After that line `tags` is gone, and the array lives on inside `root`. `Main` returns `! (TextError | FormatError)`, an [error sum](https://rux-lang.dev/docs/learn/error-sum), so `?` can pass on a failure of either kind from building or from writing. ## Writing it out `WriteValue` writes a tree into any `TextWriter`: ```text WriteValue(writer, value, style) -> ! FormatError ``` `Written` points it at a [`StringBuilder`](https://rux-lang.dev/docs/learn/string-builder), so the text can be kept, measured and parsed again, and hands the result back as a `String` the caller owns: ```rux func Written(allocator: Allocator, value: &JsonValue, style: JsonStyle) -> String ! FormatError { var builder = StringBuilder(allocator); let sink: &var TextWriter = builder; WriteValue(sink, value, style)?; return builder.IntoString(); } ``` `JsonStyle` chooses the layout: | Style | Layout | Size of this document | For | | ---------------------- | ------------------------------------ | --------------------- | -------------- | | `JsonStyle::Compact()` | no whitespace at all | 73 bytes | a wire, a file | | `JsonStyle::Pretty()` | one value per line, two-space indent | 103 bytes | a person | Either way the writer escapes exactly what JSON requires inside strings and nothing more: the quote's `"` and its newline come out as `\"` and `\n`. ## The round trip A writer is only trustworthy if what it writes reads back as the same thing. The program parses the pretty text and writes it compact again: ```rux match Parse(allocator, pretty.View().Bytes()) { .Success(again) => { let rewritten = Written(allocator, again, JsonStyle::Compact())?; let original = compact.View(); PrintLine("round trip gives the same text: {}", rewritten.View().Equals(original)); }, .Failure(reason) => PrintLine("the written text did not parse: {}", reason) } ``` ```mermaid flowchart LR tree["Tree built
by hand"] -- "`Compact`" --> c1["compact text"] tree -- "`Pretty`" --> p["pretty text"] p -- "`Parse`" --> tree2["Tree read back"] tree2 -- "`Compact`" --> c2["compact text"] c2 -. "the same bytes as" .-> c1 ``` The layout was only presentation, so the same 73 bytes come back — including `2.50`, which did not become `2.5`, because a number keeps the text it was written with. ## What JSON cannot say JSON has no spelling for NaN or infinity. A number built from the text `"NaN"` is accepted into the tree, but writing it is refused rather than invented: ```rux let notANumber = JsonValue::Number(allocator, "NaN")?; match Written(allocator, notANumber, JsonStyle::Compact()) { .Success(text) => PrintLine("wrote {}", text), .Failure(error) => PrintLine("NaN refused: {}", error) } ``` Printing the `FormatError` with `{}` gives its message, `value out of range for the form requested`. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/DataFormats/JsonWrite){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // Writing JSON is the parse lesson run backwards: a tree of `JsonValue`s goes in, text comes // out. The tree can come from `Parse` or be built by hand, and `WriteValue` writes it into any // `TextWriter` — a StringBuilder here, so the text can be kept and parsed again. // // WriteValue(writer, value, style) -> ! FormatError // // `JsonStyle` chooses the layout. `Compact()` writes no whitespace at all, for a document going // over a wire; `Pretty()` indents by two spaces, for a person. Either way the writer escapes // exactly what JSON requires inside strings, and nothing more. import Allocator::{ Allocator, SystemAllocator }; import Io::PrintLine; import Json::{ JsonStyle, JsonValue, Parse, WriteValue }; import Text::{ FormatError, String, StringBuilder, TextError, TextWriter }; // Writes `value` in `style` and hands the text back as a String the caller owns. func Written(allocator: Allocator, value: &JsonValue, style: JsonStyle) -> String ! FormatError { var builder = StringBuilder(allocator); let sink: &var TextWriter = builder; WriteValue(sink, value, style)?; return builder.IntoString(); } func Main() -> ! (TextError | FormatError) { var system = SystemAllocator(); let allocator: Allocator = system; // Building by hand. Values are move-only: `Push` and `Insert` take ownership of what they // are given, and a member's name is an owned String. var tags = JsonValue::Array(allocator); tags.Push(JsonValue::Text(allocator, "fast")?); tags.Push(JsonValue::Number(allocator, "2.50")?); var root = JsonValue::Object(allocator); root.Insert(String::FromBytes(allocator, "name")?, JsonValue::Text(allocator, "Rux")?); root.Insert(String::FromBytes(allocator, "quote")?, JsonValue::Text(allocator, "say \"hi\"\n")?); root.Insert(String::FromBytes(allocator, "tags")?, <-tags); root.Insert(String::FromBytes(allocator, "license")?, JsonValue::Null(allocator)); let compact = Written(allocator, root, JsonStyle::Compact())?; let pretty = Written(allocator, root, JsonStyle::Pretty())?; PrintLine("compact, {} bytes:\n{}", compact.Length(), compact); PrintLine("pretty, {} bytes:\n{}", pretty.Length(), pretty); // The round trip: parse the pretty text and write it compact again. The layout was only // presentation, so the same bytes come back. A number keeps the text it was written with, // which is why `2.50` did not become `2.5`. match Parse(allocator, pretty.View().Bytes()) { .Success(again) => { let rewritten = Written(allocator, again, JsonStyle::Compact())?; let original = compact.View(); PrintLine("round trip gives the same text: {}", rewritten.View().Equals(original)); }, .Failure(reason) => PrintLine("the written text did not parse: {}", reason) } // JSON cannot spell NaN or infinity, so writing one is refused, not invented. let notANumber = JsonValue::Number(allocator, "NaN")?; match Written(allocator, notANumber, JsonStyle::Compact()) { .Success(text) => PrintLine("wrote {}", text), .Failure(error) => PrintLine("NaN refused: {}", error) } } ``` Besides `Io`, its `Rux.toml` lists `Allocator`, `Json` and `Text` under `[Dependencies]`. ## Run it ```sh cd Examples/DataFormats/JsonWrite rux run ``` ```text compact, 73 bytes: {"name":"Rux","quote":"say \"hi\"\n","tags":["fast",2.50],"license":null} pretty, 103 bytes: { "name": "Rux", "quote": "say \"hi\"\n", "tags": [ "fast", 2.50 ], "license": null } round trip gives the same text: true NaN refused: value out of range for the form requested ``` ## Common mistakes ::mistake **Using a value after handing it over.**:br After `root.Insert(…, <-tags)`, the array belongs to `root`. A later `tags.Push(…)` fails with: ```text error: value 'tags' is used after it was moved ``` Finish filling a container before you insert it. :: ::mistake **Inserting without `<-`.**:br`root.Insert(String::FromBytes(allocator, "tags")?, tags)` fails with: ```text error: move-only value 'tags' requires an explicit '<-' in argument ``` A note explains: ```text 'JsonValue' prohibits copying ``` The `<-` makes the hand-over visible where it happens. :: ::mistake **A literal as a member name.**:br`Insert` takes an owned `String`. `root.Insert("name", …)` fails with: ```text error: argument 1 to 'Insert' has type 'char8[..]', but parameter 'name' requires 'String' ``` Make one with `String::FromBytes(allocator, "name")?`. :: ::mistake **Expecting `Insert` to replace.**:br`Insert` always appends, even when the object already has a member of that name — it returns `true` and the writer writes the name twice. Parsing that text back fails with: ```text object with the same name twice ``` Check with `Find` before inserting. :: ## Try it yourself 1. Add a boolean member, `"beta": true`, with `JsonValue::Boolean(allocator, true)`. How many bytes is the compact text now? 2. Build a nested object — say `"author": {"name": "Ada"}` — and look at how `Pretty()` indents it. 3. Try `"Infinity"` instead of `"NaN"`. Is it refused too? 4. Parse the document from the [JSON lesson](https://rux-lang.dev/docs/learn/json) and write it out with `Pretty()`. ## Learn more - [JSON](https://rux-lang.dev/docs/learn/json) — reading a document into the tree this lesson writes - [Move](https://rux-lang.dev/docs/learn/move) — what `<-` does, and why a `JsonValue` cannot be copied - [String builder](https://rux-lang.dev/docs/learn/string-builder) — the `TextWriter` that collects the text - [Error sum](https://rux-lang.dev/docs/learn/error-sum) — one fallible `Main` for two kinds of error - [Notes](https://rux-lang.dev/docs/learn/notes) — a checkpoint project that saves a to-do list as JSON and loads it back # Streaming JSON ::note **You'll need**: [JSON](https://rux-lang.dev/docs/learn/json), [Interface value](https://rux-lang.dev/docs/learn/interface-value), [Destructor](https://rux-lang.dev/docs/learn/destructor), [Error sum](https://rux-lang.dev/docs/learn/error-sum), [Typed pattern](https://rux-lang.dev/docs/learn/typed-pattern), [Coalesce](https://rux-lang.dev/docs/learn/coalesce) :: `Parse` builds the whole tree before your program sees any of it. For a settings file that is ideal. For a log of a million records it is not: the tree costs several times the document's size in memory, and a program that only wants one field from each record pays for all of them. `JsonEventReader` reads the same text as a **stream of events** instead — an object opened, a name, a text value, an array closed — pulling bytes from a source as it needs them and keeping only the token it is on. The program keeps whatever it wants and lets the rest go by. This lesson prints the title of every book in a catalogue without ever building a tree. ```rux import Io::{ IoError, IoErrorKind, PrintLine, Reader }; import Json::{ JsonEvent, JsonEventReader, JsonLimits, JsonParseError }; ``` ## A source of bytes The event reader reads from any `Reader` — the interface that files and network connections implement. The lesson stands one in with `TextSource`, which serves a string at most 8 bytes per read, so tokens arrive split across reads just as they would from a real stream: ```rux struct TextSource { text: char8[..]; offset: uint; } ``` Its `Read` method copies up to 8 bytes into the buffer it is given and reports how many, or fails with `EndOfStream` when nothing is left. Inside `Titles`, the source is handed over as an [interface value](https://rux-lang.dev/docs/learn/interface-value) and the reader is built on it: ```rux let source: Reader = TextSource { text: document, offset: 0 }; var reader = JsonEventReader::New(allocator, source, JsonLimits::Default())?; ``` `New` allocates the reader's buffer, and fails with an `IoError` if it cannot. `JsonLimits::Default()` sets the limits a document must stay within — its size, the length of one string, how deeply it nests — generous for ordinary documents and well short of what would exhaust the machine. ## Events Each call to `Next()` returns the next `JsonEvent`, and `Depth()` says how many arrays and objects are open. The first book of the catalogue produces: | Token | Event | `Depth()` | `Text()` | | --------- | ------------- | --------- | -------- | | `[` | `ArrayStart` | 1 | | | `{` | `ObjectStart` | 2 | | | `"title"` | `Name` | 2 | `title` | | `"Dune"` | `Text` | 2 | `Dune` | | `"year"` | `Name` | 2 | `year` | | `1965` | `Number` | 2 | `1965` | | `}` | `ObjectEnd` | 1 | | …and at the very end, `ArrayEnd` and then `End`. Commas and colons produce no events; `True`, `False` and `Null` complete the set, and `Error` means the document went wrong. ## The loop `Titles` asks for events until `End`, counts each object one level inside the top-level array as a book, and prints the text that follows a `title` name: ```rux var books: uint = 0; var wantTitle = false; var event = reader.Next(); while event != JsonEvent::End { if event == JsonEvent::Error { // After an `Error` event `Failure()` always holds the reason; the fallback is // only there because the type allows `none`. fail reader.Failure() ?? JsonParseError::Unexpected(0); } // Each book is an object one level inside the top-level array. if event == JsonEvent::ObjectStart && reader.Depth() == 2 { books += 1; } // Print the title now: its text is gone once `Next()` is called again. if event == JsonEvent::Text && wantTitle { PrintLine(" title: {}", reader.Text()); } wantTitle = event == JsonEvent::Name && IsTitle(reader.Text()); event = reader.Next(); } return books; ``` Order inside a book does not matter: Emma's `year` comes before its `title`, and the title is still found, because the program reacts to whatever name it meets. ## Two jobs that move onto the program Streaming saves memory by keeping almost nothing, and that hands two jobs to the program. **Lifetimes.** `Text()` borrows the reader's buffer, and the next `Next()` reuses it. So the text of an event must be used — or copied — before asking for another. That is why the title is printed the moment it arrives, and why `wantTitle` remembers only a `bool`, not the name's text. The buffer itself belongs to the reader, and the reader's [destructor](https://rux-lang.dev/docs/learn/destructor) gives it back however `Titles` ends: at the `return`, or at an early `fail`. **Errors arrive late.** A stream cannot know that the end of a document is wrong until it gets there. When it does, `Next()` returns `Error`, and `Failure()` says why and at which byte of the whole document — however it was split into reads. By then the earlier events have already been delivered: ```mermaid flowchart LR n["`Next()`"] --> e{"Event?"} e -- "`ObjectStart`, `Name`,
`Text`, …" --> use["use it now"] --> n e -- "`End`" --> ok(["`books`"]) e -- "`Error`" --> f(["fail `reader.Failure()`"]) ``` In the output, both broken catalogues print their titles *before* being refused. A program that streams must be ready to discover, late, that its input was bad — and must not have committed anything it cannot take back. ## Two kinds of failure `Titles` returns `uint ! (IoError | JsonParseError)`: the reader could not start, or the document was wrong. `Report` takes them apart with [typed patterns](https://rux-lang.dev/docs/learn/typed-pattern): ```rux match Titles(allocator, document) { .Success(books) => PrintLine(" {} books", books), .Failure(error) => match error { reason: JsonParseError => PrintLine(" refused at byte {}: {}", reason.Offset(), reason), _: IoError => PrintLine(" could not start reading") } } ``` A source that fails partway through is reported as `JsonParseError::Source`, with the source's own `IoError` kept on the reader by `SourceError()`. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/DataFormats/JsonStream){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // `Parse` builds the whole tree before a program sees any of it, so a large document costs its // size several times over in memory. `JsonEventReader` reads the same text as a stream of // events instead — an object opened, a name, a text value, an array closed — pulling bytes from // a `Reader` as it needs them and keeping only the token it is on. The program keeps whatever it // wants and lets the rest go by. // // Streaming moves two jobs onto the program: // // - Lifetimes. `Text()` borrows the reader's buffer, which the next `Next()` reuses, so the text // of an event must be used or copied before asking for another. The reader owns that buffer, // and its destructor gives it back however the function holding it ends. // - Errors. `Next()` answers `JsonEvent::Error` when the document goes wrong, and `Failure()` // then says why and at which byte of the whole document, however it was split into reads. // A source that fails is reported as `JsonParseError::Source`, its own `IoError` kept by // `SourceError()`. Events before the mistake were already delivered, so a program must be // ready to find out late that its input was bad. import Allocator::{ Allocator, SystemAllocator }; import Io::{ IoError, IoErrorKind, PrintLine, Reader }; import Json::{ JsonEvent, JsonEventReader, JsonLimits, JsonParseError }; import Text::StringView; // Stands in for a file or a socket: serves its text at most 8 bytes per read, so tokens arrive // split across reads, as they would from a real stream. struct TextSource { text: char8[..]; offset: uint; } extend TextSource : Reader { func Read(self: &var TextSource, into: var char8[..]) -> uint ! IoError { let remaining = self.text.length - self.offset; if remaining == 0 { fail IoError::Of(IoErrorKind::EndOfStream); } var count: uint = 8; if remaining < count { count = remaining; } if into.length < count { count = into.length; } for i in 0..count { into[i] = self.text[self.offset + i]; } self.offset += count; return count; } } func IsTitle(text: char8[..]) -> bool { let title = StringView::FromValidated("title"); return StringView::FromValidated(text).Equals(title); } // Prints the title of every book and counts the books, without ever building a tree. func Titles(allocator: Allocator, document: char8[..]) -> uint ! (IoError | JsonParseError) { let source: Reader = TextSource { text: document, offset: 0 }; // The reader's buffer lives as long as `reader` does. Whether this function ends at the // `return` or at an early `fail`, the destructor frees it on the way out. var reader = JsonEventReader::New(allocator, source, JsonLimits::Default())?; var books: uint = 0; var wantTitle = false; var event = reader.Next(); while event != JsonEvent::End { if event == JsonEvent::Error { // After an `Error` event `Failure()` always holds the reason; the fallback is // only there because the type allows `none`. fail reader.Failure() ?? JsonParseError::Unexpected(0); } // Each book is an object one level inside the top-level array. if event == JsonEvent::ObjectStart && reader.Depth() == 2 { books += 1; } // Print the title now: its text is gone once `Next()` is called again. if event == JsonEvent::Text && wantTitle { PrintLine(" title: {}", reader.Text()); } wantTitle = event == JsonEvent::Name && IsTitle(reader.Text()); event = reader.Next(); } return books; } func Report(allocator: Allocator, document: char8[..]) { PrintLine("{}", document); match Titles(allocator, document) { .Success(books) => PrintLine(" {} books", books), .Failure(error) => match error { reason: JsonParseError => PrintLine(" refused at byte {}: {}", reason.Offset(), reason), _: IoError => PrintLine(" could not start reading") } } } func Main() -> int { var system = SystemAllocator(); let allocator: Allocator = system; let catalog = "[{\"title\": \"Dune\", \"year\": 1965}, {\"year\": 1815, \"title\": \"Emma\"}]"; Report(allocator, catalog); // Two broken documents. In both, titles were printed before the mistake was found: a // stream cannot know the end is wrong until it gets there. Report(allocator, "[{\"title\": \"Dune\"}, {\"title\": \"Emma\"]"); Report(allocator, "[{\"title\": \"Dune\"}, {\"title\":"); return 0; } ``` Besides `Io`, its `Rux.toml` lists `Allocator`, `Json` and `Text` under `[Dependencies]`. ## Run it ```sh cd Examples/DataFormats/JsonStream rux run ``` ```text [{"title": "Dune", "year": 1965}, {"year": 1815, "title": "Emma"}] title: Dune title: Emma 2 books [{"title": "Dune"}, {"title": "Emma"] title: Dune title: Emma refused at byte 36: token that cannot appear here [{"title": "Dune"}, {"title": title: Dune refused at byte 29: document ended in the middle of a value ``` ## Common mistakes ::mistake **Not checking for `Error`.**:br Once a document has gone wrong, `Next()` returns `Error` on every call, and never `End`. Leave out the `if event == JsonEvent::Error` check and the loop for the first broken catalogue prints its titles and then runs forever. :: ::mistake **Keeping an event's text.**:br The `char8[..]` from `Text()` points into the reader's buffer, which the next `Next()` overwrites. Use it straight away, or copy it into a `String` you own. :: ::mistake **A reader declared with `let`.**:br Reading advances the reader, so `Next()` needs it mutable. With `let reader = …` the call fails with: ```text error: cannot call 'Next' on immutable 'reader' ``` The help says: ```text declare 'reader' with 'var' to make it mutable ``` :: ::mistake **Handling only the error you expect.**:br The failure is a sum of two types, and the `match` must cover both. Without the `IoError` arm it fails with: ```text error: match on 'IoError | JsonParseError' is not exhaustive; missing _: IoError ``` :: ## Try it yourself 1. Print each book's year as well: react to a `Number` event that follows a `year` name. 2. Change `TextSource` to serve one byte per read. Does any line of the output change — including the byte offsets? 3. Add a third book that has no title. Does the count still include it? 4. Count how many events the first catalogue produces in all, `End` excluded. ## Learn more - [JSON](https://rux-lang.dev/docs/learn/json) — the tree parser, for documents small enough to hold at once - [Interface value](https://rux-lang.dev/docs/learn/interface-value) — how `TextSource` becomes a `Reader` - [Destructor](https://rux-lang.dev/docs/learn/destructor) — how the reader's buffer is returned on every path - [Error sum](https://rux-lang.dev/docs/learn/error-sum) and [Typed pattern](https://rux-lang.dev/docs/learn/typed-pattern) — the two-kind failure and how `Report` splits it - [Buffered I/O](https://rux-lang.dev/docs/learn/buffered-io) — reading a real file a block at a time # TOML ::note **You'll need**: [JSON](https://rux-lang.dev/docs/learn/json), [String builder](https://rux-lang.dev/docs/learn/string-builder), [Date](https://rux-lang.dev/docs/learn/date), [Fallible main](https://rux-lang.dev/docs/learn/fallible-main) :: TOML is a configuration format — the one every `Rux.toml` in this course is written in. It is made for people to write by hand: one `key = value` per line, comments with `#`, and `[name]` to open a section. And unlike JSON, its values have real types. An integer is not a float even when the float is whole, and a date is a date, not a string that happens to look like one. This lesson reads a small settings document with the `Toml` package. Reading the result works the same way as in [JSON](https://rux-lang.dev/docs/learn/json): find a key, ask what kind of value it holds, take it out. ```rux import Text::{ String, StringBuilder, StringView, TextError }; import Time::Date; import Toml::{ TomlParse, TomlValue }; ``` ## The document TOML is line-based, so the program writes the document as one literal per line: ```rux let good: char8[..][8] = [ "name = \"Rux\"", "released = 2026-10-04", "", "[server]", "port = 8080", "ratio = 0.75", "tags = [\"web\", \"api\"]", "# A comment, which the parser skips." ]; let document = Lines(allocator, good)?; ``` and `Lines` joins them, each followed by a newline, with a [`StringBuilder`](https://rux-lang.dev/docs/learn/string-builder). Unescaped, the text it builds is: ```toml name = "Rux" released = 2026-10-04 [server] port = 8080 ratio = 0.75 tags = ["web", "api"] # A comment, which the parser skips. ``` `name` and `released` belong to the top-level table; `[server]` opens a nested table that holds the rest. Joining can fail — the builder needs memory — so `Lines` returns `String ! TextError`, and `Main` is a [fallible `Main`](https://rux-lang.dev/docs/learn/fallible-main), `func Main() -> ! TextError`, so that `?` can pass the failure on. ## Parsing ```text TomlParse(allocator, text) -> TomlValue ! TomlParseFailure ``` The result is the top-level table as a `TomlValue` tree, or no tree at all — only the reason, and where it was found: ```rux func Load(allocator: Allocator, text: char8[..]) { match TomlParse(allocator, text) { .Success(root) => Inspect(root), .Failure(failure) => PrintLine("refused at line {}, column {}: {}", failure.line, failure.column, failure) } } ``` A TOML document is written in lines, so a `TomlParseFailure` reports a line and a column rather than only a byte — the place a person would look in an editor. `Load` takes a `char8[..]`, so the `String` from `Lines` is passed as `document.View().Bytes()`. ## Reading values `Key` looks a key up in a table. Like JSON's `Find`, it answers a pointer that is null when the key is missing: ```rux func Key(table: &TomlValue, key: char8[..]) -> *TomlValue { return table.Find(StringView::FromValidated(key)); } ``` Each kind has its own question, answered through an out-parameter, and each answers only for its own kind: ```rux let server = Key(root, "server"); var port: int64 = 0; var ratio = 0.0; let portIsInteger = (*Key(*server, "port")).AsInteger(@port); let portIsFloat = (*Key(*server, "port")).AsFloat(@ratio); PrintLine("port {} (integer: {}, float: {})", port, portIsInteger, portIsFloat); ``` `8080` is an integer, so `AsInteger` says `true` and `AsFloat` says `false`. In JSON both would be "a number"; in TOML the spelling decides the type, and `8080.0` would be a float. | TOML value | Kind | Read with | | ------------------- | ---------- | -------------------------------- | | `"Rux"`, `'Rux'` | text | `AsText()` | | `8080`, `0x1F90` | integer | `AsInteger(@x)`, into an `int64` | | `0.75`, `8080.0` | float | `AsFloat(@x)`, into a `float64` | | `true` | boolean | `AsBoolean(@x)` | | `2026-10-04` | local date | `AsDate(@x)`, into a `Date` | | `["web", "api"]` | array | `Length()`, `At(i)` | | `[server]`, `{ … }` | table | `Find(key)`, `Length()` | A date comes out as the `Date` from the [Date](https://rux-lang.dev/docs/learn/date) lesson, ready to compare or do arithmetic on: ```rux var released = Date { year: 1970, month: 1, day: 1 }; (*Key(root, "released")).AsDate(@released); PrintLine("released {}", released); ``` Arrays are walked by index, and a key that is not there is simply a null pointer: ```rux let tags = Key(*server, "tags"); for i in 0..(*tags).Length() { PrintLine("tags[{}] {}", i, (*(*tags).At(i)).AsText()); } PrintLine("debug present: {}", Key(*server, "debug") != null); ``` ## Refusals ```rux let twice: char8[..][3] = ["[server]", "port = 8080", "port = 9090"]; let repeated = Lines(allocator, twice)?; Load(allocator, repeated.View().Bytes()); Load(allocator, "released = 2026-13-04"); ``` In TOML a key given twice in one table is an **error**, not a quiet overwrite — two values for one setting is almost always a mistake, and refusing it is the only way to make sure nobody acts on the wrong one. And a value must be spelled the way its type is: `2026-13-04` is shaped like a date, but there is no thirteenth month, so it is not the shape TOML defines for any value. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/DataFormats/Toml){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // TOML is a configuration format — the one every `Rux.toml` in this course is written in. A // document is a table of keys and values, `[name]` opens a nested table, and unlike JSON the // values have real types: an integer is not a float even when the float is whole, and a date is // a date rather than a string that looks like one. // // TomlParse(allocator, text) -> TomlValue ! TomlParseFailure // // The result is a `TomlValue` tree, read the same way as a JSON one: `Find` answers a pointer // that is null when the key is missing, and `AsInteger`, `AsFloat`, `AsDate` and the rest // answer `false` when the value is some other kind. A refused document gives no tree at all, // only the reason and where it was found, by line and column. import Allocator::{ Allocator, SystemAllocator }; import Io::PrintLine; import Text::{ String, StringBuilder, StringView, TextError }; import Time::Date; import Toml::{ TomlParse, TomlValue }; // A TOML document is lines, so it is written here one literal per line and joined. func Lines(allocator: Allocator, lines: char8[..][..]) -> String ! TextError { var builder = StringBuilder(allocator); for i in 0..lines.length { builder.Append(lines[i])?; builder.Append("\n")?; } return builder.IntoString(); } func Key(table: &TomlValue, key: char8[..]) -> *TomlValue { return table.Find(StringView::FromValidated(key)); } func Inspect(root: &TomlValue) { PrintLine("name {}", (*Key(root, "name")).AsText()); // The same question asked of an integer and a float. Each answers only its own kind. let server = Key(root, "server"); var port: int64 = 0; var ratio = 0.0; let portIsInteger = (*Key(*server, "port")).AsInteger(@port); let portIsFloat = (*Key(*server, "port")).AsFloat(@ratio); PrintLine("port {} (integer: {}, float: {})", port, portIsInteger, portIsFloat); (*Key(*server, "ratio")).AsFloat(@ratio); PrintLine("ratio {}", ratio); var released = Date { year: 1970, month: 1, day: 1 }; (*Key(root, "released")).AsDate(@released); PrintLine("released {}", released); let tags = Key(*server, "tags"); for i in 0..(*tags).Length() { PrintLine("tags[{}] {}", i, (*(*tags).At(i)).AsText()); } PrintLine("debug present: {}", Key(*server, "debug") != null); } func Load(allocator: Allocator, text: char8[..]) { match TomlParse(allocator, text) { .Success(root) => Inspect(root), .Failure(failure) => PrintLine("refused at line {}, column {}: {}", failure.line, failure.column, failure) } } func Main() -> ! TextError { var system = SystemAllocator(); let allocator: Allocator = system; let good: char8[..][8] = [ "name = \"Rux\"", "released = 2026-10-04", "", "[server]", "port = 8080", "ratio = 0.75", "tags = [\"web\", \"api\"]", "# A comment, which the parser skips." ]; let document = Lines(allocator, good)?; Load(allocator, document.View().Bytes()); // Two refusals. A key given twice in one table is an error in TOML, not a quiet overwrite, // and a value must be spelled the way its type is: there is no thirteenth month. PrintLine(""); let twice: char8[..][3] = ["[server]", "port = 8080", "port = 9090"]; let repeated = Lines(allocator, twice)?; Load(allocator, repeated.View().Bytes()); Load(allocator, "released = 2026-13-04"); } ``` Besides `Io`, its `Rux.toml` lists `Allocator`, `Text`, `Time` and `Toml` under `[Dependencies]`. ## Run it ```sh cd Examples/DataFormats/Toml rux run ``` ```text name Rux port 8080 (integer: true, float: false) ratio 0.75 released 2026-10-04 tags[0] web tags[1] api debug present: false refused at line 3, column 12: key given a value twice in the same table refused at line 1, column 17: not the shape TOML defines ``` ## Common mistakes ::mistake **Ignoring the answer of `AsInteger`.**:br The out-parameter is written only when the answer is `true`. Change `port = 8080` to `port = 8080.0` and the program prints: ```text port 0 (integer: false, float: true) ``` The value is a float now, and `port` kept its starting value. Check what the conversion answers before using the result. :: ::mistake **Passing a `String` where text is wanted.**:br`Load` and `TomlParse` take a `char8[..]`. `Load(allocator, document)` fails with: ```text error: argument 2 to 'Load' has type 'String', but parameter 'text' requires 'char8[..]' ``` Pass `document.View().Bytes()`. :: ::mistake **A pointer where a reference is wanted.**:br`Key` answers a pointer, but takes its table as a reference. `Key(server, "tags")` fails with: ```text error: argument 1 to 'Key' has type '*TomlValue', but parameter 'table' requires '&TomlValue' ``` Dereference it: `Key(*server, "tags")`. :: ::mistake **Reading through a missing key.**:br`Key` returns null for a key that is not there, and reading through null crashes the program. The lesson reads `server`, `port` and the rest unchecked only because its document is fixed; for a real configuration file, check each pointer — or treat a missing key as "use the default". :: ## Try it yourself 1. Write the port in hexadecimal, `port = 0x1F90`. What does `AsInteger` read? 2. Add `debug = true` to the `[server]` table and read it with `AsBoolean`. (The array's length, `[8]`, has to grow too.) 3. Open `[server]` a second time further down the document. Is that refused like a repeated key? 4. Add a key with a value of your own and read it back. Then change the spelling of its value so the parser refuses it, and read the line and column. ## Learn more - [JSON](https://rux-lang.dev/docs/learn/json) — the same way of reading a tree, for a format without types - [TOML write](https://rux-lang.dev/docs/learn/toml-write) — changing the tree and writing it back - [Date](https://rux-lang.dev/docs/learn/date) — the type `AsDate` fills in - [Fallible main](https://rux-lang.dev/docs/learn/fallible-main) — `Main` returning `! TextError` - [Manifest](https://rux-lang.dev/docs/packaging/manifest) — the `Rux.toml` file, the TOML you write most often # Writing TOML ::note **You'll need**: [TOML](https://rux-lang.dev/docs/learn/toml), [Writing JSON](https://rux-lang.dev/docs/learn/json-write), [Error sum](https://rux-lang.dev/docs/learn/error-sum) :: Reading a configuration file is half the job; a program that changes its own settings has to write the file back. `TomlWriteDocument` turns a `TomlValue` table into TOML text, the way `WriteValue` did for JSON in [JSON write](https://rux-lang.dev/docs/learn/json-write): ```text TomlWriteDocument(writer, table) -> ! FormatError ``` This lesson reads a document a person wrote, adds a key, writes it back, and looks closely at what the trip through the tree keeps and what it loses. ```rux import Text::{ FormatError, String, StringBuilder, StringView, TextError, TextWriter }; import Toml::{ TomlParse, TomlParseFailure, TomlValue, TomlWriteDocument }; ``` ## A document as a person writes it ```rux let lines: char8[..][6] = [ "# Settings for the demo server", "name = 'Rux' # a literal string", "mask = 0xFF", "server = { host = \"localhost\", port = 8080 }", "", "tags = [\"web\", \"api\"]" ]; let text = Lines(allocator, lines)?; PrintLine("read:\n{}", text); var root = TomlParse(allocator, text.View().Bytes())?; ``` It has everything a hand-written file collects: a comment on a line of its own and another after a value, a `'literal string'` in single quotes, a number in hexadecimal, an *inline table* in braces, and a blank line. `Main` returns `! (TextError | FormatError | TomlParseFailure)` — an [error sum](https://rux-lang.dev/docs/learn/error-sum) of the three things that can go wrong: building text, writing it, and parsing it. So every step here can use `?`, including the parse. ## Changing the tree To change a table, borrow it for changing. `FindMutable` is `Find`'s writable twin: it answers a `*var TomlValue`, and `Insert` adds a key and value to the table it points at, taking ownership of both: ```rux let server = root.FindMutable(StringView::FromValidated("server")); (*server).Insert(String::FromBytes(allocator, "debug")?, TomlValue::Boolean(allocator, true)); ``` `root` itself is declared `var`, because borrowing part of it for changing changes it. ## Writing it back `Written` is the same shape as in JSON write: a `StringBuilder` collects the text, and the caller gets it as a `String`: ```rux func Written(allocator: Allocator, table: &TomlValue) -> String ! FormatError { var builder = StringBuilder(allocator); let sink: &var TextWriter = builder; TomlWriteDocument(sink, table)?; return builder.IntoString(); } ``` ## What survives the trip The parser keeps **values, not spelling**. So writing a parsed document back gives an equivalent document, not the same file: | Read | Written | | ---------------------------------------------- | ------------------------------------------------ | | `# Settings for the demo server` | gone — comments are not values | | `name = 'Rux' # a literal string` | `name = "Rux"` — an ordinary string, no comment | | `mask = 0xFF` | `mask = 255` — the number, in decimal | | `server = { host = "localhost", port = 8080 }` | a `[server]` section, written last | | the blank line | gone; one blank line now comes before `[server]` | | `tags = ["web", "api"]` | unchanged, but now before `[server]` | The inline table moved because TOML requires it: once a `[header]` opens a section, every following `key = value` belongs to that section, so the plain keys of a table must be written before any of its sections. What does survive is every key, every value, and their order within each table — `debug` appears after `host` and `port`, where it was inserted. ## Writing is stable The writer is **deterministic**: the same tree always writes the same bytes. So write, read the output back, write again — and the second text is the first one exactly: ```rux let again = TomlParse(allocator, once.View().Bytes())?; let twice = Written(allocator, again)?; let first = once.View(); PrintLine("written twice, same text: {}", twice.View().Equals(first)); ``` ```mermaid flowchart LR hand["hand-written text"] -- "`TomlParse`" --> t1["tree"] t1 -- "`Insert` `debug`" --> t1b["changed tree"] t1b -- "`TomlWriteDocument`" --> once["once"] once -- "`TomlParse`" --> t2["tree"] t2 -- "`TomlWriteDocument`" --> twice["twice"] twice -. "`Equals`: `true`" .-> once ``` The first trip normalises the file; after that nothing moves. That matters for a program that saves its settings every time it runs: the file changes when a setting does, and not otherwise. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/DataFormats/TomlWrite){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // `TomlWriteDocument` turns a `TomlValue` table back into TOML text, written into any // `TextWriter`: // // TomlWriteDocument(writer, table) -> ! FormatError // // The parser keeps values, not spelling, so writing a parsed document back gives an equivalent // document rather than the same file. Comments and blank lines are gone, `0xFF` becomes `255`, // a literal string becomes an ordinary one and an inline table becomes a `[header]` section, // written after the plain keys because TOML requires it. What does survive is every key, every // value, and their order within each table. And the writer is deterministic: the same tree // always writes the same bytes, so write, read and write again, and the second text is the // first one exactly. import Allocator::{ Allocator, SystemAllocator }; import Io::PrintLine; import Text::{ FormatError, String, StringBuilder, StringView, TextError, TextWriter }; import Toml::{ TomlParse, TomlParseFailure, TomlValue, TomlWriteDocument }; func Lines(allocator: Allocator, lines: char8[..][..]) -> String ! TextError { var builder = StringBuilder(allocator); for i in 0..lines.length { builder.Append(lines[i])?; builder.Append("\n")?; } return builder.IntoString(); } // Writes `table` as TOML and hands the text back as a String the caller owns. func Written(allocator: Allocator, table: &TomlValue) -> String ! FormatError { var builder = StringBuilder(allocator); let sink: &var TextWriter = builder; TomlWriteDocument(sink, table)?; return builder.IntoString(); } func Main() -> ! (TextError | FormatError | TomlParseFailure) { var system = SystemAllocator(); let allocator: Allocator = system; // A document as a person might write it. let lines: char8[..][6] = [ "# Settings for the demo server", "name = 'Rux' # a literal string", "mask = 0xFF", "server = { host = \"localhost\", port = 8080 }", "", "tags = [\"web\", \"api\"]" ]; let text = Lines(allocator, lines)?; PrintLine("read:\n{}", text); var root = TomlParse(allocator, text.View().Bytes())?; // Change the tree before writing it. `FindMutable` lends a table for changing, and // `Insert` takes ownership of a new key and value. let server = root.FindMutable(StringView::FromValidated("server")); (*server).Insert(String::FromBytes(allocator, "debug")?, TomlValue::Boolean(allocator, true)); let once = Written(allocator, root)?; PrintLine("written:\n{}", once); // Read the output back and write it again: nothing moves the second time. let again = TomlParse(allocator, once.View().Bytes())?; let twice = Written(allocator, again)?; let first = once.View(); PrintLine("written twice, same text: {}", twice.View().Equals(first)); } ``` Besides `Io`, its `Rux.toml` lists `Allocator`, `Text` and `Toml` under `[Dependencies]`. ## Run it ```sh cd Examples/DataFormats/TomlWrite rux run ``` ```text read: # Settings for the demo server name = 'Rux' # a literal string mask = 0xFF server = { host = "localhost", port = 8080 } tags = ["web", "api"] written: name = "Rux" mask = 255 tags = ["web", "api"] [server] host = "localhost" port = 8080 debug = true written twice, same text: true ``` ## Common mistakes ::mistake **Looking up a table with `Find` to change it.**:br`Find` lends the table read-only. `root.Find(…)` followed by `(*server).Insert(…)` fails with: ```text error: cannot call 'Insert' on an immutable receiver ``` Use `FindMutable`. :: ::mistake **A parsed document declared with `let`.**:br`let root = TomlParse(…)?;` and then `root.FindMutable(…)` fails with: ```text error: cannot call 'FindMutable' on immutable 'root' ``` A tree you mean to change must be a `var`. :: ::mistake **Expecting `Insert` to replace a value.**:br`Insert` always appends, even when the table already has that key. Insert a second `port` and the writer writes `port` twice; reading that text back is refused, because a repeated key is an error in TOML — so this program's `?` ends `Main` with status 1. Check with `Find` before inserting. :: ::mistake **Rewriting a file a person maintains.**:br Comments, blank lines and the spelling of values do not survive. That is fine for a file only the program writes, and a nasty surprise in one a person has annotated. Write such settings to a separate file, or leave the person's file alone. :: ## Try it yourself 1. Insert a top-level key, `version = 2`, with `TomlValue::Integer(allocator, 2)`. Where in the output does it land, and why there? 2. Write the mask in binary instead: `mask = 0b1111_1111`. What does the written text say? 3. Add a comment after `tags`. Is any trace of it left in the output? 4. In the tree `again`, find `server` and read `debug` back with `AsBoolean`. Did the value survive the trip as a boolean? ## Learn more - [TOML](https://rux-lang.dev/docs/learn/toml) — reading values out of the tree this lesson writes - [JSON write](https://rux-lang.dev/docs/learn/json-write) — the same writer pattern for JSON - [Error sum](https://rux-lang.dev/docs/learn/error-sum) — `Main` failing with one of three error types - [Atomic file](https://rux-lang.dev/docs/learn/atomic-file) — saving the written text so a crash cannot leave half a file # Base64 and friends ::note **You'll need**: [Writable slice](https://rux-lang.dev/docs/learn/writable-slice), [Outcome](https://rux-lang.dev/docs/learn/outcome), [Catch fallback](https://rux-lang.dev/docs/learn/catch-fallback), [Encoding](https://rux-lang.dev/docs/learn/encoding) :: JSON, TOML, URLs, e-mail and HTTP headers all carry **text**. A key, a hash, a signature or a small image is **bytes**, any of the 256 values, most of which are not printable characters at all. To send bytes through a text format, you write them with a small alphabet of safe characters, and read them back exactly at the other end. That is a **base encoding**, and the `Encoding` package has the four you will meet: ```rux import Encoding::{ Base32Encode, Base32Variant, Base58Encode, Base58EncodedMaxLength, Base64Decode, Base64Encode, Base64EncodedLength, Base64Variant, HexDecode, HexEncode, ViewHex }; ``` ::note **Not the Encoding lesson.**:br[Encoding](https://rux-lang.dev/docs/learn/encoding) in Part 14 is about *character* encodings — how text is stored as UTF-8 or UTF-16 bytes. This lesson goes the other way: any bytes at all become plain ASCII text. The package happens to be called `Encoding` too. :: ## Four alphabets Each scheme splits the bytes into groups of bits and writes each group as one character: | Scheme | Alphabet | Bits per character | 5 bytes become | Used for | | ----------- | ----------------------------------- | ------------------ | -------------- | ------------------------------------- | | Hexadecimal | `0`–`9`, `a`–`f` | 4 | 10 characters | hashes, colours, debugging | | Base32 | `A`–`Z`, `2`–`7` | 5 | 8 characters | one-time-password secrets, file names | | Base64 | `A`–`Z`, `a`–`z`, `0`–`9`, two more | 6 | 8 characters | e-mail attachments, data URLs, JWTs | | Base58 | digits and letters, minus `0OIl` | about 5.86 | 7 characters | identifiers people copy by hand | The more bits a character carries, the shorter the text — and the more kinds of character it needs, some of which a particular format may not like. The program writes the same five bytes, `fb ef ff 00 10`, in each: ```text hex fbefff0010 base64 ++//ABA= base32 7PX76AAQ base58 VRbE2yM (at most 7) ``` ## Base64's variants Base64 needs 64 characters, and the last two of the standard alphabet, `+` and `/`, mean something in a URL or a file name. So there is a URL-safe alphabet that uses `-` and `_` instead. Either may also drop the `=` padding, which rounds the text up to a multiple of four characters: | `Base64Variant` | Last two | Padding | The five bytes | | ------------------ | -------- | ------- | -------------- | | `Standard` | `+` `/` | yes | `++//ABA=` | | `StandardUnpadded` | `+` `/` | no | `++//ABA` | | `Url` | `-` `_` | yes | `--__ABA=` | | `UrlUnpadded` | `-` `_` | no | `--__ABA` | `Standard` is what MIME and most protocols mean by "Base64"; `UrlUnpadded` is what JSON Web Tokens and most URL parameters use. A decoder must be told the same variant the text was written in. Base32 has variants as well: the RFC 4648 `Standard`, and `Crockford`, which leaves out `I`, `L`, `O` and `U` because they are easy to misread. ## Buffers you provide Nothing in the package allocates. Every function writes into a buffer you pass and returns how much of it it wrote, as a `uint ! FormatError`: ```rux func ShowBase64(label: char8[..], bytes: byte[..], form: Base64Variant) { var text: char8[64]; let written = Base64Encode(bytes, text[..], form) catch { else => { PrintLine("{:<18} does not fit", label); return; } }; PrintLine("{:<18} {}", label, text[..written]); } ``` The encoded text is `text[..written]`, the front of the buffer. To size a buffer exactly, each scheme has a length function: `Base64EncodedLength(27)` is 36. Base58's length depends on the value itself, so it has only a bound, `Base58EncodedMaxLength`. A buffer that is too short is **refused**, never filled with what fits, because a cut-off encoding would be a different value rather than a shorter one. When you only want to print bytes, there is a shortcut that needs no buffer at all: `ViewHex(bytes)` borrows them and renders them as hexadecimal under `{}`. ## Strict decoding Decoding goes back from text to bytes, into a `var byte[..]`, and returns `uint ! DecodeError`. It is strict, so that each value has exactly one encoded form and two programs can never read the same text differently. A `DecodeError` prints what is wrong and where: ```rux func ReadHex(text: char8[..]) { var bytes: byte[8]; match HexDecode(text, bytes[..]) { .Success(count) => PrintLine("hex {:<12} -> {} bytes: {}", text, count, ViewHex(bytes[..count])), .Failure(error) => PrintLine("hex {:<12} -> {}", text, error) } } ``` | Text | Decoded as | Result | | ------------ | ------------------ | ------------------------------------------- | | `fbefff0010` | hexadecimal | 5 bytes | | `FBEFFF0010` | hexadecimal | 5 bytes — either case is accepted | | `fbefff001` | hexadecimal | invalid length at 9 — half a byte | | `0xfbefff` | hexadecimal | invalid character at 1 — no prefixes | | `SGVsbG8=` | Base64 | 5 bytes, `48656c6c6f`: the text `Hello` | | `SGVsbG9=` | Base64 | non-canonical trailing bits at 6 | | `SGVsbG8` | Base64, `Standard` | invalid length at 7 — the padding is needed | | `SGVsbG8=` | into 3 bytes | destination too short, need 5 bytes | The non-canonical case is the subtle one. `o` and `9` differ only in bits that the last character carries but the data does not use, so `SGVsbG8=` and `SGVsbG9=` would decode to the same five bytes. Refusing the second keeps decoding one-to-one, which is what makes it safe to compare encoded values as text. ```mermaid flowchart LR b(["bytes"]) -- "`HexEncode`, `Base64Encode`, …" --> t(["text"]) t -- "`HexDecode`, `Base64Decode`, …" --> b t -- "wrong alphabet, length,
padding or bits" --> e["`DecodeError`
with the byte offset"] ``` ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/DataFormats/BaseEncoding){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // Text formats such as JSON, TOML, URLs and e-mail carry text, not raw bytes. A key, a hash or // an image has to be written as characters before it can travel through them, and read back // exactly afterwards. A base encoding does that with a small alphabet of safe characters: // // hexadecimal 16 characters, 4 bits each: 2 characters per byte // Base32 32 characters, 5 bits each: 8 characters per 5 bytes // Base64 64 characters, 6 bits each: 4 characters per 3 bytes // Base58 58 characters, for identifiers people copy by hand // // This is not the character encoding of the Encoding lesson, which stores text as UTF-8 or // UTF-16. It goes the other way: any bytes at all become plain ASCII text. // // Nothing in the Encoding package allocates. Every function writes into a buffer you provide and // returns how much it wrote, and a length function says how big that buffer must be. Decoding is // strict, and a `DecodeError` says what is wrong and at which byte. import Encoding::{ Base32Encode, Base32Variant, Base58Encode, Base58EncodedMaxLength, Base64Decode, Base64Encode, Base64EncodedLength, Base64Variant, HexDecode, HexEncode, ViewHex }; import Io::PrintLine; // Prints `bytes` in one Base64 variant. func ShowBase64(label: char8[..], bytes: byte[..], form: Base64Variant) { var text: char8[64]; let written = Base64Encode(bytes, text[..], form) catch { else => { PrintLine("{:<18} does not fit", label); return; } }; PrintLine("{:<18} {}", label, text[..written]); } // Decodes hexadecimal text, or says why it cannot. Encoding turns bytes into characters and // decoding turns them back, so the destination here is a `var byte[..]`. A character buffer, or // an array declared with `let`, is the wrong kind of slice: // // HexDecode(text, characters[..]) // error: argument 2 to 'HexDecode' has type 'var char8[..]', but parameter 'into' // requires 'var uint8[..]' func ReadHex(text: char8[..]) { var bytes: byte[8]; match HexDecode(text, bytes[..]) { .Success(count) => PrintLine("hex {:<12} -> {} bytes: {}", text, count, ViewHex(bytes[..count])), .Failure(error) => PrintLine("hex {:<12} -> {}", text, error) } } // Decodes standard Base64 text into a buffer of `room` bytes, or says why it cannot. func ReadBase64(text: char8[..], room: uint) { var bytes: byte[8]; match Base64Decode(text, bytes[..room]) { .Success(count) => PrintLine("b64 {:<12} -> {} bytes: {}", text, count, ViewHex(bytes[..count])), .Failure(error) => PrintLine("b64 {:<12} -> {}", text, error) } } func Main() -> int { // Five bytes that are not text: no text format could hold them as they are. let key: byte[5] = [0xFB, 0xEF, 0xFF, 0x00, 0x10]; var text: char8[64]; let hex = HexEncode(key[..], text[..]) catch { else => 0 }; PrintLine("{:<18} {}", "hex", text[..hex]); // Base64 comes in four variants. The standard alphabet ends in `+` and `/`, which mean // something in a URL, so the URL-safe one uses `-` and `_` instead. Either may drop the `=` // padding that rounds the text up to a multiple of four characters. ShowBase64("base64", key[..], Base64Variant::Standard); ShowBase64("base64, no pad", key[..], Base64Variant::StandardUnpadded); ShowBase64("base64 url", key[..], Base64Variant::Url); ShowBase64("base64 url, no pad", key[..], Base64Variant::UrlUnpadded); // Base32 uses only capitals and digits, so it survives case-insensitive systems. Crockford's // alphabet leaves out I, L, O and U, which are easy to misread. let base32 = Base32Encode(key[..], text[..], Base32Variant::Standard) catch { else => 0 }; PrintLine("{:<18} {}", "base32", text[..base32]); let crockford = Base32Encode(key[..], text[..], Base32Variant::Crockford) catch { else => 0 }; PrintLine("{:<18} {}", "base32 crockford", text[..crockford]); // Base58 drops 0, O, I, l, + and /, so a person can copy it without mistakes. Its length // depends on the value, so there is only an upper bound to size the buffer with. let base58 = Base58Encode(key[..], text[..]) catch { else => 0 }; PrintLine("{:<18} {} (at most {})", "base58", text[..base58], Base58EncodedMaxLength(5)); // The length functions size a buffer exactly. A buffer that is too short is refused, never // filled with what fits: a cut-off encoding would be a different value. So every encoder // returns `uint ! FormatError`, the count or the refusal, and never just the count: // // let written: uint = Base64Encode(key[..], text[..]); // error: cannot assign 'uint ! FormatError' to 'uint' PrintLine("27 bytes in Base64 take {} characters", Base64EncodedLength(27)); var short: char8[4]; match Base64Encode("Many hands make light work.", short[..]) { .Success(written) => PrintLine("wrote {}", written), .Failure(_) => PrintLine("a 4-character buffer is refused") } let written = Base64Encode("Many hands make light work.", text[..]) catch { else => 0 }; PrintLine("{}", text[..written]); // Decoding is strict, so every value has exactly one encoded form. ReadHex("fbefff0010"); ReadHex("FBEFFF0010"); ReadHex("fbefff001"); ReadHex("0xfbefff"); ReadBase64("SGVsbG8=", 8); ReadBase64("SGVsbG9=", 8); ReadBase64("SGVsbG8", 8); ReadBase64("SGVsbG8=", 3); return 0; } ``` Besides `Io`, its `Rux.toml` lists `Encoding` under `[Dependencies]`. ## Run it ```sh cd Examples/DataFormats/BaseEncoding rux run ``` ```text hex fbefff0010 base64 ++//ABA= base64, no pad ++//ABA base64 url --__ABA= base64 url, no pad --__ABA base32 7PX76AAQ base32 crockford ZFQZY00G base58 VRbE2yM (at most 7) 27 bytes in Base64 take 36 characters a 4-character buffer is refused TWFueSBoYW5kcyBtYWtlIGxpZ2h0IHdvcmsu hex fbefff0010 -> 5 bytes: fbefff0010 hex FBEFFF0010 -> 5 bytes: fbefff0010 hex fbefff001 -> invalid length at 9 hex 0xfbefff -> invalid character at 1 b64 SGVsbG8= -> 5 bytes: 48656c6c6f b64 SGVsbG9= -> non-canonical trailing bits at 6 b64 SGVsbG8 -> invalid length at 7 b64 SGVsbG8= -> destination too short, need 5 bytes ``` ## Common mistakes ::mistake **Decoding into a text buffer.**:br Decoding produces bytes, so the destination is a `var byte[..]`. Passing a `char8` buffer fails with: ```text error: argument 2 to 'HexDecode' has type 'var char8[..]', but parameter 'into' requires 'var uint8[..]' ``` `byte` is another name for `uint8`. A `byte` array declared with `let` is refused too, because the decoder must write into it. :: ::mistake **Decoding with the wrong variant.**:br`Base64Decode("--__ABA=", bytes[..])` uses the default `Standard` variant, and fails with `invalid character at 0`: `-` is not in the standard alphabet. Pass the variant the text was written in, here `Base64Variant::Url`. :: ::mistake **Using the whole buffer.**:br The encoded text is the front of the buffer, `text[..written]`. Printing `text[..]` prints the rest of the buffer after it as well. :: ::mistake **A fallback on text you did not write.**:br`catch { else => 0 }` is safe in this program, whose buffers are known to be big enough. On text from outside it turns a malformed key into zero bytes without a word. Report the `DecodeError` instead — it already says where the text went wrong. :: ## Try it yourself 1. Encode `"Many hands make light work."` with `Base64Variant::StandardUnpadded`. Does it differ from the padded form? Now drop the full stop and compare again. 2. Decode `"zfqz-y00g"` with `Base32Variant::Crockford`. Crockford's decoder accepts lower case and skips hyphens; what bytes do you get? 3. Print the key with `PrintLine("{:X}", ViewHex(key[..]))`, without any buffer. 4. Encode the bytes `[0, 0, 1]` in Base58. What becomes of the two leading zero bytes? ## Learn more - [Encoding API](https://rux-lang.dev/docs/api/encoding) — every scheme, the percent-encoding sets, and the streaming `EncodingWriter` and `DecodingReader` - [Encoding](https://rux-lang.dev/docs/learn/encoding) — character encodings: how text becomes bytes, the opposite direction - [Hash](https://rux-lang.dev/docs/learn/hash) — hashes and checksums, usually shown in hexadecimal - [URL](https://rux-lang.dev/docs/learn/url) — percent-encoding, the base encoding of URLs - [Writable slice](https://rux-lang.dev/docs/learn/writable-slice) — a function filling a buffer it was lent - [Slices](https://rux-lang.dev/docs/lang/slices/overview) in the Rux Reference # URL ::note **You'll need**: [Base64 and friends](https://rux-lang.dev/docs/learn/base-encoding), [Allocator](https://rux-lang.dev/docs/learn/allocator), [Coalesce](https://rux-lang.dev/docs/learn/coalesce), [Propagate](https://rux-lang.dev/docs/learn/propagate), [Fallible main](https://rux-lang.dev/docs/learn/fallible-main) :: A URL looks like a string you could take apart with a few searches for `/` and `?`. It is not. A host is not case-sensitive but a path is; `..` in a path climbs a level; `%C3%A9` is an escaped `é`; `:443` on an `https` URL says nothing at all; and a link such as `../guide` means something only next to the page it appears on. The `Url` package reads URLs by RFC 3986, the standard browsers follow, so you do not have to: ```rux import Url::{ Decode, Pairs, QueryBuilder, Url, UrlError }; ``` ## The parts of a URL ```text https://rux-lang.dev:443/docs/learn/url?q=caf%C3%A9&page=2#install └─┬─┘ └────┬─────┘ └┬┘ └─────┬──────┘ └───────┬──────┘ └──┬──┘ scheme host port path query fragment ``` `Url::Parse` takes an [allocator](https://rux-lang.dev/docs/learn/allocator), since the URL keeps its own copy of the text, and returns `Url ! UrlError`. Each component then comes from an accessor: | Accessor | Returns | For the URL above | | ----------------- | ------------ | -------------------- | | `Scheme()` | `char8[..]` | `https` | | `Host()` | `char8[..]?` | `rux-lang.dev` | | `Port()` | `uint16?` | none — not written | | `PortOrDefault()` | `uint16?` | `443` | | `Path()` | `char8[..]` | `/docs/learn/url` | | `Query()` | `char8[..]?` | `q=caf%C3%A9&page=2` | | `Fragment()` | `char8[..]?` | `install` | | `Text()` | `char8[..]` | the whole URL | The optional ones are [optional](https://rux-lang.dev/docs/learn/optional) because a URL may simply not have that part — `mailto:info@rux-lang.dev` has no host, and most URLs have no fragment. `?? ""` treats a missing part as an empty one, which is what this program wants. Every accessor is a view into the URL's own text, so nothing is copied. ## Normal form `Parse` does more than split. It puts the URL in **normal form**, so that two URLs that mean the same thing come out as the same text: ```rux let page = Url::Parse(allocator, "HTTPS://Rux-Lang.DEV:443/docs/./learn/../learn/url?q=caf%c3%a9&page=2#install")?; ``` | In the text | Normalized to | Because | | ---------------------------- | ----------------------- | --------------------------------- | | `HTTPS`, `Rux-Lang.DEV` | `https`, `rux-lang.dev` | scheme and host ignore case | | `:443` | nothing | it is `https`'s default port | | `/docs/./learn/../learn/url` | `/docs/learn/url` | `.` and `..` segments are removed | | `%c3%a9` | `%C3%A9` | escapes use upper-case hex | So comparing two parsed URLs is comparing their text, and `Equals` does just that. ## Resolving links A page's links are usually **relative references**: `guide`, `/blog`, `?page=3`. `Resolve` turns one into a full URL against the page, exactly as a browser does when you click it: ```rux for link in links { let target = page.Resolve(link)?; PrintLine(" {:<22} -> {}", link, target.Text()); } ``` ```mermaid flowchart LR base["page:
`https://rux-lang.dev/docs/learn/url`"] --> r{"`Resolve`"} ref["link:
`../packaging/manifest`"] --> r r --> out["`https://rux-lang.dev/docs/packaging/manifest`"] ``` | Reference | Replaces | | ----------------------- | ------------------------------------------ | | `guide` | the last path segment | | `../packaging/manifest` | the last segment, after climbing one level | | `/blog` | the whole path | | `?page=3` | the query, keeping the path | | `#run-it` | only the fragment | | `//github.com/rux-lang` | everything but the scheme | ## The query A query is `name=value` pairs joined by `&`, still percent-encoded. `Pairs` walks them without allocating, and `Decode` turns an encoded value into a `String`. Its last argument, `true`, reads `+` as a space, the way an HTML form writes one: ```rux for pair in Pairs(page.Query() ?? "") { let value = Decode(allocator, pair.value, true)?; PrintLine(" {} = {}", pair.name, value); } ``` Going the other way, never paste text into a query yourself. `QueryBuilder` escapes each name and value, so that an `&` or `=` inside a value cannot end the pair early, and `SetQuery` puts the result into a URL: ```rux var query = QueryBuilder(allocator); query.Append("q", "fish & chips")?; query.Append("sort", "price=asc")?; var search = Url::Parse(allocator, "https://example.com/search")?; search.SetQuery(query.Text())?; ``` That gives `?q=fish+%26+chips&sort=price%3Dasc`. For a single path segment, the `PercentEncode` you met in [Base64 and friends](https://rux-lang.dev/docs/learn/base-encoding) does the job, with the `Component` set: it escapes `/` as well, so `Kyiv 2026/10.txt` stays one segment, `Kyiv%202026%2F10.txt`. ## What is refused `UrlError` says why text is not a URL. The one to know is `MissingScheme`: `rux-lang.dev/docs` has no `https:`, so it is a *relative* reference, and the only thing to do with it is `Resolve` it against a URL that has one. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/DataFormats/Url){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // A URL names something on a network and says how to reach it: // // https://rux-lang.dev:443/docs/learn/url?q=caf%C3%A9&page=2#install // scheme host port path query fragment // // Splitting that by hand looks easy and is not: `%C3%A9` is an escaped `é`, a host is not case // sensitive but a path is, and `..` in a path climbs a level. `Url::Parse` reads a URL by RFC 3986 // and keeps it in one normalized form, so each component is a view of that text, and two URLs // that mean the same thing come out as the same text. // // A link on a page is often relative, such as `../guide` or `?page=3`. `Resolve` turns it into a // full URL against the page it appears on, exactly as a browser does. // // Components stay percent-encoded. `Pairs` walks a query's `name=value` pairs, `Decode` turns one // into text, and `QueryBuilder` goes the other way, escaping text into a query. import Allocator::{ Allocator, SystemAllocator }; import Encoding::{ PercentEncode, PercentSet }; import Io::PrintLine; import Url::{ Decode, Pairs, QueryBuilder, Url, UrlError }; func Reason(error: UrlError) -> char8[..] { return match error { UrlError::MissingScheme => "no scheme: a relative reference", UrlError::InvalidScheme => "not a scheme", UrlError::InvalidHost => "not a host", UrlError::InvalidPort => "not a port", UrlError::InvalidPercentEncoding => "a % without two hexadecimal digits", UrlError::OutOfMemory => "out of memory", UrlError::InvalidText => "not UTF-8 text" }; } func Check(allocator: Allocator, text: char8[..]) { match Url::Parse(allocator, text) { .Success(url) => PrintLine(" {:<28} -> {}", text, url.Text()), .Failure(error) => PrintLine(" {:<28} -> {}", text, Reason(error)) } } func Main() -> ! UrlError { var system = SystemAllocator(); let allocator: Allocator = system; // Parsing normalizes: the scheme and host are lower-cased, the default port is dropped, the // dot segments are removed from the path, and escapes use upper-case hexadecimal. let page = Url::Parse(allocator, "HTTPS://Rux-Lang.DEV:443/docs/./learn/../learn/url?q=caf%c3%a9&page=2#install")?; PrintLine("url {}", page.Text()); PrintLine("scheme {}", page.Scheme()); PrintLine("host {}", page.Host() ?? ""); PrintLine("port {} (not written, the default for https)", page.PortOrDefault() ?? 0); PrintLine("path {}", page.Path()); PrintLine("query {}", page.Query() ?? ""); PrintLine("fragment {}", page.Fragment() ?? ""); // The query, pair by pair. `Decode` turns `caf%C3%A9` back into `café`; `true` reads `+` as a // space, as a query from an HTML form writes it. // // A URL may have no query at all, so `Query()` returns `char8[..]?`, and `?? ""` treats a // missing query as an empty one. Without it: // // for pair in Pairs(page.Query()) { } // error: argument 1 to 'Pairs' has type 'char8[..]?', but parameter 'query' requires // 'char8[..]' for pair in Pairs(page.Query() ?? "") { let value = Decode(allocator, pair.value, true)?; PrintLine(" {} = {}", pair.name, value); } // Relative references, resolved against the page. PrintLine("links on the page:"); let links: char8[..][6] = ["guide", "../packaging/manifest", "/blog", "?page=3", "#run-it", "//github.com/rux-lang"]; for link in links { let target = page.Resolve(link)?; PrintLine(" {:<22} -> {}", link, target.Text()); } // Building a query. Each name and value is escaped as HTML forms do it: a space becomes `+`, // and `&` or `=` inside a value becomes `%26` or `%3D`, so it cannot end the pair early. var query = QueryBuilder(allocator); query.Append("q", "fish & chips")?; query.Append("sort", "price=asc")?; var search = Url::Parse(allocator, "https://example.com/search")?; search.SetQuery(query.Text())?; PrintLine("search {}", search.Text()); // One path segment from arbitrary text. The Encoding package's `PercentEncode` with the // `Component` set escapes everything but letters, digits and `-._~`, the `/` included, so the // text stays one segment. var segment: char8[64]; let length = PercentEncode("Kyiv 2026/10.txt", segment[..], PercentSet::Component) catch { else => 0 }; PrintLine("segment {}", segment[..length]); // Text that is not a URL. PrintLine("refused:"); Check(allocator, "rux-lang.dev/docs"); Check(allocator, "https://rux lang.dev/"); Check(allocator, "https://rux-lang.dev:99999/"); Check(allocator, "https://rux-lang.dev/caf%c"); } ``` Besides `Io`, its `Rux.toml` lists `Allocator`, `Encoding` and `Url` under `[Dependencies]`. ## Run it ```sh cd Examples/DataFormats/Url rux run ``` ```text url https://rux-lang.dev/docs/learn/url?q=caf%C3%A9&page=2#install scheme https host rux-lang.dev port 443 (not written, the default for https) path /docs/learn/url query q=caf%C3%A9&page=2 fragment install q = café page = 2 links on the page: guide -> https://rux-lang.dev/docs/learn/guide ../packaging/manifest -> https://rux-lang.dev/docs/packaging/manifest /blog -> https://rux-lang.dev/blog ?page=3 -> https://rux-lang.dev/docs/learn/url?page=3 #run-it -> https://rux-lang.dev/docs/learn/url?q=caf%C3%A9&page=2#run-it //github.com/rux-lang -> https://github.com/rux-lang search https://example.com/search?q=fish+%26+chips&sort=price%3Dasc segment Kyiv%202026%2F10.txt refused: rux-lang.dev/docs -> no scheme: a relative reference https://rux lang.dev/ -> not a host https://rux-lang.dev:99999/ -> not a port https://rux-lang.dev/caf%c -> a % without two hexadecimal digits ``` ## Common mistakes ::mistake **Treating an optional part as text.**:br`let host: char8[..] = page.Host();` fails with: ```text error: cannot assign 'char8[..]?' to 'char8[..]' ``` A URL may have no host, query or fragment. Decide what a missing one means, with `??` or a `match`. :: ::mistake **Building a query by pasting text.**:br Written by hand, `q=fish & chips&sort=price` reads back as three pairs — `q` is `fish `, then a pair named `chips` with no value, then `sort`. Use `QueryBuilder`, which escapes the `&`. :: ::mistake **Parsing a link on its own.**:br`Url::Parse(allocator, "../guide")` fails with `MissingScheme`. A relative reference is not a URL until it is resolved against the page it came from. :: ::mistake **Comparing URLs as you received them.**:br`HTTPS://Rux-Lang.DEV:443` and `https://rux-lang.dev/` are the same address. Parse both, then compare with `Equals`. :: ## Try it yourself 1. Resolve `"../../../../x"` against the page. Can a reference climb above the root? 2. Walk the page's path with `for segment in page.PathSegments()`. 3. Parse `http://localhost:8080/v1/playground/run`. What do `Port()` and `PortOrDefault()` return? 4. `Decode` the segment the program printed, `Kyiv%202026%2F10.txt`, and check that you get the original text back. ## Learn more - [Url API](https://rux-lang.dev/docs/api/url) — every accessor, `SetPath`, `SetFragment` and `HostKind` - [Encoding API](https://rux-lang.dev/docs/api/encoding) — `PercentEncode`, `PercentDecode` and the `Component`, `Path` and `Form` sets - [Base64 and friends](https://rux-lang.dev/docs/learn/base-encoding) — the other base encodings, in caller-provided buffers - [Coalesce](https://rux-lang.dev/docs/learn/coalesce) — `??` for a part the URL may not have - [Propagate](https://rux-lang.dev/docs/learn/propagate) — `?`, which hands each `UrlError` to `Main` - [Optionals](https://rux-lang.dev/docs/lang/optionals/overview) and [Error handling](https://rux-lang.dev/docs/lang/errors/handling) in the Rux Reference # Compress ::note **You'll need**: [Vector](https://rux-lang.dev/docs/learn/vector), [Pointer slice](https://rux-lang.dev/docs/learn/pointer-slice), [Error sum](https://rux-lang.dev/docs/learn/error-sum), [File](https://rux-lang.dev/docs/learn/file), [Memory streams](https://rux-lang.dev/docs/learn/memory-stream) :: A web server's access log says the same few things over and over: the same paths, the same statuses, the same words. **Compression** finds what repeats and writes each repeat as a short reference back to an earlier copy, so a log, a JSON document or a page of HTML shrinks to a fraction of its size. The `Compress` package speaks **Deflate**, the method inside every `.gz` and `.zip` file and behind HTTP's `Content-Encoding: gzip`: ```rux import Compress::{ Compress, CompressWriter, Decompress, DecompressReader, Format, Level }; ``` This lesson compresses an 11,572-byte log to under 1,400 bytes, gets every byte back, and then does the same through a file, a piece at a time. ## Three containers The compressed stream is the same in each; what differs is what is wrapped around it: | `Format` | Wrapped in | Overhead | Where you meet it | | -------- | ----------------------------------------------------------- | -------- | ---------------------------------- | | `Raw` | nothing: the bare Deflate stream | 0 bytes | inside ZIP files | | `Zlib` | a 2-byte header and an Adler-32 checksum | 6 bytes | PNG images, many network protocols | | `Gzip` | a 10-byte header, a CRC-32 checksum and the original length | 18 bytes | `.gz` files, HTTP | The program's output shows exactly that: 1377 bytes raw, 6 more as zlib, 18 more as gzip. Whoever reads the data must be told the same format it was written in. ## Whole buffers `Compress` takes the data as `byte[..]` and returns a `Vector` of the compressed bytes, allocated from the allocator you pass. `Decompress` takes them back: ```rux let gzip = Compress(allocator, data, Format::Gzip)?; ``` ```rux let unpacked = Decompress(allocator, gzip.AsSlice(), Format::Gzip)?; ``` Both return `Vector ! IoError`. The log is text, so the program first views its characters as the bytes they are, with a [pointer slice](https://rux-lang.dev/docs/learn/pointer-slice) as the [Hash](https://rux-lang.dev/docs/learn/hash) lesson does: ```rux func AsBytes(text: char8[..]) -> byte[..] { return (text.data as *byte)[..text.length]; } ``` ## How hard to try An optional fourth argument, a `Level`, says how hard the compressor looks for repeats. Higher levels find longer and more of them, and take longer to: | `Level` | Searches | The log, as gzip | | --------- | ----------------------------- | ---------------- | | `Store` | not at all: data copied as is | 11595 bytes | | `Fastest` | takes the first match found | 1771 bytes | | `Default` | a balance, close to zlib's | 1395 bytes | | `Best` | the most thorough | 1360 bytes | `Store` is 23 bytes *larger* than the log: the gzip header and trailer, plus a few bytes per stored block. The level is not written into the data, so `Decompress` never needs to know it. For a given level the output is always the same, which is why these sizes are the same on every run. ## What does not shrink Compression only pays where something repeats. `Hello, Rux!` has nothing to repeat, so its 11 bytes come out as 31: the 18 bytes of gzip around a stream slightly longer than the text. Random bytes, and data that is already compressed, do not shrink either. The checksum earns its place when something goes wrong. The program flips one bit in the middle of the compressed log, and `Decompress` refuses it with `IoErrorKind::InvalidInput` instead of returning something that is almost the log. ## Streams `Compress` needs all the data in memory at once. For a file of any size, `CompressWriter` is a [`Writer`](https://rux-lang.dev/docs/learn/memory-stream) that compresses whatever is written to it into another writer — here a [file](https://rux-lang.dev/docs/learn/file): ```rux var file = File::Open(allocator, path, OpenOptions::Writing())?; var writer = CompressWriter::New(allocator, <-file, Format::Gzip)?; var written: uint = 0; while written < text.length { let end = written + 1000 < text.length ? written + 1000 : text.length; written = written + writer.Write(text[written..end])?; } writer.Finish()?; ``` ```mermaid flowchart LR w["`writer.Write`"] --> cw["`CompressWriter`"] cw -- "compressed blocks" --> f[("`access.log.gz`")] f --> dr["`DecompressReader`"] dr -- "`Read` into a buffer" --> r["the log, piece by piece"] ``` The writer *takes* the file — a file is move-only, hence `<-` — and closes it when the writer is destroyed at the end of the function. Nothing is complete until `Finish` writes the last block and the checksum. `DecompressReader` is the matching `Reader`: each `Read` fills a buffer with decompressed data, and the end of the data is reported, as `IsEnd()`, only after the checksum has agreed. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/DataFormats/Compress){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // Compression finds what repeats in data and writes each repeat as a short reference back to an // earlier copy. A log, a JSON document or a page of HTML repeats a great deal and shrinks to a // fraction of its size; random bytes do not repeat and do not shrink at all. // // The Compress package speaks Deflate, the method inside gzip, zlib and ZIP files and behind // HTTP's `Content-Encoding: gzip`. The same compressed data travels in one of three containers: // // Format::Raw the bare Deflate stream // Format::Zlib a 2-byte header, the stream, and an Adler-32 checksum of the data // Format::Gzip a 10-byte header, the stream, a CRC-32 checksum and the length: a .gz file // // `Compress` and `Decompress` work on data already in memory. `CompressWriter` and // `DecompressReader` do the same through the `Writer` and `Reader` interfaces, a piece at a time, // so a file of any size can be compressed without holding all of it at once. // // The file this program writes lives in its package's `Bin/` folder, and is deleted at the end. import Allocator::{ Allocator, SystemAllocator }; import Collections::{ CollectionError, Vector }; import Compress::{ Compress, CompressWriter, Decompress, DecompressReader, Format, Level }; import FileSystem::{ DeleteFile, File, OpenOptions }; import Io::{ IoError, IoErrorKind, PrintLine }; import Path::{ OsString, Path }; import Text::TextError; // Text as the bytes it is made of, as in the Hash lesson. `Compress` takes bytes, and text is // not accepted in their place: // // Compress(allocator, "Hello, Rux!", Format::Gzip) // error: argument 2 to 'Compress' has type 'char8[..]', but parameter 'data' requires // 'uint8[..]' func AsBytes(text: char8[..]) -> byte[..] { return (text.data as *byte)[..text.length]; } func SameBytes(left: byte[..], right: byte[..]) -> bool { if left.length != right.length { return false; } for i in 0..left.length { if left[i] != right[i] { return false; } } return true; } // A web server's access log of `count` requests: a few paths and statuses in an order that looks // random but is the same on every run, and a time in milliseconds. func MakeLog(allocator: Allocator, count: int) -> Vector ! CollectionError { let paths: char8[..][6] = ["/docs/learn/compress", "/docs/learn/url", "/images/logo.svg", "/v1/playground/run", "/blog", "/packages"]; let statuses: char8[..][3] = [" 200 ", " 304 ", " 404 "]; let digits = "0123456789"; var log = Vector(allocator); var state: uint32 = 2026; for _ in 0..count { state = state * 1664525 + 1013904223; log.PushSlice("GET ")?; log.PushSlice(paths[((state >> 8) % 6) as uint])?; log.PushSlice(statuses[((state >> 16) % 3) as uint])?; log.Push(digits[((state >> 20) % 10) as uint])?; log.Push(digits[((state >> 24) % 10) as uint])?; log.PushSlice(" ms\n")?; } return <-log; } // Writes `text` into a .gz file. The writer takes the file and compresses whatever is written // to it, here 1000 characters at a time; nothing is complete until `Finish` writes the last block // and the checksum. When the function returns the writer is destroyed, and the file it holds is // closed. A file is move-only, so handing it over takes `<-`: // // CompressWriter::New(allocator, file, Format::Gzip) // error: move-only value 'file' requires an explicit '<-' in argument func WriteLog(allocator: Allocator, path: Path, text: char8[..]) -> ! IoError { var file = File::Open(allocator, path, OpenOptions::Writing())?; var writer = CompressWriter::New(allocator, <-file, Format::Gzip)?; var written: uint = 0; while written < text.length { let end = written + 1000 < text.length ? written + 1000 : text.length; written = written + writer.Write(text[written..end])?; } writer.Finish()?; } // Reads the .gz file back a buffer at a time, until the reader reports the end of the data. That // end comes only after the checksum agreed. func ReadLog(allocator: Allocator, path: Path) -> ! IoError { var file = File::Open(allocator, path, OpenOptions::Reading())?; PrintLine("file {} bytes", file.Size()?); var reader = DecompressReader::New(allocator, <-file, Format::Gzip)?; var buffer: char8[1024]; var total: uint = 0; var lines: uint = 0; while true { let count = reader.Read(buffer[..]) catch { error if error.IsEnd() => break, error => fail error }; for c in buffer[..count] { if c == '\n' { lines = lines + 1; } } total = total + count; } PrintLine("read back {} bytes, {} lines", total, lines); } func Main() -> ! IoError | CollectionError | TextError { var system = SystemAllocator(); let allocator: Allocator = system; let log = MakeLog(allocator, 400)?; let data = AsBytes(log.AsSlice()); PrintLine("log {} bytes", data.length); // The same data in the three containers. The compressed stream inside is the same; the // containers differ only by the size of their header and checksum. let raw = Compress(allocator, data, Format::Raw)?; let zlib = Compress(allocator, data, Format::Zlib)?; let gzip = Compress(allocator, data, Format::Gzip)?; PrintLine("raw {} bytes", raw.Length()); PrintLine("zlib {} bytes", zlib.Length()); PrintLine("gzip {} bytes", gzip.Length()); // How hard to look for repeats. `Store` does not compress at all, so it comes out a little // larger than the data; the others trade time for size. `Default` is what `Compress` uses // when no level is given. let levels: Level[4] = [Level::Store, Level::Fastest, Level::Default, Level::Best]; let names: char8[..][4] = ["store", "fastest", "default", "best"]; for i in 0..4 { let packed = Compress(allocator, data, Format::Gzip, levels[i])?; PrintLine("gzip, {:<13} {} bytes", names[i], packed.Length()); } // The round trip gives back every byte. Decompressing needs only the format: the level is // not part of the data. let unpacked = Decompress(allocator, gzip.AsSlice(), Format::Gzip)?; PrintLine("round trip {} bytes, identical: {}", unpacked.Length(), SameBytes(unpacked.AsSlice(), data)); // Short text has nothing to repeat, and the container's header and checksum make it larger. let short = Compress(allocator, AsBytes("Hello, Rux!"), Format::Gzip)?; PrintLine("11 bytes as gzip {} bytes", short.Length()); // The checksum catches damage. Change one bit of the compressed data and decompressing // fails with `InvalidInput` instead of returning wrong data. var damaged = Vector(allocator); damaged.PushSlice(gzip.AsSlice())?; damaged.AsMutableSlice()[100] = damaged.AsSlice()[100] ^ 0x01; match Decompress(allocator, damaged.AsSlice(), Format::Gzip) { .Success(_) => PrintLine("damaged accepted"), .Failure(error) => PrintLine("damaged refused, invalid input: {}", error.kind == IoErrorKind::InvalidInput) } // Streaming into a .gz file, and back out of it. var holder = OsString::FromText(allocator, "Bin/access.log.gz")?; let path = Path::FromView(holder.View()); WriteLog(allocator, path, log.AsSlice())?; ReadLog(allocator, path)?; DeleteFile(allocator, path)?; } ``` Besides `Io`, its `Rux.toml` lists `Allocator`, `Collections`, `Compress`, `FileSystem`, `Path` and `Text` under `[Dependencies]`. ## Run it ```sh cd Examples/DataFormats/Compress rux run ``` ```text log 11572 bytes raw 1377 bytes zlib 1383 bytes gzip 1395 bytes gzip, store 11595 bytes gzip, fastest 1771 bytes gzip, default 1395 bytes gzip, best 1360 bytes round trip 11572 bytes, identical: true 11 bytes as gzip 31 bytes damaged refused, invalid input: true file 1395 bytes read back 11572 bytes, 400 lines ``` ## Common mistakes ::mistake **Passing text where bytes are wanted.**:br`Compress(allocator, "Hello, Rux!", Format::Gzip)` fails with: ```text error: argument 2 to 'Compress' has type 'char8[..]', but parameter 'data' requires 'uint8[..]' ``` View the text as bytes first, as `AsBytes` does. :: ::mistake **Forgetting `Finish`.**:br Without it, the log in this program never leaves the writer's buffer: the file is 0 bytes, and reading it back fails. A stream is complete only when `Finish` has written its last block and its checksum. :: ::mistake **Reading in the wrong format.**:br`Decompress(allocator, zlib.AsSlice(), Format::Gzip)` fails with `InvalidInput`: zlib data does not start with a gzip header. Decompress in the format the data was written in. :: ::mistake **Handing over the file without `<-`.**:br`CompressWriter::New(allocator, file, Format::Gzip)` fails with: ```text error: move-only value 'file' requires an explicit '<-' in argument ``` The writer owns the file from then on; you no longer use `file` yourself. :: ## Try it yourself 1. Compress `gzip.AsSlice()` a second time. Does compressed data shrink again? 2. Decompress the gzip data cut short by three bytes, `gzip.AsSlice()[..gzip.Length() - 3]`. What happens? 3. Make the log ten times longer. How do the sizes at each level change? 4. Write the log as `Format::Zlib` in `WriteLog`, then read it with `Format::Gzip` in `ReadLog`, and see where it fails. ## Learn more - [Compress API](https://rux-lang.dev/docs/api/compress) — the formats, the levels, and `Flush` for a stream that must stay open - [Memory stream](https://rux-lang.dev/docs/learn/memory-stream) — the `Reader` and `Writer` interfaces the streams are built on - [File](https://rux-lang.dev/docs/learn/file) — opening, reading and writing files - [Hash](https://rux-lang.dev/docs/learn/hash) — checksums such as CRC-32, the one inside gzip - [Error sum](https://rux-lang.dev/docs/learn/error-sum) — a `Main` that can fail in three ways - [Interfaces](https://rux-lang.dev/docs/lang/interfaces/overview) and [Copy and move](https://rux-lang.dev/docs/lang/ownership/copy-and-move) in the Rux Reference # Part 22: Packages Every program so far has been one package with one source file. Real projects are bigger: many files, libraries of your own, packages from the registry, sometimes a whole tree of packages worked on together. This part shows how Rux organises all of that — from a module inside one file up to a workspace of several packages — and the `rux` commands that keep such a project tidy. By the end you can split a program into a library and an executable, decide what the library shows to the world, document it, test it, and measure how fast it is. ## What you will learn - Splitting one package across several files, and grouping names into modules with `module A::B { }`. - Choosing what a package shows to other packages with `pub`, and what it keeps private. - Reading a `Rux.toml` manifest, and the four package types it can declare. - Depending on registry packages and on packages in a folder beside your own. - Keeping a program and its libraries in one workspace. - What source, static and shared libraries are, and what each one produces. - Documenting a public API with `///` comments and generating pages with `rux doc`. - Formatting, linting and testing a package with `rux fmt`, `rux lint` and `rux test`. - Writing unit tests as `#Test()` functions with the `Test` package's checks, and running them by name. - Measuring how long code takes with benchmarks, and keeping the measured work from being optimized away. ## From module to workspace Each level groups the one before it: ```mermaid flowchart LR item["Items
functions, types,
constants"] --> mod["Module
`module Shape::Circle { }`
a namespace"] mod --> pkg["Package
`Rux.toml` + `Src/`
one `Type`, one `Name`"] pkg --> ws["Workspace
a root `Rux.toml`
with `[Workspace]`"] pkg -.->|"`[Dependencies]`:
`Path` or `Namespace` + `Version`"| pkg2["Another package"] ``` | Level | Declared by | Groups | `pub` matters? | | --------- | ----------------------------- | ----------------- | ------------------------------------- | | Module | `module Name { }` in a file | items | no — a package sees all its modules | | Package | `Rux.toml` with `[Package]` | files and modules | yes — at the border to other packages | | Workspace | `Rux.toml` with `[Workspace]` | packages | no — membership is not a dependency | ## Lessons | | Lesson | What you will learn | | ----- | ---------------------------------------------------------------- | --------------------------------------------------------------------------- | | 22.1 | [Module](https://rux-lang.dev/docs/learn/module) | split a package across source files and modules | | 22.2 | [Visibility](https://rux-lang.dev/docs/learn/visibility) | choose what a package shows to others with `pub` | | 22.3 | [Package](https://rux-lang.dev/docs/learn/package) | what a manifest says about a package | | 22.4 | [Dependency](https://rux-lang.dev/docs/learn/dependency) | depend on another package | | 22.5 | [Workspace](https://rux-lang.dev/docs/learn/workspace) | build several packages together | | 22.6 | [Source library](https://rux-lang.dev/docs/learn/source-library) | write a library and use it from an executable | | 22.7 | [Static library](https://rux-lang.dev/docs/learn/static-library) | build a static library | | 22.8 | [Shared library](https://rux-lang.dev/docs/learn/shared-library) | build a shared library | | 22.9 | [Documentation](https://rux-lang.dev/docs/learn/documentation) | document your code with `///` comments | | 22.10 | [Tooling](https://rux-lang.dev/docs/learn/tooling) | format, lint, test and document with the `rux` tool | | 22.11 | [Unit tests](https://rux-lang.dev/docs/learn/unit-test) | write `#Test()` functions with `Expect` checks and run them with `rux test` | | 22.12 | [Benchmark](https://rux-lang.dev/docs/learn/benchmark) | measure how long code takes with the `Test` package's benchmarks | ## Before you start This part leans on [Part 4: Functions](https://rux-lang.dev/docs/learn/functions) and [Part 6: Types](https://rux-lang.dev/docs/learn/types) — the libraries here export functions, structs, constructors and methods — and Source library uses a [generic](https://rux-lang.dev/docs/learn/generic) function over a [slice](https://rux-lang.dev/docs/learn/slice). Each lesson's package is in the Examples repository's `Packages/` folder: ```sh cd Examples/Packages/Module rux run ``` Several lessons hold more than one package: the library sits in a folder beside `Src/` with its own `Rux.toml`, and the lesson page shows every file. Workspace is run from its `App/` member, the two native library lessons are built with `rux build` rather than run, and Unit tests is a library whose tests run with `rux test`. ## After this part [Part 23: Compile time](https://rux-lang.dev/docs/learn/compile-time) is about code chosen while compiling — `when`, the target and build mode you met as `#build` in [Package](https://rux-lang.dev/docs/learn/package), and your own defines. [Part 24: Platform](https://rux-lang.dev/docs/learn/platform) then calls native code with `extern`, which is how a separately built program uses a [shared library](https://rux-lang.dev/docs/learn/shared-library). This part has no checkpoint project of its own; the next one, [Melody](https://rux-lang.dev/docs/learn/melody), follows Part 24. For the full rules, see [Modules](https://rux-lang.dev/docs/lang/modules/overview) in the Rux Reference, and the packaging guides: [Package manifest](https://rux-lang.dev/docs/packaging/manifest), [Package types](https://rux-lang.dev/docs/packaging/types) and [Dependencies](https://rux-lang.dev/docs/packaging/dependencies). Every command used here is described in the [CLI reference](https://rux-lang.dev/docs/cli). # Module ::note **You'll need**: [Function](https://rux-lang.dev/docs/learn/function), [Const](https://rux-lang.dev/docs/learn/const) :: Until now every program has fitted in one file, `Src/Main.rux`. Real programs outgrow that quickly, and Rux gives you two separate tools for organising them. **Files** are how you store the source: a package may have as many as you like. **Modules** are how you organise the *names* in it: a module is a named namespace, so two functions can both be called `Area` as long as they live in different modules. This lesson uses both, in one package. ## Many files, one package Every `.rux` file under `Src/` belongs to the package, and the compiler reads them all together as one unit. This lesson has three: `Main.rux`, `Rectangle.rux` and `Circle.rux`. You do not list them anywhere — putting a file in `Src/` is enough. The file's own name means nothing to the compiler. What decides where its functions live is the `module` declaration wrapped around them, in `Src/Rectangle.rux`: ```rux module Shape::Rectangle { func Area(width: int, height: int) -> int { return width * height; } func Perimeter(width: int, height: int) -> int { return 2 * (width + height); } } ``` You could rename the file to `Boxes.rux` and nothing would change. Keeping file and module names in step is still a good habit, because it tells a reader where to look. ## A module is a namespace `Src/Circle.rux` declares `Area` and `Perimeter` again. That is not a clash, because a module is a namespace: the full name of each function includes the module it is in. ```rux module Shape::Circle { const Pi: float64 = 3.14159; func Area(radius: float64) -> float64 { return Pi * radius * radius; } ``` `A::B` nests one module inside another, so both modules sit under a shared parent called `Shape`. Writing `module Shape { module Circle { … } }` would mean exactly the same thing; the `::` form just saves a level of indentation. Seen from outside, every path starts with the package name, which is `Module` — the `Name` in this lesson's `Rux.toml`: ```mermaid flowchart LR pkg(["`package Module`"]) --> shape["`module Shape`"] pkg --> main["`Main`
(`Src/Main.rux`)"] shape --> rect["`module Rectangle`
(`Src/Rectangle.rux`)"] shape --> circ["`module Circle`
(`Src/Circle.rux`)"] rect --> ra["`Area`, `Perimeter`"] circ --> ca["`Pi`, `Area`, `Perimeter`"] ``` | Function | Declared in | Full path | | ------------------ | ------------------- | --------------------------------- | | Rectangle's `Area` | `Src/Rectangle.rux` | `Module::Shape::Rectangle::Area` | | Circle's `Area` | `Src/Circle.rux` | `Module::Shape::Circle::Area` | | `Main` | `Src/Main.rux` | at the package root, in no module | ## Importing an item or a whole module `Main.rux` reaches the other two files with imports, and they show the two things an import can name: ```rux import Io::PrintLine; import Module::Shape::Circle; import Module::Shape::Rectangle::{ Area, Perimeter }; ``` The last line imports two **items**, the rectangle's functions. Imported items are used by their bare names, as if they were declared in `Main.rux`: ```rux PrintLine("rectangle 3 x 4 area {}", Area(3, 4)); PrintLine("rectangle 3 x 4 perimeter {}", Perimeter(3, 4)); ``` The second line imports a whole **module**. Its items are then reached through the module's name, which is what keeps both `Area`s usable side by side: ```rux PrintLine("circle radius 4 area {}", Circle::Area(4.0)); PrintLine("circle radius 4 perimeter {}", Circle::Perimeter(4.0)); ``` Importing a module rather than its items is the better choice whenever a name on its own would be unclear. `Circle::Area(4.0)` says which area you mean; a bare `Area(4.0)` makes the reader go and look. ## No `pub` inside a package Nothing in `Rectangle.rux` or `Circle.rux` is marked `pub`, and `Main.rux` uses them anyway. Every file of a package sees everything the package declares. `pub` is about what *other packages* may see — which is the next lesson, [Visibility](https://rux-lang.dev/docs/learn/visibility). ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Packages/Module){rel=""nofollow""}. Its comments explain every step. ::code-tree{default-value="Src/Main.rux"} ```toml [Rux.toml] [Manifest] Version = 1 MinRux = "0.4.0" [Package] Name = "Module" Version = "0.1.0" Type = "Executable" Description = "Source files, modules and imports inside one package" Authors = ["Rux Contributors "] [Dependencies] Io = { Namespace = "Rux", Version = "*" } ``` ```rux [Src/Circle.rux] // A second file, adding a second module beside the first one under the same `Shape` parent. // // It declares `Area` and `Perimeter` again. That is not a clash: a module is a namespace, so // `Shape::Circle::Area` and `Shape::Rectangle::Area` are two different names. module Shape::Circle { const Pi: float64 = 3.14159; func Area(radius: float64) -> float64 { return Pi * radius * radius; } func Perimeter(radius: float64) -> float64 { return 2.0 * Pi * radius; } } ``` ```rux [Src/Main.rux] // Until now every package has been a single `Main.rux`. A package may hold as many source files // as it likes under `Src/`, and the compiler reads them all as one package. // // Each of the other two files wraps its contents in `module Shape::Rectangle { }` or // `module Shape::Circle { }`. A module is a named namespace inside the package, and `A::B` nests // one module inside another, so both of these live under a shared parent called `Shape`. // // An import can bring in two kinds of thing: // // - an item, such as a function, which is then used by its bare name, or // - a whole module, whose items are then reached through it: `Circle::Area(4.0)`. // // Nothing in the other files is marked `pub`. Every file of a package sees everything the package // declares; `pub` is about what other packages may see, which is the next lesson. import Io::PrintLine; import Module::Shape::Circle; import Module::Shape::Rectangle::{ Area, Perimeter }; func Main() -> int { // Imported items read like functions declared in this file. PrintLine("rectangle 3 x 4 area {}", Area(3, 4)); PrintLine("rectangle 3 x 4 perimeter {}", Perimeter(3, 4)); // The circle's functions have the same names, so they are reached through their module. // That keeps both `Area`s usable side by side. PrintLine("circle radius 4 area {}", Circle::Area(4.0)); PrintLine("circle radius 4 perimeter {}", Circle::Perimeter(4.0)); return 0; } ``` ```rux [Src/Rectangle.rux] // This file adds a module called `Shape::Rectangle` to the package. The file's own name means // nothing to the compiler; the `module` declaration is what decides where these functions live. // // The path is written relative to the package. Seen from an import, the full name starts with the // package name, as every import does: `Module::Shape::Rectangle`. module Shape::Rectangle { func Area(width: int, height: int) -> int { return width * height; } func Perimeter(width: int, height: int) -> int { return 2 * (width + height); } } ``` :: ## Run it ```sh cd Examples/Packages/Module rux run ``` ```text rectangle 3 x 4 area 12 rectangle 3 x 4 perimeter 14 circle radius 4 area 50.26544 circle radius 4 perimeter 25.13272 ``` ## Common mistakes ::mistake **Leaving the package name out of the import.**:br An import always starts with a package. Write `import Shape::Circle;` and the compiler looks for a package called `Shape`: ```text error: package 'Shape' is not listed in [Dependencies] ``` It comes with the help line "add the package under [Dependencies] or correct the import path". Your own modules start with your own package's name, `Module::Shape::Circle`. :: ::mistake **Using a module without importing it.**:br Without `import Module::Shape::Circle;`, the call `Circle::Area(4.0)` fails with: ```text error: name 'Circle' is not defined in this scope ``` Spelling out the whole path does not help either — `Module::Shape::Circle::Area(4.0)` fails the same way, naming `'Module'`. The first segment of a path has to be brought in by an import. :: ::mistake **Importing a package as if it were a module.**:br`import Io;` fails with: ```text error: import 'Io' does not name a module ``` The help suggests `import Io::Name`. Import the items you need from a package, or one of its modules. :: ::mistake **Two imported functions nobody can tell apart.**:br Here both `Area`s could even be imported by name together, because one takes two `int`s and the other a `float64`, so every call picks one. If they took the same parameters, `Area(2, 3)` would fail with: ```text error: call to 'Area' is ambiguous: 2 overloads accept argument types (int, int) ``` Import the module and qualify the call instead. :: ## Try it yourself 1. Add a fourth file, `Src/Square.rux`, with a module `Shape::Square` and a function `Area(side: int) -> int`. Import the module and print the area of a 5 × 5 square. 2. Replace `import Module::Shape::Circle;` with `import Module::Shape;` and change the calls to `Shape::Circle::Area(4.0)`. Does it still run? 3. Change `Name` in `Rux.toml` to `Shapes`. Which lines does the compiler reject, and what do you have to change? Look at the name of the program in `Bin/` afterwards. ## Learn more - [Module declaration](https://rux-lang.dev/docs/lang/modules/overview#module-declarations) and [Import](https://rux-lang.dev/docs/lang/modules/imports) in the Rux Reference - [Visibility](https://rux-lang.dev/docs/learn/visibility) — what `pub` means between packages - [Directory layout](https://rux-lang.dev/docs/packaging/layout) — where the files of a package go # Visibility ::note **You'll need**: [Module](https://rux-lang.dev/docs/learn/module), [Constructor](https://rux-lang.dev/docs/learn/constructor), [Mutating method](https://rux-lang.dev/docs/learn/mutating-method) :: In [Module](https://rux-lang.dev/docs/learn/module), nothing was marked `pub` and everything still worked, because every file of a package sees everything the package declares. `pub` matters at a different border: the one between **packages**. It marks what a package lets the packages that depend on it see, and everything without it stays private. That is how a library keeps a promise — here, that a counter never passes its limit — no matter what the code using it tries. ## Two packages in one lesson Showing a border between packages needs two of them. The program is the lesson's own package; the library, `Tally`, sits in a folder beside `Src/` with its own manifest: ```text Visibility/ ├── Rux.toml the program, which depends on Tally ├── Src/ │ └── Main.rux └── Tally/ ├── Rux.toml Type = "SourceLibrary" └── Src/ └── Counter.rux ``` The program's `Rux.toml` names the library under `[Dependencies]`: ```toml Tally = { Path = "Tally" } ``` That is a *path dependency*, and [Dependency](https://rux-lang.dev/docs/learn/dependency) covers it properly. For now it is enough that one `rux run` compiles both packages, and that `Main.rux` can then write `import Tally::Counter;`. ## `pub`, one declaration at a time Visibility is chosen for each declaration separately, and a member does not inherit it from its type. In `Tally/Src/Counter.rux`: ```rux pub struct Counter { pub step: int; count: int; } ``` `Counter` is public and so is its `step` field, but `count` is not. The functions in the `extend` block are each marked too, and the limit and the helper that enforces it are left private: | Declaration in `Tally` | `pub`? | What `Main.rux` can do with it | | ------------------------- | ------ | ------------------------------ | | `struct Counter` | yes | import it and name the type | | field `step` | yes | read it and change it | | field `count` | no | nothing — not even read it | | `Counter(step)`, `Tick()` | yes | call them | | `Count()` | yes | call it, to learn the count | | `const Limit`, `Clamp(…)` | no | nothing — not even import them | ## A private field keeps a promise The library's one promise is that `count` never goes past `Limit`. Every change to it goes through `Tick`, and `Tick` clamps: ```rux pub func Tick(self: &var Counter) { self.count = Clamp(self.count + self.step); } ``` Because `count` is private, there is no other way in. The program ticks three times with a step of 4: ```rux var counter = Counter(4); counter.Tick(); counter.Tick(); counter.Tick(); ``` Three ticks of 4 would make 12, but the program prints `count 10`. Nothing in `Main.rux` can push it further, because nothing in `Main.rux` can touch `count`. The public constructor is the only way to make a `Counter` at all: a struct literal would have to set `count`, so it is refused. ```mermaid flowchart LR main["Visibility
`Src/Main.rux`"] subgraph tally ["`package Tally`"] direction TB pubs["`pub`: `Counter`, `step`,
`Counter()`, `Tick()`, `Count()`"] privs["private: `count`,
`Limit`, `Clamp()`"] pubs -- "used inside
the package" --> privs end main -- "allowed" --> pubs main -.->|"refused"| privs ``` This is the usual shape of a good library: a small public surface, and private details that it is free to change later without breaking anyone. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Packages/Visibility){rel=""nofollow""}. Its comments explain every step. ::code-tree{default-value="Src/Main.rux"} ```toml [Rux.toml] [Manifest] Version = 1 MinRux = "0.4.0" [Package] Name = "Visibility" Version = "0.1.0" Type = "Executable" Description = "What pub lets a dependent package see, and what it keeps private" Authors = ["Rux Contributors "] [Dependencies] Io = { Namespace = "Rux", Version = "*" } Tally = { Path = "Tally" } ``` ```toml [Tally/Rux.toml] [Manifest] Version = 1 MinRux = "0.4.0" [Package] Name = "Tally" Version = "0.1.0" Type = "SourceLibrary" Description = "A counter library whose count can only grow up to its limit" Authors = ["Rux Contributors "] ``` ```rux [Src/Main.rux] // Inside one package, every file sees every declaration. `pub` matters at the boundary between // packages: it marks what a package lets the packages that depend on it see. // // This lesson needs two packages to show that. The companion library lives in `Tally/`, beside // `Src/`, with its own `Rux.toml`. This package's manifest lists it under `[Dependencies]` as // `Tally = { Path = "Tally" }`, so building this program compiles the library as well. // // Visibility is chosen per declaration, and a member does not inherit it from its type. `Counter` // is public, its `step` field is public, and its `count` field is not. A caller can read `step`, // but can learn the count only by asking `Count()`, and can change it only through `Tick()`, which // never lets it pass the library's private limit. import Io::PrintLine; import Tally::Counter; // A private function cannot even be imported. Adding it to the import above is rejected: // // import Tally::{ Counter, Clamp }; // // error: function 'Clamp' is private to package 'Tally' // help: add 'pub' to the declaration of 'Clamp' func Main() -> int { // The public constructor is the only way to make a `Counter` here. A struct literal would have // to set the private `count`, and is refused for that reason. var counter = Counter(4); counter.Tick(); counter.Tick(); counter.Tick(); // Three ticks of 4 would make 12; the library's private limit keeps it at 10. PrintLine("step {}, count {}", counter.step, counter.Count()); // The private field itself is out of reach, for reading as much as for writing: // // counter.count = 0; // // error: struct field 'count' is private to package 'Tally' // help: add 'pub' before the declaration of 'count' return 0; } ``` ```rux [Tally/Src/Counter.rux] // The companion library. It is a package of its own, with its own `Rux.toml`, so everything in it // is private to it unless it says `pub`. // // The public surface is the `Counter` type, its `step` field and three of its functions. The // running total, the limit and the helper that enforces the limit stay private, and that is the // whole point: no caller can push `count` past `Limit`, because no caller can touch `count`. pub struct Counter { pub step: int; count: int; } extend Counter { pub func Counter(step: int) -> Counter { return Counter { step: step, count: 0 }; } pub func Tick(self: &var Counter) { self.count = Clamp(self.count + self.step); } pub func Count(self: &Counter) -> int { return self.count; } } const Limit: int = 10; func Clamp(value: int) -> int { return value > Limit ? Limit : value; } ``` :: ## Run it ```sh cd Examples/Packages/Visibility rux run ``` ```text step 4, count 10 ``` ## Common mistakes ::mistake **Importing a private item.**:br A private function cannot even be imported. `import Tally::{ Counter, Clamp };` fails with: ```text error: function 'Clamp' is private to package 'Tally' ``` The help line says "add 'pub' to the declaration of 'Clamp'". The private constant is refused the same way, as: ```text constant 'Limit' is private to package 'Tally' ``` :: ::mistake **Reaching for a private field.**:br`counter.count = 0;` fails with: ```text error: struct field 'count' is private to package 'Tally' ``` Reading it is refused just the same. Ask the type instead, through `Count()`. :: ::mistake **Building a struct that has private fields.**:br`Counter { step: 4, count: 0 }` fails with: ```text error: struct 'Counter' cannot be initialized outside its package because it has private fields ``` The help line says "use a public constructor instead". Call `Counter(4)`. :: ::mistake **Making the type public but not its methods.**:br`pub` on a struct does not reach its methods. Remove it from `Tick` and the call fails with: ```text error: method 'Tick' is private to package 'Tally' ``` Take it off the struct instead, and even the import fails: ```text error: type 'Counter' is private to package 'Tally' ``` :: ## Try it yourself 1. `step` is public, so the program may change it. Set `counter.step = 1;` before the ticks and predict the output. 2. Add a public `Reset` method to `Counter` in `Tally/Src/Counter.rux` that sets `count` back to 0, and call it from `Main`. 3. Make `Limit` public, import it next to `Counter`, and print it. Is the promise about `count` any weaker now? ## Learn more - [Items visibility](https://rux-lang.dev/docs/lang/modules/visibility) in the Rux Reference - [Constructor](https://rux-lang.dev/docs/learn/constructor) and [Mutating method](https://rux-lang.dev/docs/learn/mutating-method) — the two kinds of function `Counter` exposes - [Dependency](https://rux-lang.dev/docs/learn/dependency) — the `Path` line that connects the two packages - [Documentation](https://rux-lang.dev/docs/learn/documentation) — describing the `pub` items for the people who use them # Package ::note **You'll need**: [Module](https://rux-lang.dev/docs/learn/module), [Enum](https://rux-lang.dev/docs/learn/enum), [Match expression](https://rux-lang.dev/docs/learn/match-expression) :: Every lesson so far has had a `Rux.toml` beside its `Src/` folder, and you have mostly ignored it. That file is the **package manifest**: it tells `rux` what the package is called, what it builds and what it needs. This lesson reads one section by section, and its program asks the compiler to report back on its own manifest. ## The manifest, section by section Here is this lesson's `Rux.toml` in full: ```toml [Rux.toml] [Manifest] Version = 1 MinRux = "0.4.0" [Package] Name = "Package" Version = "0.1.0" Type = "Executable" Description = "The parts of a Rux.toml manifest and the four package types" Authors = ["Rux Contributors "] [Dependencies] Core = { Namespace = "Rux", Version = "*" } Io = { Namespace = "Rux", Version = "*" } ``` It has three sections, each about something different: | Section | Describes | Fields used here | | ---------------- | ----------------------------- | ---------------------------------------------------------------------------------------- | | `[Manifest]` | the file itself | `Version`, the schema; `MinRux`, the oldest compiler | | `[Package]` | the package | `Name`, `Version`, `Type`, `Description`, `Authors` | | `[Dependencies]` | the packages this one imports | one line per import name — the [next lesson](https://rux-lang.dev/docs/learn/dependency) | The manifest is strict. Field names are case-sensitive, and an unknown field is an error rather than something quietly ignored, so a typo fails the build instead of silently changing it. ## Two versions that have nothing to do with each other The file has two `Version` lines, and they answer different questions. `[Manifest].Version = 1` is the **schema** version: which set of rules the file is written in. It is always written out, never inferred, and 1 is the only one so far. `[Package].Version = "0.1.0"` is the package's own **release number**, a semantic version that you raise as the package changes. `MinRux` sits next to the schema version because it is also about reading the file: a compiler older than `MinRux` refuses the package before compiling anything. ## `Name` reaches further than it looks `Name` is more than a label. It is the first segment of every import path into the package — you used that in [Module](https://rux-lang.dev/docs/learn/module), where every path began with `Module::` — and it is the name of what the build produces. `rux run` here builds `Bin/Debug///Package.exe` on Windows. ## Four package types `Type` is required, and it decides what `rux build` makes: ```mermaid flowchart LR t(["`[Package].Type`"]) --> exe["`Executable`
a program with `Main`"] t --> src["`SourceLibrary`
compiled into each
package that uses it"] t --> sta["`StaticLibrary`
`.lib` or `.a` archive"] t --> sha["`SharedLibrary`
`.dll`, `.so` or `.dylib`"] exe --> run["`rux build` and `rux run`"] src --> check["`rux check` only"] sta --> build["`rux build`"] sha --> build ``` Every lesson so far has been an `Executable`. The other three are the subject of [Source library](https://rux-lang.dev/docs/learn/source-library), [Static library](https://rux-lang.dev/docs/learn/static-library) and [Shared library](https://rux-lang.dev/docs/learn/shared-library). ## The program reads its own manifest `#build` and `#compiler` are values the compiler fills in while it compiles, imported from `Core` like any other item. [Part 23: Compile time](https://rux-lang.dev/docs/learn/compile-time) covers them properly; here they let the program see its manifest from the inside. `#build.outputKind` is `[Package].Type`: ```rux let kind = match #build.outputKind { .Executable => "Executable", .SourceLibrary => "SourceLibrary", .StaticLibrary => "StaticLibrary", .SharedLibrary => "SharedLibrary" }; ``` `#compiler.version` is the version of the compiler doing the build, so the program can compare it with the `MinRux` it declares: ```rux let minimum = SemanticVersion(0, 4, 0); PrintLine("MinRux 0.4.0 met: {}", #compiler.version.Compare(minimum) >= 0); ``` A program that runs at all always prints `true` here — a compiler that did not meet `MinRux` would have refused to build it. And `#build.profile` is `Debug` for a plain `rux run`, or `Release` with `rux run --release`. ## Starting a new package You rarely write a manifest from nothing. `rux new Name` creates a folder with a minimal `Rux.toml`, a `Src/Main.rux` and a `.gitignore`; `--source`, `--static` and `--shared` pick the other three types. The manifest it writes has only the required fields — no `MinRux`, which is optional until you publish — so you add the rest, and the `[Dependencies]` you need, by hand. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Packages/Package){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // Every lesson so far has had a `Rux.toml` beside its `Src/` directory. That file is the package // manifest, and this lesson reads it section by section. // // - `[Manifest]` describes the file itself. `Version = 1` is the manifest schema, and `MinRux` is // the oldest compiler allowed to build the package. // - `[Package]` describes the package. `Name` is also the first segment of every import path into // it. `Version` is the package's own version, unrelated to the schema version above. `Type` // decides what `rux build` produces. // - `[Dependencies]` lists the packages this one imports, one line per import name. // // `Type` is required, and it is one of four: // // Executable a program with a `Main`; `rux run` builds it and starts it // SourceLibrary source compiled into every package that depends on it // StaticLibrary a native archive: `.lib` on Windows, `.a` elsewhere // SharedLibrary a native library loaded at run time: `.dll`, `.so` or `.dylib` // // The program asks the compiler what it is building. `#build` and `#compiler` are values the // compiler fills in while it compiles, imported from `Core` like any other item. The Compile time // part covers them properly; here they let the program report on its own manifest. import Core::{ #build, #compiler, OutputKind, SemanticVersion }; import Io::PrintLine; func Main() -> int { // `outputKind` is `[Package].Type`, seen from inside the program. let kind = match #build.outputKind { .Executable => "Executable", .SourceLibrary => "SourceLibrary", .StaticLibrary => "StaticLibrary", .SharedLibrary => "SharedLibrary" }; PrintLine("Type {}", kind); // A compiler older than `MinRux` refuses the package before compiling anything, so a program // that runs at all always finds this true. let minimum = SemanticVersion(0, 4, 0); PrintLine("MinRux 0.4.0 met: {}", #compiler.version.Compare(minimum) >= 0); // `rux run` builds the Debug profile, into `Bin/Debug///Package.exe` on Windows. // The file name comes from `[Package].Name`. PrintLine("Profile {}", #build.profile); return 0; } ``` Besides `Io`, its `Rux.toml` lists `Core` under `[Dependencies]`. ## Run it ```sh cd Examples/Packages/Package rux run ``` ```text Type Executable MinRux 0.4.0 met: true Profile Debug ``` This package's own `Rux.toml`, line by line: | Line | Meaning | | --------------------------------------------- | -------------------------------------------------------------------------- | | `[Manifest]` | Facts about the file itself | | `Version = 1` | The manifest schema; 1 is the only one, and it is never inferred | | `MinRux = "0.4.0"` | The oldest compiler that may build the package | | `[Package]` | Facts about the package | | `Name = "Package"` | Its name, the first segment of its import paths and of its artifact's name | | `Version = "0.1.0"` | The package's own semantic version | | `Type = "Executable"` | What it builds: one of the four package types in `Src/Main.rux` | | `Description = "..."` | One line about it | | `Authors = [...]` | Who wrote it | | `[Dependencies]` | The packages it imports, one per import name | | `Core = { Namespace = "Rux", Version = "*" }` | `Core` from the registry, any version installed | `rux new Name` writes a manifest like this one; `--source`, `--static` and `--shared` select the other three types. ## Common mistakes ::mistake **Leaving out `Type`.**:br There is no default package type. Without the line, `rux` stops at: ```text error: [Package] must declare 'Type' ``` The help line lists the four choices. :: ::mistake **An old or invented type name.**:br`Type = "Program"` fails with: ```text error: [Package].Type must be 'Executable', 'SharedLibrary', 'StaticLibrary' or 'SourceLibrary', found 'Program' ``` The older spellings `Program`, `Library` and `Source` are gone, with no aliases. :: ::mistake **A misspelt field.**:br The manifest is strict: `Descripton = "…"` fails with: ```text error: unknown field 'Descripton' in [Package] ``` That is a feature — a typo cannot quietly drop a setting. :: ::mistake **Raising the wrong `Version`.**:br`[Manifest].Version` is not your release number. Set it to 2 and the build stops with: ```text error: unsupported manifest version 2 in [Manifest].Version; this compiler accepts version 1 ``` Release numbers go in `[Package].Version`. :: ::mistake **A `MinRux` newer than your compiler.**:br With `MinRux = "9.0.0"`, nothing is compiled: ```text error: package 'Package' requires Rux '9.0.0' or newer, but this is Rux '0.4.0' ``` Install a newer `rux`, or lower `MinRux` if the package really builds with an older one. :: ## Try it yourself 1. Run `rux run --release` and compare the `Profile` line with a plain `rux run`. 2. Change `Type` to `StaticLibrary` and try `rux run`. Then try `rux build` and find the file it writes under `Bin/`. 3. Run `rux info` in this folder. Which manifest fields does it show? 4. Outside the Examples repository, run `rux new Sketch --source` and compare its `Rux.toml` and `Src/` with this lesson's. ## Learn more - [Package manifest](https://rux-lang.dev/docs/packaging/manifest) — every section and field, with the validation rules - [Package types](https://rux-lang.dev/docs/packaging/types) — what each `Type` builds on each platform - [`rux new`](https://rux-lang.dev/docs/cli/new) and [`rux info`](https://rux-lang.dev/docs/cli/info) in the CLI reference - [Match expression](https://rux-lang.dev/docs/learn/match-expression) — the `match` that turns `outputKind` into text # Dependency ::note **You'll need**: [Package](https://rux-lang.dev/docs/learn/package), [Visibility](https://rux-lang.dev/docs/learn/visibility) :: Almost every program in this course has started with `import Io::PrintLine;`, and that import only works because the manifest lists `Io` as a **dependency**. This lesson looks at that list properly. There are two kinds of dependency — packages from the registry, and packages in a folder on your own disk — and this program uses both. ## The `[Dependencies]` section The lesson's `Rux.toml` ends with three lines: ```toml [Dependencies] Io = { Namespace = "Rux", Version = "*" } Math = { Namespace = "Rux", Version = "*" } Units = { Path = "Units" } ``` The key on the left of each line is the **import name**: the first segment of every `import` that reaches into that package. `Io = …` is what makes `import Io::PrintLine;` mean something. The inline table on the right says where the package comes from, and its shape decides which kind of dependency it is. ## Registry dependencies A registry dependency names a **namespace** and a **version requirement**. `Io` and `Math` are standard packages, published under the `Rux` namespace. They ship with the compiler, so they are already in the package cache on your machine; for any other registry package, `rux install` downloads a matching version into that cache once, and builds read it from there without going online again. The requirement says which versions are acceptable: | Requirement | Accepts | | ----------------- | ------------------------------------ | | `*` | any version — whichever is installed | | `^0.1.0` | 0.1.x, but not 0.2.0 | | `>=1.2.0, <2.0.0` | a range spelt out | `rux list` shows what each line resolved to — here `Resolved Rux/Io @ * to 0.1.0`, the same for `Math`, and `Path Units at 'Units'`. ::note **Standard packages are declared by hand.**:br In Rux 0.4.0, `rux add Rux/Io` does not work for the standard packages. Write their line into `Rux.toml` yourself, as every lesson in this course does: `Io = { Namespace = "Rux", Version = "*" }`. :: ## Path dependencies A path dependency names a folder holding a `Rux.toml`, relative to this manifest. Here it is `Units/`, right beside `Src/`: ```rux pub const KilometresPerMile: float64 = 1.609344; pub func ToMiles(kilometres: float64) -> float64 { return kilometres / KilometresPerMile; } ``` Its source is compiled with the program, so an edit to `Units/Src/Units.rux` shows up on the next build, and nothing needs installing. The price is that a package with a path dependency cannot be **published**: the path means nothing on anyone else's machine. ## Both kinds look the same in the code Once declared, nothing in the source says where a package came from: ```rux import Io::PrintLine; import Math::{ Hypot, Round }; import Units::ToMiles; ``` ```mermaid flowchart LR reg[("registry")] -- "`rux install`
(once)" --> cache[("package cache
`Io`, `Math`")] cache -- "`Namespace` + `Version`" --> prog["Dependency
`Src/Main.rux`"] folder["`Units/`
beside `Src/`"] -- "`Path`" --> prog prog --> exe["`Dependency.exe`"] ``` `Hypot(3.0, 4.0)` from `Math` is the length of the long side of a right triangle — five kilometres for three east and four north — and `ToMiles` from `Units` converts it. `Round(… * 100.0) / 100.0` keeps two decimal places. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Packages/Dependency){rel=""nofollow""}. Its comments explain every step. ::code-tree{default-value="Src/Main.rux"} ```toml [Rux.toml] [Manifest] Version = 1 MinRux = "0.4.0" [Package] Name = "Dependency" Version = "0.1.0" Type = "Executable" Description = "Registry dependencies from the package cache and a path dependency beside the source" Authors = ["Rux Contributors "] [Dependencies] Io = { Namespace = "Rux", Version = "*" } Math = { Namespace = "Rux", Version = "*" } Units = { Path = "Units" } ``` ```toml [Units/Rux.toml] [Manifest] Version = 1 MinRux = "0.4.0" [Package] Name = "Units" Version = "0.1.0" Type = "SourceLibrary" Description = "Distance conversions, reached by a path dependency" Authors = ["Rux Contributors "] ``` ```rux [Src/Main.rux] // A package names what it needs in the `[Dependencies]` section of its `Rux.toml`. Each line's key // is the import name, the first segment of every `import` that reaches into that package. This // program uses both kinds of dependency there are: // // Io = { Namespace = "Rux", Version = "*" } // Math = { Namespace = "Rux", Version = "*" } // Units = { Path = "Units" } // // A registry dependency names a namespace and a version requirement. `rux install` downloads a // matching version into the package cache on this machine, and builds then read it from there, // without going online again. `*` accepts any version; `^0.1.0` would accept 0.1.x but not 0.2.0, // and `>=1.2.0, <2.0.0` spells a range out. // // A path dependency names a directory holding a `Rux.toml`, relative to this manifest. The source // there is compiled with this program, edits to it are seen on the next build, and nothing needs // installing. A package with a path dependency cannot be published, because the path means // nothing on anyone else's machine. // // Once declared, the two kinds look the same in the code. import Io::PrintLine; import Math::{ Hypot, Round }; import Units::ToMiles; func Main() -> int { // Three kilometres east, then four north: how far from the start, as the crow flies? let kilometres = Hypot(3.0, 4.0); let miles = Round(ToMiles(kilometres) * 100.0) / 100.0; PrintLine("straight line {} km", kilometres); PrintLine("which is {} miles", miles); return 0; } ``` ```rux [Units/Src/Units.rux] // A small library of our own, kept in a directory beside the program that uses it. Nothing about it // is published anywhere: the program finds it by its path. pub const KilometresPerMile: float64 = 1.609344; pub func ToMiles(kilometres: float64) -> float64 { return kilometres / KilometresPerMile; } ``` :: ## Run it ```sh cd Examples/Packages/Dependency rux run ``` ```text straight line 5.0 km which is 3.11 miles ``` ## Common mistakes ::mistake **Importing a package the manifest does not list.**:br Delete the `Math` line and the build stops before any code is checked: ```text error: package 'Math' is not listed in [Dependencies] ``` It comes with the note "the import requires a package dependency with the same import name". Every import name needs its line. :: ::mistake **A path that points nowhere.**:br With `Path = "Unit"`, `rux` reports the missing folder, then the dependency it could not load: ```text error: could not open the manifest error: cannot load dependency package 'Units' ``` The path is relative to the manifest that declares it, not to the folder you run `rux` from. :: ::mistake **Leaving out the version.**:br`Math = { Namespace = "Rux" }` fails with: ```text error: registry dependency 'Math' must declare 'Version' ``` Write `Version = "*"` if any version will do. :: ::mistake **Mixing the two kinds.**:br A dependency is one kind or the other. `Units = { Path = "Units", Version = "*" }` fails with: ```text error: path dependency 'Units' cannot also declare 'Namespace' or 'Version' ``` :: ::mistake **A requirement nothing installed can meet.**:br With `Version = "^9.0.0"` for `Math`, the build fails with: ```text error: no installed version of 'Rux/Math' satisfies '^9.0.0' ``` A note lists the versions that are installed. Loosen the requirement, or install a version that matches. :: ## Try it yourself 1. Change the requirement for `Math` to `^0.1.0` and run `rux list`. Does anything change in the build? 2. Add a `ToKilometres` function to `Units` and use it to convert the rounded `miles` back. Why is the answer not exactly 5.0? 3. The import name does not have to match the package's own name. Rename the line to `Distance = { Path = "Units", Package = "Units" }` and change the import to match. ## Learn more - [Dependencies](https://rux-lang.dev/docs/packaging/dependencies) — requirement syntax, the package cache and target-specific dependencies - [`rux install`](https://rux-lang.dev/docs/cli/install) and [`rux list`](https://rux-lang.dev/docs/cli/list) in the CLI reference - [Math](https://rux-lang.dev/docs/learn/math) — the standard package this program borrows `Hypot` and `Round` from - [Workspace](https://rux-lang.dev/docs/learn/workspace) — several packages, with path dependencies between them, kept in one tree # Workspace ::note **You'll need**: [Dependency](https://rux-lang.dev/docs/learn/dependency), [For](https://rux-lang.dev/docs/learn/for) :: A project often grows into several packages that you work on together: a program, plus the libraries it is built from. You could keep them in unrelated folders and connect them with path dependencies, as [Dependency](https://rux-lang.dev/docs/learn/dependency) did. A **workspace** goes one step further: it puts them in one tree under a single root manifest, so one command can check, build or lint all of them at once. ## A root manifest with `[Workspace]` The `Rux.toml` at the root of this lesson has no `[Package]` section. It has `[Workspace]` instead: ```toml [Rux.toml] [Manifest] Version = 1 MinRux = "0.4.0" [Workspace] Packages = [ "App", "Temperature", ] ``` `Packages` lists every **member** by its folder. The list is explicit: there are no wildcards, and every member must sit inside the root, so adding a package to the project means adding a line here. A manifest has either `[Package]` or `[Workspace]`, never both — a workspace is not a package. It has no source of its own, declares no dependencies and has nothing to run. ```text Workspace/ ├── Rux.toml [Workspace], listing the two members ├── App/ │ ├── Rux.toml Type = "Executable" │ └── Src/Main.rux └── Temperature/ ├── Rux.toml Type = "SourceLibrary" └── Src/Temperature.rux ``` ## Members are ordinary packages Each member has its own manifest and is written exactly as a lone package would be. Being listed changes nothing about it — and in particular, membership does **not** create dependencies. The program still names the library in its own `App/Rux.toml`: ```toml Temperature = { Path = "../Temperature" } ``` Then `App/Src/Main.rux` imports it like any other package: ```rux import Io::PrintLine; import Temperature::ToFahrenheit; ``` So a workspace answers "which packages make up this project?", while each member's `[Dependencies]` still answers "which packages does this one use?": ```mermaid flowchart LR root(["`Workspace/Rux.toml`
`[Workspace]`"]) -. "member" .-> app["App
`Executable`"] root -. "member" .-> temp["Temperature
`SourceLibrary`"] app -- "`Path = ../Temperature`" --> temp app --> exe["`App.exe`"] ``` ## Commands at the root and in a member At the root, `rux` works on every member in turn: | Where you are | Command | What happens | | ------------- | --------------------------------- | ----------------------------------------------------- | | root | `rux check` | checks both members: `Checked 2 packages` | | root | `rux build` | builds `App`; the source library has nothing to build | | root | `rux lint` | lints every member | | root | `rux run` | refused — the workspace has nothing to run | | root | `rux --manifest App/Rux.toml run` | runs the program without changing folder | | `App/` | `rux run` | builds and runs the program, as for any package | `--manifest` is a global option: it tells any `rux` command which `Rux.toml` to use instead of the one in the current folder. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Packages/Workspace){rel=""nofollow""}. Its comments explain every step. ::code-tree{default-value="Temperature/Src/Temperature.rux"} ```toml [Rux.toml] [Manifest] Version = 1 MinRux = "0.4.0" [Workspace] Packages = [ "App", "Temperature", ] ``` ```toml [App/Rux.toml] [Manifest] Version = 1 MinRux = "0.4.0" [Package] Name = "App" Version = "0.1.0" Type = "Executable" Description = "The program member of the Workspace lesson" Authors = ["Rux Contributors "] [Dependencies] Io = { Namespace = "Rux", Version = "*" } Temperature = { Path = "../Temperature" } ``` ```toml [Temperature/Rux.toml] [Manifest] Version = 1 MinRux = "0.4.0" [Package] Name = "Temperature" Version = "0.1.0" Type = "SourceLibrary" Description = "The library member of the Workspace lesson" Authors = ["Rux Contributors "] ``` ```rux [App/Src/Main.rux] // A project often grows into several packages that are worked on together: a program and the // libraries it is built from. A workspace keeps them in one tree under a single root manifest. // // The root `Rux.toml` of this lesson has no `[Package]` section. It has `[Workspace]` instead, // listing every member by its directory: // // [Workspace] // Packages = [ // "App", // "Temperature", // ] // // The list is explicit. There are no wildcards, and a member must sit inside the root, so adding // a package to the project means adding a line here. A workspace is not a package: it declares no // dependencies and has no source of its own. `rux check` or `rux build` at the root works on every // member, but the root has nothing to run, so the program is run from its own member directory. // // Membership does not create dependencies either. This program still names the library in its // own manifest, `Temperature = { Path = "../Temperature" }`, exactly as a lone package would. import Io::PrintLine; import Temperature::ToFahrenheit; func Main() -> int { let readings: float64[4] = [-40.0, 0.0, 21.5, 100.0]; for celsius in readings { PrintLine("{} C = {} F", celsius, ToFahrenheit(celsius)); } return 0; } ``` ```rux [Temperature/Src/Temperature.rux] // The library member of the workspace. It is an ordinary package with its own manifest; being // listed in the workspace changes nothing about how it is written. pub func ToFahrenheit(celsius: float64) -> float64 { return celsius * 9.0 / 5.0 + 32.0; } ``` :: ## Run it ```sh cd Examples/Packages/Workspace/App rux run ``` ```text -40.0 C = -40.0 F 0.0 C = 32.0 F 21.5 C = 70.7 F 100.0 C = 212.0 F ``` From the root, `rux check`, `rux build` and `rux lint` work on every member. `rux run` there stops, because the workspace "has nothing to run", and suggests `rux --manifest App/Rux.toml run`, which runs the program without changing directory. ## Common mistakes ::mistake **Running the workspace.**:br`rux run` at the root stops with: ```text error: manifest '…\Workspace\Rux.toml' is a workspace and has nothing to run ``` The help line suggests `rux --manifest App/Rux.toml run`. Run that, or change into `App/` first. :: ::mistake **Expecting membership to connect packages.**:br Remove the `Temperature` line from `App/Rux.toml` and the import fails, even though both packages are members: ```text error: package 'Temperature' is not listed in [Dependencies] ``` Each member declares what it uses. :: ::mistake **A wildcard in the member list.**:br`Packages = ["*"]` is not a pattern. `rux` takes it as a folder name and reports: ```text error: workspace member '*' has no Rux.toml ``` List every member by name. :: ::mistake **A member outside the root.**:br`"../Dependency"` in the list fails with: ```text error: '[Workspace].Packages item' cannot contain a '..' component ``` A workspace owns its members, so they live inside it. A package elsewhere can still be a path dependency. :: ## Try it yourself 1. From the workspace root, run `rux check`, then `rux --manifest App/Rux.toml run`. 2. Delete `"Temperature",` from the root manifest and run `rux check` at the root again. How many packages are checked now — and does `App` still build? 3. Add a third member: a source library called `Kelvin` with a `pub` function `ToKelvin(celsius: float64) -> float64`. List it in the workspace, depend on it from `App`, and print each reading in kelvin too. ## Learn more - [Workspaces](https://rux-lang.dev/docs/packaging/manifest#workspaces) in the package manifest reference - [Global options](https://rux-lang.dev/docs/cli/global) — `--manifest` and the other options every command accepts - [`rux check`](https://rux-lang.dev/docs/cli/check) and [`rux build`](https://rux-lang.dev/docs/cli/build) in the CLI reference - [Source library](https://rux-lang.dev/docs/learn/source-library) — the kind of package `Temperature` is # Source library ::note **You'll need**: [Dependency](https://rux-lang.dev/docs/learn/dependency), [Generic](https://rux-lang.dev/docs/learn/generic), [Slice](https://rux-lang.dev/docs/learn/slice) :: You have already used several libraries: `Tally`, `Units` and `Temperature` earlier in this part, and `Io` in nearly every lesson before that. All of them are **source libraries**, `Type = "SourceLibrary"`, the usual kind of library in Rux. This lesson looks at what that type means: a source library is never compiled on its own. Its source is compiled into each package that depends on it, and that is what lets a generic function in it work with types the library has never heard of. ## Compiled into the program that uses it The library is in `Stats/`, beside `Src/`, and the program depends on it by path: ```toml Stats = { Path = "Stats" } ``` When you build the program, the compiler reads `Stats/Src/Stats.rux` along with the program's own `Src/Main.rux`, almost as if the library's files were part of the program. "Almost", because `pub` still guards the border between the two, exactly as in [Visibility](https://rux-lang.dev/docs/learn/visibility). One build, one executable: ```mermaid flowchart LR lib["`Stats/Src/Stats.rux`
generic `Largest`"] --> c["`rux build`
(in `SourceLibrary/`)"] main["`Src/Main.rux`
`int32` and `float64` calls"] --> c c --> exe["`SourceLibrary.exe`
`Largest` for `int32`
`Largest` for `float64`"] ``` So a source library produces nothing by itself — no `.lib`, no `.dll`, nothing in `Bin/`. ## A generic function, made to order The whole library is one generic function: ```rux pub func Largest(values: T[..]) -> T { var best = values[0]; for value in values { if value > best { best = value; } } return best; } ``` There is no single machine-code `Largest` anywhere, because the library is never compiled alone. Each program that depends on it compiles this source with its own and gets one `Largest` for every element type it actually uses. This one passes it two arrays: ```rux let scores: int32[5] = [72, 95, 88, 61, 90]; let prices: float64[3] = [4.25, 19.99, 7.5]; PrintLine("highest score {}", Largest(scores)); PrintLine("highest price {}", Largest(prices)); ``` so `Largest` is compiled twice, once with `T` as `int32` and once with `T` as `float64`. A different program could use it for `char` and get a third. That is the main reason Rux libraries are shipped as source: generic code can serve the user's types. ## Checked alone, never built alone You can still work on a source library by itself. In `Stats/`, `rux check` parses and type-checks it. The commands that would make an artifact refuse: | Command in `Stats/` | Result | | ------------------- | ---------------------------------------------------------------- | | `rux check` | `Checked 1 package` — the library on its own is valid | | `rux build` | refused: it "cannot be built or run as a top-level target" | | `rux run` | refused: "package 'Stats' is a source library and cannot be run" | To see the library do anything, build or run a package that uses it — here, the lesson's own program. ## Errors show up where the type meets the code A generic function only promises to work for types that support what it does. `Largest` uses `>`, so it works for numbers and characters, but not for a struct that declares no `>`. Because the library is compiled with your program, that problem is found when your program is built — and reported inside the library's source, with a note pointing back at your call. [Generic bound](https://rux-lang.dev/docs/learn/generic-bound) shows how a library can state such a requirement up front instead. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Packages/SourceLibrary){rel=""nofollow""}. Its comments explain every step. ::code-tree{default-value="Src/Main.rux"} ```toml [Rux.toml] [Manifest] Version = 1 MinRux = "0.4.0" [Package] Name = "SourceLibrary" Version = "0.1.0" Type = "Executable" Description = "A source library compiled into the program that depends on it" Authors = ["Rux Contributors "] [Dependencies] Io = { Namespace = "Rux", Version = "*" } Stats = { Path = "Stats" } ``` ```toml [Stats/Rux.toml] [Manifest] Version = 1 MinRux = "0.4.0" [Package] Name = "Stats" Version = "0.1.0" Type = "SourceLibrary" Description = "Generic statistics, shipped as source" Authors = ["Rux Contributors "] ``` ```rux [Src/Main.rux] // `Type = "SourceLibrary"` is the usual kind of library in Rux, and every standard package such as // `Io` is one. Its source is compiled into each package that depends on it, as if its files were // part of that package, while `pub` still guards the boundary between the two. // // So a source library produces nothing by itself. In `Stats/`, `rux check` works, but the commands // that would make an artifact refuse: // // rux build // error: package 'Stats' has Type = "SourceLibrary" and is compiled into dependent packages; // it cannot be built or run as a top-level target // // The program is where it all comes together. Building this package compiles `Stats` with it, and // that is what lets a generic library function serve types the library never heard of: `Largest` // is compiled here for `int32` and again for `float64`, because those are what this program // passes it. import Io::PrintLine; import Stats::Largest; func Main() -> int { let scores: int32[5] = [72, 95, 88, 61, 90]; let prices: float64[3] = [4.25, 19.99, 7.5]; PrintLine("highest score {}", Largest(scores)); PrintLine("highest price {}", Largest(prices)); return 0; } ``` ```rux [Stats/Src/Stats.rux] // A generic function in a source library. The library is never compiled on its own, so there is // no single machine-code `Largest` here. Each program that depends on the library compiles this // source along with its own and gets a `Largest` for every element type it actually uses. pub func Largest(values: T[..]) -> T { var best = values[0]; for value in values { if value > best { best = value; } } return best; } ``` :: ## Run it ```sh cd Examples/Packages/SourceLibrary rux run ``` ```text highest score 95 highest price 19.99 ``` ## Common mistakes ::mistake **Building the library itself.**:br In `Stats/`, `rux build` fails with: ```text error: package 'Stats' has Type = "SourceLibrary" and is compiled into dependent packages; it cannot be built or run as a top-level target ``` Use `rux check` there, and build the program that depends on it. :: ::mistake **A type the generic code cannot handle.**:br Pass `Largest` an array of a struct `Point` and the error is reported at `value > best` in `Stats.rux`: ```text error: operator '>' is not defined for 'Point' ``` The note under it, "in 'Largest' instantiated with T = Point by the call at …", leads back to the line in your program. Strings fail the same way, as: ```text operator '>' is not defined for slice type 'char8[..]' ``` :: ::mistake **An empty slice.**:br`Largest` reads `values[0]` before it looks at anything else. Give it an empty slice and the program stops at run time with: ```text Panic: index out of range ``` The library trusts its caller here; a safer version would return an optional instead. :: ## Try it yourself 1. Add `pub func Smallest(values: T[..]) -> T` to `Stats` and print the lowest score and the lowest price. 2. Call `Largest` with an array of `char`, such as `['r', 'u', 'x']`. Which letter wins, and why? 3. Change `Largest` to return `T?` and give back `none` when `values.length` is 0. Update the program to print a fallback with `??`. ## Learn more - [Package types](https://rux-lang.dev/docs/packaging/types) — how a source library differs from the other three - [Generic](https://rux-lang.dev/docs/learn/generic) and [Generic bound](https://rux-lang.dev/docs/learn/generic-bound) — writing functions that work for many types - [Static library](https://rux-lang.dev/docs/learn/static-library) — a library compiled ahead of time instead - [`rux check`](https://rux-lang.dev/docs/cli/check) — the one command a source library answers to on its own # Static library ::note **You'll need**: [Package](https://rux-lang.dev/docs/learn/package), [Source library](https://rux-lang.dev/docs/learn/source-library) :: A [source library](https://rux-lang.dev/docs/learn/source-library) waits to be compiled into whatever uses it. A **static library** is the opposite: the package is compiled ahead of time, straight to machine code, and packed into a native archive. Archives are what native toolchains — C and C++ linkers, for instance — know how to use, so this is how Rux code is handed to them. This package has no `Main` and nothing to run; the lesson is about what the build produces. ## Asking for an archive One line of the manifest changes: ```toml Type = "StaticLibrary" ``` `rux build` then writes an archive whose name follows each platform's convention: | Platform | File written by `rux build` | | --------------------- | ---------------------------------------------------------- | | Windows | `Bin/Debug/Windows/x86-64/StaticLibrary.lib` | | Linux, macOS, FreeBSD | `libStaticLibrary.a`, in the matching `Bin/Debug/…` folder | `rux build --release` writes the optimised version under `Bin/Release/` instead. A native linker treats an archive as a box of parts: when it builds a program, it copies in the functions that program calls, and leaves the rest. The finished program carries its own copy of everything it took, so nothing extra has to ship beside it. ## One symbol per function Inside the archive, each function is a **symbol** — a name a linker can bind a call to. The source decides which names are offered to the outside: ```rux pub func Area(width: int, height: int) -> int { return width * height; } pub func Perimeter(width: int, height: int) -> int { return Double(width + height); } func Double(value: int) -> int { return 2 * value; } ``` `Area` and `Perimeter` are `pub`, so they become **global** symbols that other code can link against. `Double` is package-private, so it becomes a **local** symbol: it is in the archive, because `Perimeter` needs it, but nothing outside can bind to it. A symbol lister shows the difference. With LLVM installed, `llvm-nm` on the Windows archive prints: ```text Main.obj: 00000000 T Area 00000137 t Double 0000008e T Perimeter ``` Capital `T` means a global function, lower-case `t` a local one. The numbers are positions within the compiled code and change as the code does. `Main.obj` is named after the source file, `Src/Main.rux`. ```mermaid flowchart LR src["`Src/Main.rux`"] -- "`rux build`" --> lib["`StaticLibrary.lib`
`T Area`, `T Perimeter`
`t Double`"] other["another program
(C, C++, …)"] --> link["native linker"] lib --> link link --> exe["`program.exe`
with its own copy of
`Area` and `Perimeter`"] ``` ## What a static library is not It is **not a program**. There is no `Main`, so `rux run` refuses to start it. It is also **not what Rux packages consume**. If another Rux package lists this one under `[Dependencies]`, it compiles this package's *source*, exactly as it would a source library, and `pub` works as it always does: `Area` can be imported, `Double` cannot. In Rux 0.4.0 every dependency is taken as source. The archive is for native toolchains, not for other Rux packages. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Packages/StaticLibrary){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // `Type = "StaticLibrary"` asks `rux build` for a native archive: the package compiled ahead of // time to machine code and packed into `StaticLibrary.lib` on Windows, or `libStaticLibrary.a` on // Linux, macOS and FreeBSD. A native linker copies what it needs from an archive into the program // it is building, so nothing extra has to ship beside that program. // // The archive holds one symbol per function. `Area` and `Perimeter` are `pub`, so they become // global symbols that other code can link against. `Double` is package-private, so it becomes a // local symbol: it is in the archive, because `Perimeter` calls it, but nothing outside can bind // to it. // // Two things a static library is not: // // - It is not a program. There is no `Main`, and `rux run` refuses with "package 'StaticLibrary' // produces a static library and cannot be run". // - It is not what Rux packages consume. A package that lists this one under `[Dependencies]` // compiles its source, exactly as it would a source library; in Rux 0.4.0 dependencies are // always taken as source. The archive is for native toolchains. pub func Area(width: int, height: int) -> int { return width * height; } pub func Perimeter(width: int, height: int) -> int { return Double(width + height); } func Double(value: int) -> int { return 2 * value; } ``` ## Run it ```sh cd Examples/Packages/StaticLibrary rux build ``` ```text Compiling StaticLibrary v0.1.0 (Debug, Windows x86-64) Built StaticLibrary (Debug, Windows x86-64) in 1 ms Output: Bin\Debug\Windows\x86-64\StaticLibrary.lib 1 file | 28 LOC | 61 tokens | 18.6K LOC/s | StaticLibrary.lib 1 KB ``` Any symbol lister shows what the archive holds; with LLVM installed, `llvm-nm Bin/Debug/Windows/x86-64/StaticLibrary.lib` prints `T` for the global `Area` and `Perimeter` and `t` for the local `Double`. ## Common mistakes ::mistake **Running a library.**:br`rux run` fails with: ```text error: package 'StaticLibrary' produces a static library and cannot be run ``` The message notes that "only executable packages have an entry point". Use `rux build`. :: ::mistake **Expecting a private function to be linkable.**:br`Double` is in the archive, but only as a local symbol, so a native linker cannot resolve a call to it from outside. Add `pub` to anything other code should be able to call. :: ::mistake **Expecting a Rux dependency to use the archive.**:br A Rux package that depends on this one compiles its source instead. Building the archive first changes nothing for it, and `import StaticLibrary::{ Area, Double };` still fails with: ```text error: function 'Double' is private to package 'StaticLibrary' ``` :: ## Try it yourself 1. Add a `pub` function `Volume(width: int, height: int, depth: int) -> int`, rebuild, and list the symbols again. Which letter does `Volume` get? 2. Make `Double` public and list the symbols. What changed? 3. Run `rux build --release`. Where does the archive go, and does `llvm-nm` show the same three symbols in it? 4. Write a small executable package beside this one that depends on it with `Path` and prints `Area(3, 4)`. Does its build use `StaticLibrary.lib`? ## Learn more - [Package types](https://rux-lang.dev/docs/packaging/types) — the archive names on each platform - [`rux build`](https://rux-lang.dev/docs/cli/build) in the CLI reference - [Shared library](https://rux-lang.dev/docs/learn/shared-library) — the other native library type, loaded at run time - [Visibility](https://rux-lang.dev/docs/learn/visibility) — the same `pub` that decides global and local symbols here # Shared library ::note **You'll need**: [Static library](https://rux-lang.dev/docs/learn/static-library) :: A [static library](https://rux-lang.dev/docs/learn/static-library) is copied into each program that links it. A **shared library** is not copied anywhere: it ships as a file of its own, and programs load it while they run. Every program that uses it shares the one copy on disk, and the library can be replaced without rebuilding them. The source of this lesson is identical to the static library's; only `Type` differs, and with it what the build produces. ## Asking for a shared library ```toml Type = "SharedLibrary" ``` Each platform has its own name and extension for the file: | Platform | File written by `rux build` | | -------------- | ---------------------------------------------------------------- | | Windows | `SharedLibrary.dll`, plus the import library `SharedLibrary.lib` | | Linux, FreeBSD | `libSharedLibrary.so` | | macOS | `libSharedLibrary.dylib` | On Windows the build writes two files into `Bin/Debug/Windows/x86-64/`. The `.dll` is the library itself. The small `.lib` beside it is an **import library**: a native linker reads it when it builds a program, to learn which functions that program will find in the `.dll` when it starts. ## The export table: what `pub` lets out What other programs can call is the library's **export table**, and `pub` decides what goes in it: ```rux pub func Area(width: int, height: int) -> int { return width * height; } pub func Perimeter(width: int, height: int) -> int { return Double(width + height); } func Double(value: int) -> int { return 2 * value; } ``` `Area` and `Perimeter` are exported under exactly those names. `Double` is compiled into the library, because `Perimeter` calls it, but it is never exported, so no program can look it up. On Windows, `llvm-readobj --coff-exports` (with LLVM installed) or `dumpbin /exports` (from a Visual Studio prompt) lists the table; for this library it names `Area` and `Perimeter`, and nothing else. The same rule covers dependencies. A shared library built on `Io` contains the parts of `Io` it uses, but exports only its own `pub` functions, not `Io`'s. ## Static or shared? | | Static library | Shared library | | ---------------------- | -------------------------- | ------------------------------------------ | | File on Windows | `.lib` | `.dll` and an import `.lib` | | Joined to the program | when the program is linked | when the program starts | | Ships with the program | no — already copied inside | yes — the program needs the file beside it | | Updating the library | rebuild every program | replace one file | | What `pub` controls | global or local symbols | the export table | ```mermaid flowchart LR src["`Src/Main.rux`"] -- "`rux build`" --> dll["`SharedLibrary.dll`
exports `Area`, `Perimeter`"] src -- "`rux build`" --> imp["`SharedLibrary.lib`
(import library)"] imp -- "read when linking" --> prog["a program"] dll -- "loaded when it runs" --> prog ``` ## Calling it Like a static library, a shared library has no `Main`, so `rux run` refuses it. And a Rux package that depends on it compiles its source instead, as for every dependency in Rux 0.4.0. To call the exports from a separately built program, you declare them with `extern` and name the library with `#Link` — the subject of [Extern](https://rux-lang.dev/docs/learn/extern) in Part 24. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Packages/SharedLibrary){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // `Type = "SharedLibrary"` asks `rux build` for a library that programs load while they run: // `SharedLibrary.dll` on Windows, `libSharedLibrary.so` on Linux and FreeBSD, and // `libSharedLibrary.dylib` on macOS. Unlike an archive, it is not copied into the program. It // ships as its own file, and every program that loads it shares the one copy. // // What other programs can call is the library's export table, and `pub` decides what goes in it. // `Area` and `Perimeter` are exported under exactly those names. `Double` is package-private, so // it is compiled into the library but never exported: no program can look it up. The same holds // for dependencies: a library built on `Io` contains the code it uses, but exports only its own // `pub` functions, not `Io`'s. // // On Windows, the build also writes `SharedLibrary.lib` beside the `.dll`. That small file is an // import library, which a native linker reads to know which exports the program will find in the // `.dll` at run time. // // Like a static library, a shared library has no `Main`, so `rux run` refuses it; and a Rux // package that depends on it compiles its source instead, as for every dependency in Rux 0.4.0. // Calling an export from a separately built program is done with `extern` and `#Link`, which the // Platform part covers. pub func Area(width: int, height: int) -> int { return width * height; } pub func Perimeter(width: int, height: int) -> int { return Double(width + height); } func Double(value: int) -> int { return 2 * value; } ``` ## Run it ```sh cd Examples/Packages/SharedLibrary rux build ``` ```text Compiling SharedLibrary v0.1.0 (Debug, Windows x86-64) Built SharedLibrary (Debug, Windows x86-64) in 1 ms Output: Bin\Debug\Windows\x86-64\SharedLibrary.dll 1 file | 30 LOC | 61 tokens | 24.6K LOC/s | SharedLibrary.dll 2 KB ``` `SharedLibrary.lib`, the import library, is written beside the `.dll`. To see the export table, run `dumpbin /exports` from a Visual Studio prompt, or `llvm-readobj --coff-exports` with LLVM installed, on `Bin/Debug/Windows/x86-64/SharedLibrary.dll`. Both list `Area` and `Perimeter`, and not `Double`. ## Common mistakes ::mistake **Running a library.**:br`rux run` fails with: ```text error: package 'SharedLibrary' produces a shared library and cannot be run ``` The help line says "build it with 'rux build'". :: ::mistake **Forgetting `pub` on a function you mean to export.**:br Nothing warns you: the library builds, and the function is simply missing from the export table. The failure comes later, when a program that expects it is linked or loaded. List the exports after any change to the public surface. :: ::mistake **Shipping the program without the library.**:br A program that loads `SharedLibrary.dll` needs that file at run time, where the system can find it — usually beside the program. The import `.lib` is only for linking and does not need to ship. :: ## Try it yourself 1. Add a `pub` function `Volume(width: int, height: int, depth: int) -> int`, rebuild, and list the exports. Is `Volume` there? 2. Remove `pub` from `Perimeter`, rebuild and list the exports again. What happens to `Double`, which only `Perimeter` called? 3. Compare the folders that `rux build` fills in this lesson and in [Static library](https://rux-lang.dev/docs/learn/static-library). Which file appears in both, and does it mean the same thing? ## Learn more - [Package types](https://rux-lang.dev/docs/packaging/types) — shared library names on each platform - [Extern](https://rux-lang.dev/docs/learn/extern) and [C interop](https://rux-lang.dev/docs/learn/c-interop) — calling native libraries from Rux - [Link](https://rux-lang.dev/docs/lang/attributes/link) in the Rux Reference — the `#Link` attribute - [`rux build`](https://rux-lang.dev/docs/cli/build) in the CLI reference # Documentation ::note **You'll need**: [Comment](https://rux-lang.dev/docs/learn/comment), [Visibility](https://rux-lang.dev/docs/learn/visibility), [Method](https://rux-lang.dev/docs/learn/method) :: Ordinary comments are for whoever reads the source. **Documentation comments** are for whoever *uses* the code: tools collect them and turn them into reference pages, the kind you read for `Io` or `Math`. Once your package has `pub` items that other packages call, describing them is part of the job. This lesson writes documentation comments for a small `Rectangle` type and generates its pages with `rux doc`. ## Two spellings, one rule You met documentation comments briefly in [Comment](https://rux-lang.dev/docs/learn/comment). There are two spellings: `///` at the start of each line, or one `/** … */` block. Both attach to the declaration **directly below** them: ```rux /// A rectangle measured in whole units. pub struct Rectangle { /// The horizontal side. pub width: int; /// The vertical side. pub height: int; } ``` The block form suits a longer description: ```rux /** The space the rectangle covers. @returns `width` times `height` */ pub func Area(self: &Rectangle) -> int { return self.width * self.height; } ``` A blank line between the comment and the declaration detaches it. The comment then documents nothing, and the declaration is left undocumented. ## The summary and the tags The **first sentence** is the summary. Indexes show it on its own, so it should make sense without the rest: "The space the rectangle covers." rather than "Returns this.". After the prose come **tags**, which give the generator structure to work with: | Tag | Describes | | ------------- | --------------------------------------------------------------- | | `@param name` | one named parameter | | `@returns` | the result | | `@see` | a related item or a web address | | `@deprecated` | that the item should no longer be used, and what to use instead | `Scaled` documents its parameter and its result: ```rux /// Makes a copy with both sides multiplied. The original is left as it was. /// @param factor what each side is multiplied by /// @returns the scaled copy pub func Scaled(self: &Rectangle, factor: int) -> Rectangle { ``` and `Size`, an older name kept for callers who still use it, says so and points to its replacement: ```rux /// The space the rectangle covers, under its earlier name. /// @returns the same value as `Area` /// @deprecated call `Area`, whose name says what it measures /// @see `Rectangle::Area` pub func Size(self: &Rectangle) -> int { ``` Text inside a documentation comment is Markdown, which is why `` `Area` `` comes out as code in the generated page. ## Generating the pages `rux doc` checks the package as `rux check` does, then writes the pages to `Bin/Docs/`, starting at `index.html`; `rux doc --open` opens them in your browser. Only `pub` items appear, because the pages describe what other packages can use. `Main`, which is not `pub`, is left out. ```mermaid flowchart LR src["`///` and `/** */` comments
on `pub` items"] --> lint["`rux lint`
warns about missing docs
and unknown tags"] src --> doc["`rux doc`"] doc --> pages["`Bin/Docs/index.html`
one entry per `pub` item"] ``` `rux lint` reads the same comments and warns about two kinds of slip: a `pub` struct or function with no documentation at all, and a tag it does not know. Neither stops the program compiling — which is exactly why a separate check is useful. [Tooling](https://rux-lang.dev/docs/learn/tooling) puts `rux lint` and `rux doc` next to the other commands. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Packages/Documentation){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // Ordinary comments, like this one, are for whoever reads the source. Documentation comments are // for whoever uses the API: tools collect them and turn them into reference pages. There are two // spellings, `///` on each line or one `/** ... */` block, and both attach to the declaration // directly below them. A blank line in between detaches the comment. // // The first sentence is the summary, shown on its own in indexes, so it should stand alone. Tags // come after the prose and give the generator structure to work with: // // @param name ... one named parameter // @returns ... the result // @see ... a related item or a web address // @deprecated ... what to use instead // // `rux doc` writes the pages to `Bin/Docs/`, starting at `index.html`; `rux doc --open` opens them. // Only `pub` items appear, because the pages describe what other packages can use. // // Tag names are exact. Write `@return` instead of `@returns`, and the program still compiles, but // `rux lint` warns "unknown documentation tag '@return'" and `rux doc` refuses to generate the // page until it is fixed. `rux lint` also warns about any `pub` item left without documentation. import Io::PrintLine; /// A rectangle measured in whole units. pub struct Rectangle { /// The horizontal side. pub width: int; /// The vertical side. pub height: int; } extend Rectangle { /** The space the rectangle covers. @returns `width` times `height` */ pub func Area(self: &Rectangle) -> int { return self.width * self.height; } /// Makes a copy with both sides multiplied. The original is left as it was. /// @param factor what each side is multiplied by /// @returns the scaled copy pub func Scaled(self: &Rectangle, factor: int) -> Rectangle { return Rectangle { width: self.width * factor, height: self.height * factor }; } /// The space the rectangle covers, under its earlier name. /// @returns the same value as `Area` /// @deprecated call `Area`, whose name says what it measures /// @see `Rectangle::Area` pub func Size(self: &Rectangle) -> int { return self.Area(); } } func Main() -> int { let tile = Rectangle { width: 3, height: 2 }; let floor = tile.Scaled(4); PrintLine("tile {} x {} covers {}", tile.width, tile.height, tile.Area()); PrintLine("floor {} x {} covers {}", floor.width, floor.height, floor.Area()); return 0; } ``` ## Run it ```sh cd Examples/Packages/Documentation rux run ``` ```text tile 3 x 2 covers 6 floor 12 x 8 covers 96 ``` Then generate the pages, which land in `Bin/Docs/index.html`: ```sh rux doc --open ``` ## Common mistakes ::mistake **A misspelt tag.**:br Tag names are exact. Write `@return` instead of `@returns` and the program still compiles, but `rux lint` warns: ```text unknown documentation tag '@return' ``` `rux doc` refuses with this until you fix it: ```text error: invalid documentation: unknown documentation tag '@return' ``` :: ::mistake **A blank line under the comment.**:br Leave an empty line between `/// A rectangle measured in whole units.` and the struct, and `rux lint` reports two warnings: ```text documentation comment is not attached to an item public struct 'Rectangle' has no documentation comment ``` :: ::mistake **A public function with no documentation.**:br It compiles, and the pages list it with nothing to say. Add a bare `pub func Half(value: int) -> int` to this program and `rux lint` catches it: ```text warning: public function 'Half' has no documentation comment ``` Its help line suggests a comment above the declaration. :: ::mistake **Documenting private items and expecting them in the pages.**:br`rux doc` writes pages for `pub` items only. Its `--document-private-items` option includes the rest, which can help while you work on the package itself. :: ## Try it yourself 1. Run `rux doc --open` and find `Size` in the pages. How is its `@deprecated` tag shown? 2. Add a documented `pub` method `Perimeter` with a `@returns` tag, and regenerate the pages. 3. Misspell `@param` as `@parameter` and run `rux lint`, then `rux doc`. What does each say? 4. Run `rux doc --document-private-items`. What appears that was missing before? ## Learn more - [Comments](https://rux-lang.dev/docs/lang/lexical/comments) in the Rux Reference - [`rux doc`](https://rux-lang.dev/docs/cli/doc) and [`rux lint`](https://rux-lang.dev/docs/cli/lint) in the CLI reference - [Visibility](https://rux-lang.dev/docs/learn/visibility) — the `pub` that decides what is documented - [Tooling](https://rux-lang.dev/docs/learn/tooling) — the other commands that keep a package tidy # Tooling ::note **You'll need**: [Source library](https://rux-lang.dev/docs/learn/source-library), [Documentation](https://rux-lang.dev/docs/learn/documentation), [Range](https://rux-lang.dev/docs/learn/range) :: So far you have used three `rux` commands: `run`, `check` and `build`. A few more keep a package tidy once it is more than a single file — they format it, lint it, test it and document it. None of them changes what the program does; together they catch the mistakes the compiler lets through. This lesson has a small `Calendar` library, a program that uses it, and a test for it, so that every command has something to work on. ## The pieces of this lesson ```text Tooling/ ├── Rux.toml the program; depends on Calendar ├── Src/Main.rux ├── Calendar/ the code under test, a source library │ ├── Rux.toml │ └── Src/Calendar.rux └── Tests/ └── LeapYear/ one test, an executable package ├── Rux.toml └── Src/Main.rux ``` `Calendar` lives in its own library so that both the program and the test can depend on it. The program prints the length of February for five years: ```rux for year in 1900..=1904 { PrintLine("February {} has {} days", year, DaysInMonth(year, 2)); } ``` ## The commands All of them run from the package folder, `Tooling/`: | Command | What it does | | ----------------- | ------------------------------------------------------------------- | | `rux fmt` | rewrites the sources and `Rux.toml` in the standard layout | | `rux fmt --check` | changes nothing; lists the files `rux fmt` would rewrite, and fails | | `rux lint` | warns about what compiles but is still wrong, such as missing docs | | `rux test` | builds and runs every executable package below `Tests/` | | `rux doc` | writes reference pages for the `pub` items to `Bin/Docs/` | ```mermaid flowchart LR edit["edit the code"] --> fmt["`rux fmt`"] fmt --> lint["`rux lint`"] lint --> test["`rux test`"] test --> doc["`rux doc`"] test -- "a test fails" --> edit ``` ## Formatting `rux fmt` puts every file in the one standard layout, so a diff shows real changes and not someone's spacing habits. For `Rux.toml` that means the canonical order and spelling — sections in a fixed order, `Description` before `Authors`, spaces around every `=`. For source files in Rux 0.4.0 it is line-level clean-up: trailing spaces go and line endings are made consistent, while indentation is left as you wrote it. `--check` turns formatting into a pass-or-fail question. It touches nothing, names each file that `rux fmt` would rewrite, and exits with status 1 if there is one. That is the form to use in a script or in continuous integration, where nobody wants the build to rewrite their files. ## Testing A test in Rux is an ordinary executable package below `Tests/`. `rux test` builds and runs each one, and a test **passes when its `Main` returns 0**. This lesson's test checks the leap-year rules with `Assert` from `Core`: ```rux Assert(IsLeapYear(2024), "2024 is a leap year"); Assert(!IsLeapYear(2023), "2023 is not a leap year"); // A century is not a leap year, unless it divides by 400. Assert(!IsLeapYear(1900), "1900 is not a leap year"); Assert(IsLeapYear(2000), "2000 is a leap year"); ``` When an `Assert` condition is false, it prints its message and ends the program with a failing status, so a failed test says which check it was. Because a test is a package, it has its own `Rux.toml`, which depends on the code under test by path and on `Core` from the registry: ```toml [Dependencies] Calendar = { Path = "../../Calendar" } Core = { Namespace = "Rux", Version = "*" } ``` Add more folders under `Tests/` and `rux test` finds them by itself; there is no list to keep. If you break the rules in `Calendar`, the report shows which test failed and why — here, after an assertion that claims 2100 is a leap year (the timings and the exit code vary by machine): ```text Testing Tooling v0.1.0 (Debug, Windows x86-64) Running 1 test Failed LeapYear in 692 ms note: test 'LeapYear' exited with code -1073741795 Output: Assertion failed: 2100 is a leap year at Main (Src/Main.rux:16:5) Failed 1 test in 692 ms (0 passed, 1 failed) ``` ## Linting and documenting `rux lint` and `rux doc` work as in [Documentation](https://rux-lang.dev/docs/learn/documentation). `Calendar`'s functions are documented with `@param` and `@returns`, so its pages have something to show. ## What this course never runs `rux pack` and `rux publish` also exist, for sharing a source library through the package registry. They need an account and change something public, so this course stops short of them. The [publishing guide](https://rux-lang.dev/docs/packaging/publishing) covers them when you are ready. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Packages/Tooling){rel=""nofollow""}. Its comments explain every step. ::code-tree{default-value="Src/Main.rux"} ```toml [Rux.toml] [Manifest] Version = 1 MinRux = "0.4.0" [Package] Name = "Tooling" Version = "0.1.0" Type = "Executable" Description = "Formatting, linting, testing and documenting a package with the rux tools" Authors = ["Rux Contributors "] [Dependencies] Calendar = { Path = "Calendar" } Io = { Namespace = "Rux", Version = "*" } ``` ```toml [Calendar/Rux.toml] [Manifest] Version = 1 MinRux = "0.4.0" [Package] Name = "Calendar" Version = "0.1.0" Type = "SourceLibrary" Description = "Leap years and month lengths, the code under test in the Tooling lesson" Authors = ["Rux Contributors "] ``` ```rux [Src/Main.rux] // `rux run` and `rux check` are not the only commands. A few more keep a package tidy, and all of // them are run from the package directory: // // rux fmt rewrite every source file and the manifest in the standard layout // rux fmt --check change nothing; list the files that `rux fmt` would rewrite, and fail // rux lint warn about what compiles but is still wrong, such as a `pub` item with no // documentation or a misspelled documentation tag // rux test build and run every executable package below `Tests/` // rux doc generate reference pages for the `pub` items, in `Bin/Docs/` // // `--check` exists for scripts and continuous integration: it makes formatting a pass-or-fail // question without touching anyone's files. // // This lesson has one test, in `Tests/LeapYear/`, for the small `Calendar` library beside `Src/`. // The program below uses the same library, so a passing test says something about the program. // // `rux pack` and `rux publish` also exist, for sharing a source library through the registry. They // need an account and change something public, so this course never runs them. import Calendar::DaysInMonth; import Io::PrintLine; func Main() -> int { for year in 1900..=1904 { PrintLine("February {} has {} days", year, DaysInMonth(year, 2)); } return 0; } ``` ```toml [Tests/LeapYear/Rux.toml] [Manifest] Version = 1 MinRux = "0.4.0" [Package] Name = "LeapYear" Version = "0.1.0" Type = "Executable" Description = "Tests for the leap year rules in Calendar" Authors = ["Rux Contributors "] [Dependencies] Calendar = { Path = "../../Calendar" } Core = { Namespace = "Rux", Version = "*" } ``` ```rux [Calendar/Src/Calendar.rux] // The code under test. It lives in its own small library so that both the program and the test // package can depend on it. /// Whether `year` has a 29 February in the Gregorian calendar. /// @param year the year, counted in the usual way /// @returns true for every fourth year, except centuries not divisible by 400 pub func IsLeapYear(year: int) -> bool { return year % 4 == 0 && (year % 100 != 0 || year % 400 == 0); } /// How many days `month` has in `year`. /// @param year the year, which matters only for February /// @param month the month, from 1 for January to 12 for December /// @returns the number of days, from 28 to 31 pub func DaysInMonth(year: int, month: int) -> int { if month == 2 { return IsLeapYear(year) ? 29 : 28; } if month == 4 || month == 6 || month == 9 || month == 11 { return 30; } return 31; } ``` ```rux [Tests/LeapYear/Src/Main.rux] // A test is an executable package below `Tests/`. `rux test` builds and runs each one, and a test // passes when its `Main` returns 0. // // `Assert` from `Core` does the checking. When its condition is false it prints its message and // ends the program with a failing status, so a failed test says which check it was. A test is an // ordinary package, so it depends on the code under test by path and on `Core` from the registry. import Calendar::{ DaysInMonth, IsLeapYear }; import Core::Assert; func Main() -> int { Assert(IsLeapYear(2024), "2024 is a leap year"); Assert(!IsLeapYear(2023), "2023 is not a leap year"); // A century is not a leap year, unless it divides by 400. Assert(!IsLeapYear(1900), "1900 is not a leap year"); Assert(IsLeapYear(2000), "2000 is a leap year"); Assert(DaysInMonth(2024, 2) == 29, "February 2024 has 29 days"); Assert(DaysInMonth(2023, 2) == 28, "February 2023 has 28 days"); Assert(DaysInMonth(2023, 4) == 30, "April has 30 days"); return 0; } ``` :: ## Run it ```sh cd Examples/Packages/Tooling rux run ``` ```text February 1900 has 28 days February 1901 has 28 days February 1902 has 28 days February 1903 has 28 days February 1904 has 29 days ``` The other commands, all run from this directory: | Command | What it does | | ----------------- | ------------------------------------------------------------------ | | `rux fmt` | Rewrites the sources and `Rux.toml` in the standard layout | | `rux fmt --check` | Changes nothing; fails if `rux fmt` would rewrite a file | | `rux lint` | Warns about what compiles but is still wrong, such as missing docs | | `rux test` | Builds and runs each package below `Tests/`; status 0 passes | | `rux doc` | Writes reference pages for the `pub` items to `Bin/Docs/` | `rux test` prints one line per test; the timings vary: ```text Testing Tooling v0.1.0 (Debug, Windows x86-64) Running 1 test Passed LeapYear in 427 ms Passed 1 test in 427 ms (1 passed, 0 failed) ``` ## Common mistakes ::mistake **A test that cannot fail.**:br A test passes when `Main` returns 0, and nothing else is looked at. A test that prints "wrong!" and still returns 0 passes. Check with `Assert`, which ends the program with a failing status. :: ::mistake **A test without its dependencies.**:br A test is a package like any other. Remove the `Core` line from `Tests/LeapYear/Rux.toml` and `rux test` reports `Failed LeapYear`, with the note "the test package did not compile" and the familiar: ```text package 'Core' is not listed in [Dependencies] ``` :: ::mistake **Expecting `rux fmt --check` to fix anything.**:br It only reports, for example: ```text error: source file '…\Src\Main.rux' is not formatted ``` Then it exits with status 1. Run `rux fmt` to rewrite the files. :: ## Try it yourself 1. Break `IsLeapYear` in `Calendar/Src/Calendar.rux` by removing the `year % 400 == 0` part, and run `rux test`. Which assertion fails? Then run `rux run` — does the program's output show the bug? 2. Add a second test, `Tests/MonthLength/`, that checks `DaysInMonth` for January, April and December. Run `rux test` and count the tests. 3. Add a few spaces to the end of a line in `Src/Main.rux`. Run `rux fmt --check`, then `echo $?`, then `rux fmt`, then `rux fmt --check` again. 4. Run `rux doc --open` in `Calendar/`. Does a source library get pages even though it cannot be built? ## Learn more - [`rux fmt`](https://rux-lang.dev/docs/cli/fmt), [`rux lint`](https://rux-lang.dev/docs/cli/lint), [`rux test`](https://rux-lang.dev/docs/cli/test) and [`rux doc`](https://rux-lang.dev/docs/cli/doc) in the CLI reference - [Assert](https://rux-lang.dev/docs/learn/assert) — the check every test is made of - [Publishing](https://rux-lang.dev/docs/packaging/publishing) — `rux pack` and `rux publish`, for when you share a package - [Source library](https://rux-lang.dev/docs/learn/source-library) — the kind of package `Calendar` is # Unit tests ::note **You'll need**: [Source library](https://rux-lang.dev/docs/learn/source-library), [Tooling](https://rux-lang.dev/docs/learn/tooling), [Module](https://rux-lang.dev/docs/learn/module), [Presence](https://rux-lang.dev/docs/learn/presence), [Propagate](https://rux-lang.dev/docs/learn/propagate) :: [Tooling](https://rux-lang.dev/docs/learn/tooling) tested a library from the outside: a separate package under `Tests/` whose `Main` called `Assert`, and stopped at the first check that failed. That works, but each test is a whole program, and the first failure hides every check after it. A **unit test** is smaller: one function that calls your code with input whose answer you know, and checks that the answer comes back. Rux marks such a function with `#Test()`, and `rux test` finds every one, runs them all, and reports each by name. This lesson tests three small temperature functions — a conversion, a parser and a description: ```rux import Test::{ ExpectNear, ExpectText, TestFailure }; ``` ## A test is a function A test takes nothing and returns `! TestFailure`. Every check of the `Test` package returns `! TestFailure` as well, so a test hands a failed check on with [`?`](https://rux-lang.dev/docs/learn/propagate), and stops there: ```rux #Test() func FixedPoints() -> ! TestFailure { ExpectNear(ToFahrenheit(0.0), 32.0, 0.000001)?; ExpectNear(ToFahrenheit(100.0), 212.0, 0.000001)?; ExpectNear(ToFahrenheit(-40.0), -40.0, 0.000001)?; } ``` A test passes when it returns, and fails when a check fails. A failed check ends only its own test; the others still run. | Check | Passes when | Its failure says | | ----------------------------------------- | --------------------------------- | ---------------------------------------- | | `Expect(condition, message)` | the condition holds | the message | | `ExpectEqual(actual, expected)` | the two are equal | `expected 2, but got 1` | | `ExpectNotEqual(actual, unexpected)` | they differ | `expected anything but 5` | | `ExpectNear(actual, expected, tolerance)` | two floats are within a tolerance | `expected 2.0 within 0.5, but got 1.0` | | `ExpectText(actual, expected)` | two texts are equal | the byte where they part, and both texts | | `ExpectSome(optional, message)` | there is a value — and returns it | the message | | `ExpectNone(optional, message)` | there is none | the message | | `ExpectSuccess` / `ExpectFailure` | an outcome succeeded / failed | the message | `ExpectSome` is the one to notice: it does not just check, it hands back the value inside, so a second check can look at it: ```rux ExpectEqual(ExpectSome(ParseDegrees("21"), "21 is a temperature")?, 21)?; ``` ## Where tests live Tests sit **beside the code they test**, in the same package and here in the same file, so they can call functions that are not `pub` too. When `rux test` builds a package in test mode, it generates a `Main` that runs every `#Test()` function. So the package must not have a `Main` of its own — which is why this lesson's package is a [source library](https://rux-lang.dev/docs/learn/source-library). An application keeps its `Main` in an executable and its tested code in a library it depends on. ```mermaid flowchart LR t["`rux test`"] --> b["test build:
a generated `Main`"] b --> r["runs every
`#Test()` function"] r --> ok["all passed:
one line"] r --> bad["a check failed:
the full report"] ``` The generated `Main` calls the `Test` package's runner, so the package lists `Test` under `[Dependencies]`, as its `Rux.toml` shows. A test inside a `module` is named after it, so the three parser tests are `Parse::Positive`, `Parse::Negative` and `Parse::Rejects`. A module imports for itself, which is why `Parse` has its own `import Test::…` line. ## Running them `rux test` runs every test. Arguments after `--` go to the runner: a plain word is a filter that a test's name must contain, `--exact` makes it match the whole name, and `--skip` leaves matching tests out: | Command | Runs | | ------------------------------------- | ------------------------------------------------------ | | `rux test` | all five tests | | `rux test -- Parse` | `Parse::Positive`, `Parse::Negative`, `Parse::Rejects` | | `rux test -- --exact Parse::Negative` | that one test | | `rux test -- --skip Words` | every test but `Words` | When every test passes, `rux test` reports the package in one line. The report worth reading comes when something breaks. Change `Describe`'s `celsius < 15` to `celsius <= 15` — an easy slip at a boundary — and run the tests again: ```text Testing UnitTest v0.1.0 (Debug, Windows x86-64) Running 1 test Failed UnitTest in 444 ms note: test 'UnitTest' exited with code 1 Output: running 5 of 5 tests test FixedPoints ... ok (0.014 ms) test Words ... FAILED texts differ at byte 0 (expected 4 bytes, got 4) expected "mild" but got "cold" test Parse::Positive ... ok (0.014 ms) test Parse::Negative ... ok (0.005 ms) test Parse::Rejects ... ok (0.01 ms) failed: Words result: FAILED. 4 passed, 1 failed, 0 skipped, 0 filtered out; finished in 0.397 ms Failed 1 test in 451 ms (0 passed, 1 failed) ``` The failed check names what it expected and what it got, and the other four tests still ran. `rux test -- Parse` passes at this point, because the broken function is not among the tests it chose. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Packages/UnitTest){rel=""nofollow""}. Its comments explain every step. ::code-tree{default-value="Src/Temperature.rux"} ```toml [Rux.toml] [Manifest] Version = 1 MinRux = "0.4.0" [Package] Name = "UnitTest" Version = "0.1.0" Type = "SourceLibrary" Description = "Write `#Test()` functions with `Expect` checks and run them with `rux test`" Authors = ["Rux Contributors "] [Dependencies] Test = { Namespace = "Rux", Version = "*" } ``` ```rux [Src/Temperature.rux] // A unit test calls a small piece of your code with input whose answer you know, and checks that // the answer comes back. Run them after every change, and a change that breaks something says so // at once, naming the check that failed. // // In Rux a test is a function marked `#Test()` that takes nothing and returns `! TestFailure`. // The checks of the `Test` package, `ExpectEqual`, `ExpectText`, `ExpectNear` and the rest, each // return `! TestFailure` too, so a test hands a failed check on with `?` and stops there. // // `rux test` builds the package in test mode, generates a `Main` that runs every `#Test()` // function, and runs it. That is why this package is a library: an executable has a `Main` of // its own and cannot hold tests. The tests sit beside the code, in the same file, so they can call // functions that are not `pub` as well. Run them with // // rux test every test // rux test -- Parse only the tests whose names contain "Parse" // // A package with tests must depend on `Test`, whose runner the generated `Main` calls; without it: // // error: package 'UnitTest' has '#Test()' functions but does not depend on 'Test' import Test::{ ExpectNear, ExpectText, TestFailure }; /// Converts degrees Celsius to degrees Fahrenheit. /// @param celsius the temperature in degrees Celsius /// @returns the same temperature in degrees Fahrenheit pub func ToFahrenheit(celsius: float64) -> float64 { return celsius * 9.0 / 5.0 + 32.0; } /// Reads a whole number of degrees with an optional minus sign, such as `21` or `-5`. /// @param text the text to read /// @returns the degrees, or none for anything else, or for more than three digits pub func ParseDegrees(text: char8[..]) -> int32? { let negative = text.length > 0 && text[0] == '-'; let start: uint = negative ? 1 : 0; if text.length == start || text.length - start > 3 { return none; } var value: int32 = 0; for i in start..text.length { let c = text[i]; if c < '0' || c > '9' { return none; } value = value * 10 + (c as int32 - 48); } return negative ? -value : value; } /// One word for how a temperature feels. /// @param celsius the temperature in degrees Celsius /// @returns `freezing`, `cold`, `mild` or `hot` pub func Describe(celsius: int32) -> char8[..] { if celsius <= 0 { return "freezing"; } if celsius < 15 { return "cold"; } if celsius < 25 { return "mild"; } return "hot"; } // Floating-point arithmetic rounds, so two floats are compared within a tolerance, never with // `==`. These three points are the ones everybody knows. #Test() func FixedPoints() -> ! TestFailure { ExpectNear(ToFahrenheit(0.0), 32.0, 0.000001)?; ExpectNear(ToFahrenheit(100.0), 212.0, 0.000001)?; ExpectNear(ToFahrenheit(-40.0), -40.0, 0.000001)?; } // Boundaries are where mistakes hide, so test each side of each one. A failed `ExpectText` shows // both texts and the byte where they part. #Test() func Words() -> ! TestFailure { ExpectText(Describe(0), "freezing")?; ExpectText(Describe(1), "cold")?; ExpectText(Describe(14), "cold")?; ExpectText(Describe(15), "mild")?; ExpectText(Describe(24), "mild")?; ExpectText(Describe(25), "hot")?; } // Tests in a module are named after it: `Parse::Positive`, `Parse::Negative`, `Parse::Rejects`. // So `rux test -- Parse` runs just these three. A module imports for itself. module Parse { import Test::{ ExpectEqual, ExpectNone, ExpectSome, TestFailure }; // `ExpectSome` fails with its message when the optional is empty, and otherwise hands back // the value inside for the next check. #Test() func Positive() -> ! TestFailure { ExpectEqual(ExpectSome(ParseDegrees("21"), "21 is a temperature")?, 21)?; ExpectEqual(ExpectSome(ParseDegrees("0"), "0 is a temperature")?, 0)?; } #Test() func Negative() -> ! TestFailure { ExpectEqual(ExpectSome(ParseDegrees("-5"), "-5 is a temperature")?, -5)?; } // What a function refuses matters as much as what it accepts. #Test() func Rejects() -> ! TestFailure { ExpectNone(ParseDegrees(""), "empty text")?; ExpectNone(ParseDegrees("-"), "a sign alone")?; ExpectNone(ParseDegrees("12C"), "a unit after the digits")?; ExpectNone(ParseDegrees("1000"), "four digits")?; } } ``` :: ## Run it ```sh cd Examples/Packages/UnitTest rux test ``` ```text Testing UnitTest v0.1.0 (Debug, Windows x86-64) Running 1 test Passed UnitTest in 431 ms Passed 1 test in 437 ms (1 passed, 0 failed) ``` The platform and the times vary. `rux test` counts test packages, so `1 test` is this package with its five tests. A passing package is reported in one line; when a check fails, `rux test` prints the runner's report instead, naming each test and what the failed check expected and got. ## Common mistakes ::mistake **Tests in a package with a `Main`.**:br Add a `Main` to this package, make it an `Executable`, and `rux test` reports: ```text error: package 'UnitTest' declares 'Main' and '#Test()' functions; a test build generates its own 'Main' ``` Keep the tested code in a library, and the `Main` in an executable that depends on it. :: ::mistake **A check without `?`.**:br`ExpectNear(ToFahrenheit(0.0), 33.0, 0.000001);` on its own line fails to compile with: ```text error: fallible result of type '! TestFailure' is discarded ``` That is a mercy: a check whose failure is dropped could never fail the test. :: ::mistake **Comparing floats exactly.**:br`ExpectEqual(0.1 + 0.2, 0.3)?;` fails with `expected 0.3, but got 0.30000000000000004`. Floating-point arithmetic rounds; compare with `ExpectNear` and a tolerance. :: ::mistake **A filter that matches nothing.**:br`rux test -- --exact Negative` runs no test at all — the test is called `Parse::Negative` — and a run of no tests passes. Check the spelling of a filter that suddenly makes everything pass. :: ## Try it yourself 1. Break `Describe` as above, run `rux test`, then fix it and run again. 2. Add a test that `ParseDegrees("+5")` gives `5`. It fails; change `ParseDegrees` to accept a plus sign until it passes. 3. Add a check to `Rejects` that `ParseDegrees("2 1")` is none, and run only that test with `--exact`. 4. Test that `ToFahrenheit(37.0)` is about `98.6`. What tolerance does it need? ## Learn more - [Test API](https://rux-lang.dev/docs/api/test) — every check, `TestFailure`, and the runner's options - [#Test](https://rux-lang.dev/docs/lang/attributes/test) in the Rux Reference — what a test function may look like, and every error for misuse - [rux test](https://rux-lang.dev/docs/cli/test) — the command and its options - [Tooling](https://rux-lang.dev/docs/learn/tooling) — test packages under `Tests/`, and the other `rux` commands - [Benchmark](https://rux-lang.dev/docs/learn/benchmark) — the `Test` package's other half: measuring how long code takes # Benchmark ::note **You'll need**: [Binary search](https://rux-lang.dev/docs/learn/binary-search), [Callback](https://rux-lang.dev/docs/learn/callback), [Pointer](https://rux-lang.dev/docs/learn/pointer), [Unit tests](https://rux-lang.dev/docs/learn/unit-test) :: [Binary search](https://rux-lang.dev/docs/learn/binary-search) claimed that halving beats looking at every element: for 1,024 sorted numbers, about ten steps instead of up to 1,024. A **benchmark** checks a claim like that with a clock. This lesson times a linear and a binary search over the same 1,024 sorted numbers, with the benchmarks of the `Test` package — the same package whose checks drive [unit tests](https://rux-lang.dev/docs/learn/unit-test): ```rux import Test::{ BenchmarkCase, BenchmarkOptions, Consume, RunBenchmarksWith }; ``` ## Why repeat the work One binary search takes tens of nanoseconds — less than the clock can resolve reliably, and less than the noise from everything else the machine is doing. So a benchmark repeats the work many times, times the lot, and divides. The `Test` package decides how many times, so you do not have to guess. A benchmark is a function that takes an **iteration count** and does the work that many times, in its own loop: ```rux func Binary(iterations: uint64) { var values: int[1024]; Fill(values[..]); var found: uint64 = 0; for n in 0..iterations { if BinarySearch(values[..], (n % 2048) as int) != none { found = found + 1; } } Consume(@found); } ``` Filling the array happens once per call, before the loop. The runner calls the function with counts in the hundreds of thousands, so that one-off cost all but vanishes from the time per iteration. Asking for `n % 2048` searches for every value from 0 to 2047 in turn, so half of the searches find their number and half do not. ## Keeping the work An optimizing compiler removes work whose result nobody uses. Here nothing ever reads `found`, so in principle a Release build could drop the searches and report the time for an empty loop. `Consume(@found)` prevents that: it takes the result's address and stores it where the compiler cannot see it read, which costs one store. Every benchmark should end by consuming what its loop produced. ## Running them A `BenchmarkCase` gives a benchmark its name, and a table of them goes to the runner with a `BenchmarkOptions`: ```rux let benchmarks: BenchmarkCase[3] = [ BenchmarkCase { name: "Search::Linear", run: Linear }, BenchmarkCase { name: "Search::LinearMissing", run: LinearMissing }, BenchmarkCase { name: "Search::Binary", run: Binary } ]; var options = BenchmarkOptions(); options.minimumTime = Duration::FromMilliseconds(100); RunBenchmarksWith(benchmarks[..], options); ``` For each benchmark, the runner calls the function with a count that grows from 1 until one call lasts at least `minimumTime`, then reports that last call: ```mermaid flowchart LR s(["count = 1"]) --> run["`run(count)`,
timed"] run --> q{"at least
`minimumTime`?"} q -- "no" --> g["grow the count,
2× to 100×"] --> run q -- "yes" --> out["print ns per iteration"] ``` | `BenchmarkOptions` field | Default | Means | | ------------------------ | ----------- | --------------------------------------------------------- | | `minimumTime` | 200 ms | how long the measured call must last | | `maximumIterations` | one billion | the most a call is asked to do, for work too fast to time | | `filter` | empty: all | run only the benchmarks whose names contain this text | `Measure(Binary, options)` does the same for one function and hands back a `BenchmarkResult` instead of printing, for a program that wants to compare the numbers itself. ::note **From the command line.**:br`RunBenchmarks`, without `With`, reads its options from the program's arguments: each plain argument is a filter, and a benchmark runs when its name holds any of them, while `--quick` measures each for 10 milliseconds. This lesson sets its options in code instead, so its output does not depend on how it was started. :: ## Reading the numbers Linear search averages about a thousand nanoseconds, and over a third more when the value is missing and every element must be looked at. Binary search takes well under a hundred. Your numbers will differ — the program's output says which lines vary — but the ratio between them is the point, and it is the reason binary search exists. Measure an optimized build when the numbers matter: `rux run --release`. A Debug build optimizes nothing, so it times code that you would never ship. On the machine that produced the output below, Release ran the binary search about three times faster, and the linear one about five. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Packages/Benchmark){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // A benchmark measures how long a piece of code takes. One run of a fast function is too short // for a clock to time well, so a benchmark repeats the work many times and divides: the answer is // the time per iteration, in nanoseconds. // // The `Test` package does the repeating for you. A `BenchmarkCase` is a name and a function that // takes an iteration count and does the work that many times, in its own loop. `RunBenchmarksWith` // calls each one with a count that grows from 1 until a run lasts at least the minimum time in // its `BenchmarkOptions`, then prints the time per iteration of that last run. // // This program asks a question the Binary search lesson answered on paper: how much faster is // a binary search than looking at every element? Before timing anything, it checks that the two // searches agree, since a fast answer is worth nothing if it is wrong. // // Times depend on the machine, on what else it is doing, and on the build. Measure with // `rux run --release`: a Debug build does not optimize, so it times code nobody ships. import Algorithms::{ BinarySearch, Contains }; import Io::PrintLine; import Test::{ BenchmarkCase, BenchmarkOptions, Consume, RunBenchmarksWith }; import Time::Duration; // The sorted data every benchmark searches: 0, 2, 4, ... 2046, so odd numbers are missing. func Fill(values: var int[..]) { for i in 0..values.length { values[i] = i as int * 2; } } // Each benchmark sets up its data before its loop. That costs the same once whatever the count, // so over thousands of iterations its share of the time per iteration all but vanishes. // // The loop counts what it found and hands the count to `Consume`. Without that, a Release build // could see that the result is never used, remove the searches as having no effect, and report // a time for doing nothing. `Consume` takes the count's address: // // Consume(found); // error: argument 1 to 'Consume' has type 'uint64', but parameter 'value' requires '*T' // // The iteration count is a `uint64`, and a benchmark taking anything else does not fit: // // BenchmarkCase { name: "Search::Linear", run: Linear } with func Linear(iterations: int) // error: field 'run' in initializer for 'BenchmarkCase' has type 'func(int) -> opaque', // but its declaration requires 'func(uint64) -> opaque' func Linear(iterations: uint64) { var values: int[1024]; Fill(values[..]); var found: uint64 = 0; for n in 0..iterations { if Contains(values[..], (n % 2048) as int) { found = found + 1; } } Consume(@found); } // A value that is not there is the worst case for a linear search: it looks at every element. func LinearMissing(iterations: uint64) { var values: int[1024]; Fill(values[..]); var found: uint64 = 0; for n in 0..iterations { if Contains(values[..], 2049) { found = found + 1; } } Consume(@found); } func Binary(iterations: uint64) { var values: int[1024]; Fill(values[..]); var found: uint64 = 0; for n in 0..iterations { if BinarySearch(values[..], (n % 2048) as int) != none { found = found + 1; } } Consume(@found); } func Main() -> int { // First, are both searches right? They must agree on every value, present or missing. var values: int[1024]; Fill(values[..]); var agree = true; for target in 0..2048 { let linear = Contains(values[..], target); let binary = BinarySearch(values[..], target) != none; if linear != binary { agree = false; } } PrintLine("linear and binary search agree on 2048 values: {}", agree); PrintLine(); // Then, how fast? `BenchmarkOptions()` measures each benchmark for at least 200 milliseconds; // a shorter minimum gives a quicker but rougher answer. Setting `options.filter = "Linear"` // would run only the benchmarks whose names contain `Linear`. let benchmarks: BenchmarkCase[3] = [ BenchmarkCase { name: "Search::Linear", run: Linear }, BenchmarkCase { name: "Search::LinearMissing", run: LinearMissing }, BenchmarkCase { name: "Search::Binary", run: Binary } ]; var options = BenchmarkOptions(); options.minimumTime = Duration::FromMilliseconds(100); RunBenchmarksWith(benchmarks[..], options); return 0; } ``` Besides `Io`, its `Rux.toml` lists `Algorithms`, `Test` and `Time` under `[Dependencies]`. ## Run it ```sh cd Examples/Packages/Benchmark rux run ``` ```text linear and binary search agree on 2048 values: true bench Search::Linear ... 970.3 ns/iter (119084 iterations) bench Search::LinearMissing ... 1298.7 ns/iter (78212 iterations) bench Search::Binary ... 79.3 ns/iter (2000000 iterations) result: 3 measured, 0 filtered out ``` The three `bench` lines are samples: the times and iteration counts depend on the machine and change on every run. The other lines are the same each time. For times worth comparing, measure an optimized build with `rux run --release`. ## Common mistakes ::mistake **Consuming the value, not its address.**:br`Consume(found);` fails with: ```text error: argument 1 to 'Consume' has type 'uint64', but parameter 'value' requires '*T' ``` Write `Consume(@found)`. :: ::mistake **The wrong count type.**:br The runner passes a `uint64`. With `func Linear(iterations: int)`, the table entry fails with: ```text error: field 'run' in initializer for 'BenchmarkCase' has type 'func(int) -> opaque', but its declaration requires 'func(uint64) -> opaque' ``` :: ::mistake **Setting up inside the loop.**:br Filling the array inside the `for` loop would time the filling a thousand times over, and the search would vanish in it. Prepare before the loop; repeat only the work being measured. :: ::mistake **Trusting one run, or a Debug build.**:br A single timing is at the mercy of whatever else the machine was doing, and a Debug build is not the program you ship. Let the runner repeat the work, and compare numbers from `rux run --release`. :: ## Try it yourself 1. Run `rux run --release` and compare the three times with a Debug run. 2. Set `options.filter = "Linear"` before running. How many benchmarks are measured, and how many filtered out? 3. Make the data four times larger — `int[4096]` in all three benchmarks, and `n % 8192`. How much slower does each search get? 4. Measure just the binary search with `Measure(Binary, options)` and print `result.NanosecondsPerIteration()` and `result.iterations` yourself. ## Learn more - [Test API](https://rux-lang.dev/docs/api/test) — `BenchmarkCase`, `BenchmarkOptions`, `Measure` and `Consume` - [Binary search](https://rux-lang.dev/docs/learn/binary-search) — the search being measured - [Stopwatch](https://rux-lang.dev/docs/learn/stopwatch) — timing one stretch of code with `Instant` - [Unit tests](https://rux-lang.dev/docs/learn/unit-test) — the `Test` package's checks - [Function types](https://rux-lang.dev/docs/lang/functions/function-types) in the Rux Reference — the `func(uint64)` a `BenchmarkCase` holds # Part 23: Compile time Everything so far has happened while the program runs: an `if` tests a value, a loop counts, a function is called. But some questions are settled before the program exists at all — which compiler is building it, which operating system and processor it is for, whether it is a debug or a release build, which switches you passed on the command line. This part is about asking those questions in the source and letting the answers decide which code is compiled in. By the end you can write one program that builds differently for Windows and Linux, for debug and release, and refuses — with a message of your choosing — to build where it cannot work. ## What you will learn - Choosing code while compiling with `when` and `else when`, and why the branches it skips may name things that do not exist. - Branching on the machine being built for with `#target.os` and `#target.arch`, and building for another one with `--target`. - Telling a debug build from a release build with `#build.mode`, and checks that vanish from a release build. - Reading the file, line and function of an expression with `#source`, and which place it really describes. - Stopping or warning a build from the source with `#Error` and `#Warn`, and silencing one lint rule with `#Allow`. - Handing the build values of your own with `--define` and `[Build.Defines]`, and reading them with `#config`. - How `int8`, `#target` and `Assert` reach a program through `intrinsic` declarations. ## How `when` shapes a program Most lessons in this part feed the same machine. The compiler knows some facts before it starts; `when` turns them into a choice; only the chosen code is compiled: ```mermaid flowchart LR subgraph known ["Known while compiling"] cv["`#compiler`
`version` · 23.1"] tg["`#target`
`os`, `arch` · 23.2"] bd["`#build`
`mode` · 23.3"] cf["`#config`
your defines · 23.6"] end known --> w{"`when`"} w -- "the taken branch" --> keep["resolved, type-checked
and compiled in"] w -- "the other branches" --> drop["discarded unread"] w -- "a branch holding `#Error` · 23.5" --> stop(["the build stops
with your message"]) ``` `#source` (23.4) is known while compiling too, but it describes a place in the code rather than the build, so it is read as a value rather than branched on. All of them come from `Core` as `intrinsic` declarations — [Intrinsic](https://rux-lang.dev/docs/learn/intrinsic) (23.7) shows what that means by declaring a few of them in a package of its own. | Ask about… | Read | Lesson | | ---------------------------- | ----------- | ------------------------------------------------------------------ | | the compiler doing the build | `#compiler` | [When](https://rux-lang.dev/docs/learn/when) | | the machine being built for | `#target` | [Target](https://rux-lang.dev/docs/learn/target) | | debug or release | `#build` | [Build mode](https://rux-lang.dev/docs/learn/build-mode) | | where this expression is | `#source` | [Source location](https://rux-lang.dev/docs/learn/source-location) | | a value you passed in | `#config` | [Define](https://rux-lang.dev/docs/learn/define) | ## Lessons | | Lesson | What you will learn | | ---- | ------------------------------------------------------------------ | ---------------------------------------------------------------- | | 23.1 | [When](https://rux-lang.dev/docs/learn/when) | select code at compile time with `when` | | 23.2 | [Target](https://rux-lang.dev/docs/learn/target) | the operating system and architecture being compiled for | | 23.3 | [Build mode](https://rux-lang.dev/docs/learn/build-mode) | tell debug builds from release builds | | 23.4 | [Source location](https://rux-lang.dev/docs/learn/source-location) | the file and line of an expression | | 23.5 | [Compile error](https://rux-lang.dev/docs/learn/compile-error) | stop the build with `#Error`, or warn with `#Warn` | | 23.6 | [Define](https://rux-lang.dev/docs/learn/define) | values passed to the build from the manifest or the command line | | 23.7 | [Intrinsic](https://rux-lang.dev/docs/learn/intrinsic) | declarations the compiler implements itself | ## Before you start The early lessons need little beyond Parts 1–4 — [Const](https://rux-lang.dev/docs/learn/const), [If](https://rux-lang.dev/docs/learn/if), [Match](https://rux-lang.dev/docs/learn/match) and [Function](https://rux-lang.dev/docs/learn/function) — plus [Enum](https://rux-lang.dev/docs/learn/enum) from Part 6 and [Assert](https://rux-lang.dev/docs/learn/assert) from Part 9. The last two lean on [Part 22: Packages](https://rux-lang.dev/docs/learn/packages): [Compile error](https://rux-lang.dev/docs/learn/compile-error) uses `rux lint` from [Tooling](https://rux-lang.dev/docs/learn/tooling), and [Intrinsic](https://rux-lang.dev/docs/learn/intrinsic) is a two-package lesson built on [Dependency](https://rux-lang.dev/docs/learn/dependency). Each lesson's package is in the Examples repository's `CompileTime/` folder: ```sh cd Examples/CompileTime/When rux run ``` Several lessons are worth running more than once — with `--release`, with `--define`, or built for another system with `--target` — and each says which. ## After this part [Part 24: Platform](https://rux-lang.dev/docs/learn/platform) puts `when #target` to work: calling the operating system's own libraries with `extern`, talking to C, choosing calling conventions and writing assembly, each guarded so that a build for the wrong system stops with a clear `#Error`. Its checkpoint project, [Melody](https://rux-lang.dev/docs/learn/melody), plays a tune through the Windows console speaker. For the full rules behind this part, see [Compile-time programming](https://rux-lang.dev/docs/lang/comptime/overview), [Conditional compilation](https://rux-lang.dev/docs/lang/comptime/conditional), [Build context](https://rux-lang.dev/docs/lang/comptime/context) and [Attributes](https://rux-lang.dev/docs/lang/attributes/overview) in the Rux Reference. # When ::note **You'll need**: [Const](https://rux-lang.dev/docs/learn/const), [If](https://rux-lang.dev/docs/learn/if), [Function](https://rux-lang.dev/docs/learn/function) :: Every `if` you have written so far decides while the program runs. Both of its branches are compiled, because until the program runs nobody knows which one will be needed. Some questions, though, are answered before the program even exists: which compiler is building it, which operating system it is for, whether this is a debug or a release build. For those, Rux has `when`, the compile-time `if`. Its condition must be something the compiler already knows, and only the branch it picks becomes part of the program. That one difference has a big consequence. The branches `when` skips are never resolved or type-checked, so they may name functions that do not exist. That is exactly what code for a newer compiler, or for another platform, looks like from where you are building — and it is what makes one source file able to serve them all. ## `if` and `when` side by side | | `if` | `when` | | ------------------- | -------------------------------------- | --------------------------------------- | | Decided | while the program runs | while the program is compiled | | Condition | any `bool` | a value the compiler knows | | Untaken branch | compiled and type-checked all the same | dropped before it is resolved | | Next test in chain | `else if` | `else when` | | Scope of a branch | its own: bindings end with the branch | none: bindings stay after it | | Where it can appear | inside a function body | inside a body, and between declarations | The values a `when` can read come from the `Core` package. This lesson uses `#compiler.version`, the version of the compiler doing the build; [Target](https://rux-lang.dev/docs/learn/target), [Build mode](https://rux-lang.dev/docs/learn/build-mode) and [Define](https://rux-lang.dev/docs/learn/define) add the operating system, the build mode and values of your own. ## Constants the compiler can compare `#compiler.version` is a `SemanticVersion`: three numbers, `major`, `minor` and `patch`, that compare the way version numbers should. To compare it against a version of your own, declare that version as a constant: ```rux const Rux040 = SemanticVersion { major: 0, minor: 4, patch: 0 }; const Rux100 = SemanticVersion { major: 1, minor: 0, patch: 0 }; ``` Notice the struct literal. `SemanticVersion(1, 0, 0)` is a call to a constructor, and a call only runs when the program does — far too late for a `when`, which has to be decided before there is a program to run. The compiler refuses it, and its help line says what a constant may be built from: literals, operators, casts and other constants. ## Choosing declarations Between declarations, `when` decides which declarations exist at all. Each branch here declares a function called `Channel`, so the rest of the program calls `Channel()` without knowing — or caring — which one it got: ```rux when #compiler.version >= Rux100 { func Channel() -> char8[..] { return "stable"; } } else when #compiler.version >= Rux040 { func Channel() -> char8[..] { return "preview"; } } else { // Never resolved by this compiler, so naming a function nobody wrote is not an error. func Channel() -> char8[..] { return LegacyChannel(); } } ``` A chain keeps the keyword it opened with: after `when` comes `else when`, never `else if`. That keeps it obvious which tests the compiler answers and which the running program answers. The compiler walks the chain top to bottom, keeps the first branch whose condition holds, and throws the others away unread: ```mermaid flowchart LR w{"`when`, while compiling:
which compiler is this?"} -- "`1.0.0` or newer" --> s["`Channel` returns `stable`"] w -- "`0.4.0` or newer
(Rux 0.4.0 stops here)" --> p["`Channel` returns `preview`"] w -- "anything older" --> l["`Channel` calls
`LegacyChannel()`"] p --> kept(["kept: resolved, type-checked
and compiled into the program"]) s -.-> gone(["discarded unread: a name
nobody wrote is no error here"]) l -.-> gone ``` `LegacyChannel` is never written anywhere. With Rux 0.4.0 the last branch is discarded, so nothing ever goes looking for it. ## Choosing statements Inside a function body, `when` decides which statements exist. It opens no scope of its own, so a binding made in the taken branch is still there after it: ```rux when #compiler.version.minor >= 4 { let greeting = "when picked this branch while compiling"; } else { let greeting = NotWrittenYet(); } PrintLine("{}", greeting); ``` After compiling, it is as if the `when` and the `else` branch had never been written and the first `let` stood on its own. The same code with `if` fails twice over: `NotWrittenYet` does not exist, and `greeting` would end with the branch that made it. The version itself is printed with ordinary field reads. They cost nothing at run time — the compiler folds them into the program as plain numbers. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/CompileTime/When){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // `if` chooses while the program runs, so both of its branches have to compile. `when` chooses // while the program is being compiled: its condition must be something the compiler already // knows, and only the branch it picks becomes part of the program. // // The branches `when` skips are never resolved or type-checked. They may call functions that do // not exist, which is exactly what code for a newer compiler, or for another platform, looks like // from where you are building. Written with `if`, the same code would not compile. // // A chain keeps the keyword it opened with: after `when`, the next test is `else when`, and // writing `else if` there is an error. import Core::{ #compiler, SemanticVersion }; import Io::PrintLine; // A constant is written as a struct literal: a call such as `SemanticVersion(1, 0, 0)` would only // run when the program does, and is "not a compile-time value". const Rux040 = SemanticVersion { major: 0, minor: 4, patch: 0 }; const Rux100 = SemanticVersion { major: 1, minor: 0, patch: 0 }; // Between declarations, `when` decides which declarations exist. Each branch declares the same // function, so the rest of the program calls `Channel` without knowing which one it got. when #compiler.version >= Rux100 { func Channel() -> char8[..] { return "stable"; } } else when #compiler.version >= Rux040 { func Channel() -> char8[..] { return "preview"; } } else { // Never resolved by this compiler, so naming a function nobody wrote is not an error. func Channel() -> char8[..] { return LegacyChannel(); } } func Main() -> int { // The version is a compile-time constant, folded into the binary as plain numbers. PrintLine("Compiled with Rux {}.{}.{}", #compiler.version.major, #compiler.version.minor, #compiler.version.patch); PrintLine("Release channel: {}", Channel()); // Inside a body, `when` decides which statements exist. It opens no scope of its own, so a // binding made in the taken branch is still there after it. when #compiler.version.minor >= 4 { let greeting = "when picked this branch while compiling"; } else { let greeting = NotWrittenYet(); } PrintLine("{}", greeting); return 0; } ``` Besides `Io`, its `Rux.toml` lists `Core` under `[Dependencies]`. ## Run it ```sh cd Examples/CompileTime/When rux run ``` ```text Compiled with Rux 0.4.0 Release channel: preview when picked this branch while compiling ``` The version numbers are those of the compiler that built the program. ## Common mistakes ::mistake **Writing `else if` after `when`.**:br A chain cannot switch from compile time to run time halfway through. `} else if …` after a `when` fails with: ```text error: expected 'when' after 'else' in a compile-time 'when' chain; 'if' is the run-time conditional ``` :: ::mistake **A condition only the running program knows.**:br`let minor = 4;` followed by `when minor >= 4` fails with: ```text error: 'minor' is not a compile-time constant ``` A `let` gets its value when the program runs; a `when` has to be settled before that. Use a `const`, or a value from `Core` such as `#compiler`. :: ::mistake **Building a constant with a call.**:br`const Rux100 = SemanticVersion(1, 0, 0);` fails with: ```text error: call to 'SemanticVersion' is not a compile-time value ``` Write the struct literal instead, as the lesson does. :: ::mistake **Using `if` where only one branch can compile.**:br An `if` compiles both branches, so a branch that names something missing breaks the build: ```text error: name 'NotWrittenYet' is not defined in this scope ``` When a branch only makes sense for some builds, it needs `when`. :: ## Try it yourself 1. Change `Rux040` to version 0.5.0 and predict what happens before you build. (The `else` branch is now the one that is kept, so `LegacyChannel` finally has to exist.) 2. After the `PrintLine` of `greeting`, add a `when` that prints "a patch release" when `#compiler.version.patch` is above zero, and "the first release of 0.4" otherwise, with the numbers read from `#compiler.version`. 3. Change the statement-level `when` to `if`, keep the `else` as it is, and read both errors. ## Learn more - [Conditional compilation](https://rux-lang.dev/docs/lang/comptime/conditional) and [Build context](https://rux-lang.dev/docs/lang/comptime/context) in the Rux Reference - [Compile-time programming](https://rux-lang.dev/docs/lang/comptime/overview) — how `when`, the build context and intrinsics fit together - [`#compiler`](https://rux-lang.dev/docs/api/core/compiler#compiler-constant) in the Core API reference - [If](https://rux-lang.dev/docs/learn/if) — the run-time conditional `when` mirrors - [Target](https://rux-lang.dev/docs/learn/target) — the next lesson, which branches on the machine being built for # Target ::note **You'll need**: [When](https://rux-lang.dev/docs/learn/when), [Enum](https://rux-lang.dev/docs/learn/enum), [Match](https://rux-lang.dev/docs/learn/match) :: Every build is for one machine: an operating system and a processor architecture. A path is written `Users\Ada` on Windows and `/home/ada` on Linux; a function from `Kernel32.dll` exists on one system and not the others; assembly for an Intel processor means nothing to an ARM one. Code that has to be different from machine to machine needs a way to ask which machine it is being built for. `#target` answers that. It describes the machine as ordinary values — an enum for the system, another for the processor, a few numbers and a name — and the compiler fills them in. Because they are known while compiling, [`when`](https://rux-lang.dev/docs/learn/when) can branch on them and keep only the code that fits. ## What `#target` holds `#target` comes from `Core`, like `#compiler` did. The fields you will reach for most: | Field | Type | On this Windows PC | Other values | | ------------- | ----------------- | ------------------ | ------------------------------ | | `os` | `OperatingSystem` | `.Windows` | `.Linux`, `.macOS`, `.FreeBSD` | | `arch` | `Architecture` | `.X86_64` | `.AArch64` | | `pointerBits` | `uint` | `64` | `64` on every supported target | | `triple` | `char8[..]` | `"windows-x86_64"` | `"linux-aarch64"`, … | | `dataModel` | `DataModel` | `.LLP64` | `.LP64` on every Unix | There are also `abi`, `endian` and `objectFormat`, which matter once you start talking to code written in other languages in [Part 24](https://rux-lang.dev/docs/learn/platform). Both enums have an `.Unknown` variant too, which no supported build produces. ## The match form To pick one of several values, `when` has a match form. It looks at one value and keeps the arm whose variant matches: ```rux when #target.os { .Windows => const SystemName: char8[..] = "Windows"; .Linux => const SystemName: char8[..] = "Linux"; .macOS => const SystemName: char8[..] = "macOS"; .FreeBSD => const SystemName: char8[..] = "FreeBSD"; else => const SystemName: char8[..] = "an unknown system"; } ``` This sits between declarations, so it decides which declaration exists. Each arm declares the same constant, `SystemName`, and the rest of the program uses it without caring which arm produced it. It reads like a [`match`](https://rux-lang.dev/docs/learn/match), and the enum shorthand `.Windows` works the same way — but only the kept arm is ever compiled. The `else` arm is worth keeping even though the four arms cover every system Rux builds for today. Without it, a build for a system no arm names stops with `no arm of this 'when' matches …`, which is a fine outcome for code that really cannot run there, and a poor one for code that simply forgot. ## The ordinary form For a yes-or-no question about the target, the ordinary form reads better: ```rux when #target.os == OperatingSystem::Windows { const PathSeparator: char8[..] = "\\"; } else { const PathSeparator: char8[..] = "/"; } ``` Enum-valued fields such as `os` and `arch` compare only for equality. "Is the system less than Windows?" has no meaning, and the compiler rejects it. ## The target is not the machine you are on The target is the machine the program will **run** on, not the one compiling it. Ask for another with `--target`, using the same names `#target.triple` prints: ```sh rux build --target linux-x86_64 ``` The compiler is still running on Windows, yet every branch above is chosen again for Linux: `SystemName` becomes `"Linux"` and `PathSeparator` becomes `"/"`. The result lands in `Bin/Debug/Linux/x86-64/` — a Linux program, which you copy to a Linux machine to run. This is why platform code branches on `#target` and never on anything it could only discover by looking around at run time: by then, it is too late to change what was compiled. ```mermaid flowchart LR host["The machine compiling
(here: Windows x86-64)"] --> rux["`rux build --target …`"] rux -- "no `--target`" --> w["target `os` is `.Windows`
→ a Windows program"] rux -- "`--target linux-x86_64`" --> l["target `os` is `.Linux`
→ a Linux program"] rux -- "`--target macos-aarch64`" --> m["target `arch` is `.AArch64`
→ a program for an Apple silicon Mac"] ``` ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/CompileTime/Target){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // Every build is for one machine: an operating system and a processor architecture. `#target` // describes that machine as ordinary values, filled in by the compiler, so `when` can branch on // them and keep only the code that fits. // // The target is the machine the program will run on, not the one compiling it. Ask for another // with `rux build --target linux-x86_64`, and every branch below is chosen again for Linux, even // though the compiler is still running on Windows. That is why platform code branches on // `#target` and never on anything it could discover at run time. import Core::{ #target, OperatingSystem }; import Io::PrintLine; // The match form of `when` picks one arm by value. Each arm declares the same constant, so the // rest of the program uses `SystemName` without caring which arm produced it. when #target.os { .Windows => const SystemName: char8[..] = "Windows"; .Linux => const SystemName: char8[..] = "Linux"; .macOS => const SystemName: char8[..] = "macOS"; .FreeBSD => const SystemName: char8[..] = "FreeBSD"; else => const SystemName: char8[..] = "an unknown system"; } when #target.arch { .X86_64 => const ProcessorName: char8[..] = "x86-64"; .AArch64 => const ProcessorName: char8[..] = "AArch64"; else => const ProcessorName: char8[..] = "an unknown processor"; } // The ordinary form works too, for a yes-or-no question about the target. when #target.os == OperatingSystem::Windows { const PathSeparator: char8[..] = "\\"; } else { const PathSeparator: char8[..] = "/"; } func Main() -> int { PrintLine("Built for {} on {}", SystemName, ProcessorName); PrintLine("Target name: {}", #target.triple); PrintLine("A path here looks like Users{}Ada{}Notes.txt", PathSeparator, PathSeparator); return 0; } ``` Besides `Io`, its `Rux.toml` lists `Core` under `[Dependencies]`. ## Run it ```sh cd Examples/CompileTime/Target rux run ``` ```text Built for Windows on x86-64 Target name: windows-x86_64 A path here looks like Users\Ada\Notes.txt ``` This is the output of a Windows x86-64 build; other targets print their own names and separator. ## Common mistakes ::mistake **Leaving out the `else` arm.**:br A match-form `when` with no arm for the system being built stops the build. Remove the `.FreeBSD` and `else` arms, run `rux check --target freebsd-x86_64`, and it fails with: ```text error: no arm of this 'when' matches .FreeBSD ``` :: ::mistake **Spelling a variant the old way.**:br The variant is `.macOS`, with a lower-case m. `.MacOS` fails with: ```text error: '.MacOS' is not a variant of 'OperatingSystem' ``` The message goes on to list the variants that do exist. :: ::mistake **Ordering an enum.**:br`when #target.os < .Windows` fails with: ```text error: 'when' condition is not a valid compile-time expression ``` Systems and architectures compare only with `==` and `!=`. :: ## Try it yourself 1. Run `rux build --target linux-x86_64`, then `rux build --target macos-aarch64`, and look at the folders that appear under `Bin/Debug/`. 2. Remove the `.FreeBSD` and `else` arms from the first `when`. Check the program for each of `windows-x86_64`, `linux-x86_64`, `macos-aarch64` and `freebsd-x86_64` with `rux check --target …`. Which ones still build? 3. Add a `when #target.dataModel == .LLP64` that prints "C's long is 32 bits here", with an `else` that prints "64 bits". What do you expect for Windows, and for Linux? 4. Print `#target.pointerBits` on its own line. ## Learn more - [Build context](https://rux-lang.dev/docs/lang/comptime/context) in the Rux Reference — every field of `#target` - [`#target`](https://rux-lang.dev/docs/api/core/target#target-constant) in the Core API reference - [`rux build`](https://rux-lang.dev/docs/cli/build) — `--target` and the other build options - [Enum](https://rux-lang.dev/docs/learn/enum) and [Match](https://rux-lang.dev/docs/learn/match) — the run-time forms of what this lesson does at compile time - [Extern](https://rux-lang.dev/docs/learn/extern) — calling a library that only one system has # Build mode ::note **You'll need**: [When](https://rux-lang.dev/docs/learn/when), [Assert](https://rux-lang.dev/docs/learn/assert) :: The same source can be built two ways. While you are writing a program you want it to compile quickly and to catch every mistake as early as possible. When you hand it to someone, you want it small and fast. Rux calls these two a **debug build** and a **release build**, and `#build` lets the program ask which one it is part of. The [Assert](https://rux-lang.dev/docs/learn/assert) lesson already met the difference from the outside: `DebugAssert` is checked in one and gone from the other. This lesson looks at it from the inside. ## Debug and release `rux run` and `rux build` make a debug build unless you say otherwise. Add `--release` for the other kind: ```sh rux run # debug rux run --release # release ``` | | Debug | Release | | ----------------- | -------------------------------- | -------------------------- | | Optimized | no — the code follows the source | yes | | Debug information | emitted | left out | | `DebugAssert` | checked | removed | | Output folder | `Bin/Debug///` | `Bin/Release///` | | Good for | writing and testing | shipping | ## Asking which build this is `#build` comes from `Core`, like `#target`, and is just as free to read: every field is fixed before compiling starts and folds into the program as a constant. ```rux PrintLine("Profile: {}", #build.profile); when #build.mode == BuildMode::Debug { PrintLine("Debug build: unoptimized, with every check switched on"); } else { PrintLine("Release build: optimized, with the debug checks compiled out"); } ``` `profile` is a name — `Debug` or `Release` here, but a project may name its own profiles, so the name is not the thing to branch on. `mode` is the part every profile has: always `BuildMode::Debug` or `BuildMode::Release`. Because `mode` is known while compiling, the `when` keeps only one of the two `PrintLine` calls; the release program does not contain the debug message at all. `#build` has a few more fields worth knowing: | Field | Type | Holds | | ----------------- | ----------- | ------------------------------------------------------ | | `profile` | `char8[..]` | the profile's name | | `mode` | `BuildMode` | `.Debug` or `.Release` | | `debugAssertions` | `bool` | whether `DebugAssert` checks are kept | | `debugInfo` | `bool` | whether debug information is emitted | | `isTest` | `bool` | whether this is a `rux test` build | | `date`, `time` | `char8[..]` | when the build started, as `YYYY-MM-DD` and `HH:MM:SS` | The program prints `#build.debugAssertions` because it answers the narrower question the rest of the program cares about: will the next line be checked? ## A check that costs nothing once you ship `DebugAssert` takes a condition and a message, just like `Assert`. In a debug build it behaves exactly like `Assert`. In a release build it is removed entirely — and its arguments are **not even evaluated**: ```rux // Stands in for a slow consistency check. The line it prints shows whether it ran at all. func ScoresAreSorted() -> bool { PrintLine(" ...checking that the scores are sorted"); return true; } ``` ```rux DebugAssert(ScoresAreSorted(), "the scores must be sorted"); ``` Compare the two outputs below: the line `...checking that the scores are sorted` appears only in the debug run. In the release program `ScoresAreSorted` is never called, so an expensive check costs exactly nothing. ```mermaid flowchart LR d["`DebugAssert(condition, message)`"] --> m{"Which build?"} m -- "debug" --> ev["`condition` is evaluated"] ev -- "`true`" --> on["the program carries on"] ev -- "`false`" --> stop["`Assertion failed: message`
the program stops"] m -- "release" --> gone["the call is removed;
`condition` is never evaluated"] gone --> on ``` That is also the catch. Anything a `DebugAssert` argument does — print, count, save — happens in a debug build and silently does not happen in a release one. Keep the condition a pure question, and use [`Assert`](https://rux-lang.dev/docs/learn/assert) for checks that must still run in the program you ship. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/CompileTime/BuildMode){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // `rux run` makes a debug build: unoptimized, quick to compile, full of checks. `rux run --release` // makes a release build: optimized, with the debug-only checks taken out. `#build` describes the // build in progress, and `#build.mode` says which of the two it is. // // `DebugAssert` is the check that comes and goes. In a debug build it behaves like `Assert`. In a // release build it is removed entirely, and its arguments are not even evaluated, so an expensive // check costs nothing once you ship. The other side of that bargain: never put work the program // needs inside one, or a release build will quietly skip it. import Core::{ #build, BuildMode, DebugAssert }; import Io::PrintLine; // Stands in for a slow consistency check. The line it prints shows whether it ran at all. func ScoresAreSorted() -> bool { PrintLine(" ...checking that the scores are sorted"); return true; } func Main() -> int { // A project may name its own profiles; the mode is the part every profile has. PrintLine("Profile: {}", #build.profile); when #build.mode == BuildMode::Debug { PrintLine("Debug build: unoptimized, with every check switched on"); } else { PrintLine("Release build: optimized, with the debug checks compiled out"); } // `#build.debugAssertions` answers the narrower question of whether those checks are kept. PrintLine("Debug assertions kept: {}", #build.debugAssertions); DebugAssert(ScoresAreSorted(), "the scores must be sorted"); PrintLine("Done"); return 0; } ``` Besides `Io`, its `Rux.toml` lists `Core` under `[Dependencies]`. ## Run it ```sh cd Examples/CompileTime/BuildMode rux run ``` ```text Profile: Debug Debug build: unoptimized, with every check switched on Debug assertions kept: true ...checking that the scores are sorted Done ``` ```sh rux run --release ``` ```text Profile: Release Release build: optimized, with the debug checks compiled out Debug assertions kept: false Done ``` ## Common mistakes ::mistake **Putting needed work inside `DebugAssert`.**:br`DebugAssert(SaveScores(), "the scores were saved")` saves the scores in a debug build and never calls `SaveScores` in a release one. Do the work first, keep the result in a variable, and assert on the variable. :: ::mistake **Using `DebugAssert` for a promise the shipped program relies on.**:br A release build removes it, so a broken assumption sails straight past. If the check must hold for your users too, write `Assert`. :: ::mistake **Branching on the profile's name.**:br A project can name its own profiles, so comparing `#build.profile` against `"Release"` misses every release profile with another name. Branch on `#build.mode`. :: ## Try it yourself 1. Make `ScoresAreSorted` return `false`. Run the program with and without `--release`. The debug build stops with `Assertion failed: the scores must be sorted`; what does the release build print? 2. Print `#build.date` and `#build.time`, then build twice and compare. 3. Print `#build.debugInfo` in both builds. ## Learn more - [Build context](https://rux-lang.dev/docs/lang/comptime/context) in the Rux Reference — every field of `#build` - [`#build`](https://rux-lang.dev/docs/api/core/build#build-constant) and [`Assert`](https://rux-lang.dev/docs/api/core/diagnostics#assert) in the Core API reference - [`rux run`](https://rux-lang.dev/docs/cli/run) and [`rux build`](https://rux-lang.dev/docs/cli/build) — the `--release` option - [Assert](https://rux-lang.dev/docs/learn/assert) — `Assert` and `DebugAssert` from the run-time side - [Define](https://rux-lang.dev/docs/learn/define) — build switches of your own # Source location ::note **You'll need**: [Function](https://rux-lang.dev/docs/learn/function), [Target](https://rux-lang.dev/docs/learn/target) :: When something goes wrong, the first question is usually "where?". A log line that says `Main.rux:31` saves a search through the whole program, and that is why every compiler error you have read so far starts with a file, a line and a column. `#source` gives your own program the same knowledge: the file, the line and column, and the function an expression is written in. Like [`#target`](https://rux-lang.dev/docs/learn/target), `#source` is filled in by the compiler while it compiles. A read costs nothing at run time — by then it is just a constant number or a piece of text. ## Reading `#source` `#source` comes from `Core`. Read its fields with a dot: ```rux PrintLine("This read is at line {}, column {} of {}, in {}", #source.line, #source.column, #source.fileName, #source.function); ``` This prints `line 24, column 23 of Main.rux, in Main`. Look closely at the column: 23 is not where the `PrintLine` starts, nor where `#source.line` starts. It is exactly where `#source.column` is written. Every read describes **itself** — the expression that does the reading — and nothing else. | Field | Type | In this program | | ---------- | ----------- | ---------------- | | `line` | `uint` | `24` | | `column` | `uint` | `23` | | `fileName` | `char8[..]` | `"Main.rux"` | | `filePath` | `char8[..]` | `"Src/Main.rux"` | | `function` | `char8[..]` | `"Main"` | | `module` | `char8[..]` | `"Main"` | `fileName` is the file's name alone; `filePath` is its path inside the package, which tells two `Main.rux` files in different folders apart. ## Which place does it describe? That rule — a read describes where it is written — has a consequence that surprises almost everyone. A helper that reads `#source.line` inside its own body reports its own line, every time, no matter who called it: ```rux // Reads `#source` in its own body, so it always describes this function. func LogHere(message: char8[..]) { PrintLine(" {}:{} in {}: {}", #source.fileName, #source.line, #source.function, message); } ``` Both calls print `Main.rux:14 in LogHere`. Line 14 is the line inside `LogHere`, and `LogHere` is the function around it — true, and useless for finding the caller. To report where a call came from, the **caller** has to read `#source.line` and pass the value in: ```rux // Is handed the location by its caller, so it describes the call. func LogAt(line: uint, message: char8[..]) { PrintLine(" line {}: {}", line, message); } ``` ```rux LogAt(#source.line, "first call"); LogAt(#source.line, "second call"); ``` Now the two calls print lines 31 and 32 — their own lines, because that is where `#source.line` is written. ```mermaid flowchart LR c1["line 27: `LogHere(…)`"] --> h["`LogHere` reads `#source.line`
at line 14"] c2["line 28: `LogHere(…)`"] --> h h --> o1["both print `14`"] c3["line 31: `LogAt(#source.line, …)`"] --> o2["prints `31`"] c4["line 32: `LogAt(#source.line, …)`"] --> o3["prints `32`"] ``` ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/CompileTime/SourceLocation){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // `#source` tells a program where it is in its own source code: the file, the line and column, // and the function around it. Like `#target`, the compiler fills it in while compiling, so a read // costs nothing at run time — it is just a constant. // // The surprise is *which* place it describes. Every read of `#source` describes the expression // that reads it, wherever that is written. A helper that reads `#source.line` inside its own body // therefore reports its own line, every time, no matter who called it. To report where a call // came from, the caller has to read `#source.line` itself and pass the value in. import Core::{ #source }; import Io::PrintLine; // Reads `#source` in its own body, so it always describes this function. func LogHere(message: char8[..]) { PrintLine(" {}:{} in {}: {}", #source.fileName, #source.line, #source.function, message); } // Is handed the location by its caller, so it describes the call. func LogAt(line: uint, message: char8[..]) { PrintLine(" line {}: {}", line, message); } func Main() -> int { PrintLine("This read is at line {}, column {} of {}, in {}", #source.line, #source.column, #source.fileName, #source.function); PrintLine("A helper that reads #source itself:"); LogHere("first call"); LogHere("second call"); PrintLine("A helper that is passed #source.line:"); LogAt(#source.line, "first call"); LogAt(#source.line, "second call"); return 0; } ``` Besides `Io`, its `Rux.toml` lists `Core` under `[Dependencies]`. ## Run it ```sh cd Examples/CompileTime/SourceLocation rux run ``` ```text This read is at line 24, column 23 of Main.rux, in Main A helper that reads #source itself: Main.rux:14 in LogHere: first call Main.rux:14 in LogHere: second call A helper that is passed #source.line: line 31: first call line 32: second call ``` ## Common mistakes ::mistake **Expecting a helper to know its caller.**:br A helper that reads `#source` in its own body describes its own body. If a log line should name the call site, read `#source.line` at the call and pass it in, as `LogAt` does. :: ::mistake **Forgetting the import.**:br`#source` is declared in `Core`, so without `import Core::{ #source };` a read fails with: ```text error: name '#source' is not defined in this scope ``` :: ## Try it yourself 1. Print `#source.filePath` and `#source.module` next to `#source.fileName`. 2. Write `func Check(condition: bool, line: uint)` that prints `check failed at line N` when the condition is false. Call it twice from `Main`, once with `2 + 2 == 5`, passing `#source.line` each time. 3. Join the first `PrintLine` call onto a single line. Predict the new line and column before you run. ## Learn more - [Build context](https://rux-lang.dev/docs/lang/comptime/context) in the Rux Reference — every field of `#source` - [`#source`](https://rux-lang.dev/docs/api/core/source#source-constant) in the Core API reference - [Assert](https://rux-lang.dev/docs/learn/assert) and [Panic](https://rux-lang.dev/docs/learn/panic) — they report the file, line and column of the call that failed - [Compile error](https://rux-lang.dev/docs/learn/compile-error) — making the compiler itself report a location # Compile error ::note **You'll need**: [When](https://rux-lang.dev/docs/learn/when), [Target](https://rux-lang.dev/docs/learn/target), [Tooling](https://rux-lang.dev/docs/learn/tooling) :: Some mistakes are better caught by the compiler than by whoever runs the program. A program that needs 64-bit pointers should refuse to be built for anything else, with a message that says why, instead of building and then misbehaving. A function that has a better replacement should tell everyone who still calls it. These are messages from the source code to the person building it, and three directives carry them: | Directive | Effect | | ---------------- | --------------------------------------------------------- | | `#Error("…")` | stops the build with that message | | `#Warn("…")` | prints a warning and lets the build carry on | | `#Allow("rule")` | silences one `rux lint` rule for the declaration below it | ## Stopping the build with `#Error` `#Error` stops the build wherever the compiler reaches it. So it is almost always written inside a [`when`](https://rux-lang.dev/docs/learn/when) branch — the branch a build should never take: ```rux when #target.pointerBits < 64 { #Error("this program needs a 64-bit target"); } ``` Every target Rux supports today has 64-bit pointers, so this branch is never taken, and a branch that is not taken is never looked at: the directive in it never fires. Flip the condition to `>= 64` and the build stops on the spot, pointing at the directive: ```text Src/Main.rux:35:9: error: this program needs a 64-bit target ``` Used like this, `#Error` is a statement, so it is imported from `Core` like any other name: `import Core::{ #Error, #target };`. Its message must be a string literal written right there — the compiler prints it while compiling, long before any variable has a value. ## Warning every caller with `#Warn` Written above a declaration, as an attribute, a directive fires at every **use** of that declaration rather than where it is written. That is how an old function points its callers at the new one: ```rux // Fires at each call below, as a warning; the program still builds and runs. #Warn("Average rounds toward zero; call AverageRounded instead") func Average(total: int, count: int) -> int { return total / count; } ``` The warning at the top of the output below comes from this attribute. It points at line 38, column 41 — the call to `Average` in `Main`, not the declaration — and the program still builds and runs. `#Error` works as an attribute too: the build then stops at the first call, which is how a removed function can explain where to go instead of just vanishing. As an attribute, neither directive needs an import; that is why the program imports `#Error` but not `#Warn`. Written as a statement inside a body, `#Warn("…");` is imported from `Core` exactly like `#Error`. | Written as | Fires | Import from `Core` | | ----------------------------- | ------------------------------------- | ------------------ | | a statement, `#Error("…");` | where it is reached; stops the build | yes | | a statement, `#Warn("…");` | where it is reached; build carries on | yes | | an attribute on a declaration | at every use of that declaration | no | ## Silencing one lint rule with `#Allow` [`rux lint`](https://rux-lang.dev/docs/learn/tooling) checks style rules the compiler does not. One of them asks for PascalCase constant names, which would turn kilobytes (kB) into KB. The spelling is deliberate here, so the rule is switched off for this one declaration and nowhere else: ```rux #Allow("naming.const") const kB: int = 1000; ``` Without the attribute, `rux lint` reports `warning: constant name 'kB' should be PascalCase` and suggests renaming it to `KB`. The rules `#Allow` accepts are `naming.type`, `naming.const` and `docs.missing`. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/CompileTime/CompileError){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // Some mistakes are better caught by the compiler than by whoever runs the program. Three // directives let source code speak to the build: // // - `#Error("...")` stops the build with that message, wherever it is reached. // - `#Warn("...")` prints a warning and lets the build carry on. // - `#Allow("rule")` silences one `rux lint` rule for the declaration it is attached to. // // `#Error` is almost always written inside a `when` branch: the branch a build should never take. // A branch that is not taken is never looked at, so the directive in it never fires. Written as // an attribute on a declaration instead, `#Error` or `#Warn` fires at every use of that // declaration, which is how an old function points its callers at the new one. import Core::{ #Error, #target }; import Io::PrintLine; // Fires at each call below, as a warning; the program still builds and runs. #Warn("Average rounds toward zero; call AverageRounded instead") func Average(total: int, count: int) -> int { return total / count; } func AverageRounded(total: int, count: int) -> int { return (total + count / 2) / count; } // `rux lint` asks for PascalCase constant names, which would turn kilobytes (kB) into KB. The // spelling is deliberate here, so the rule is switched off for this one declaration. #Allow("naming.const") const kB: int = 1000; func Main() -> int { // Every supported target has 64-bit pointers, so this branch is never taken. Flip the // condition to `>= 64` and the build stops with: // Src/Main.rux:35:9: error: this program needs a 64-bit target when #target.pointerBits < 64 { #Error("this program needs a 64-bit target"); } PrintLine("Average of 7 and 8: {}", Average(15, 2)); PrintLine("Rounded average: {}", AverageRounded(15, 2)); PrintLine("A 3 kB file holds {} bytes", 3 * kB); return 0; } ``` Besides `Io`, its `Rux.toml` lists `Core` under `[Dependencies]`. ## Run it ```sh cd Examples/CompileTime/CompileError rux run ``` ```text Src\Main.rux:38:41: warning: Average rounds toward zero; call AverageRounded instead 38 | PrintLine("Average of 7 and 8: {}", Average(15, 2)); | ^ note: compiler phase: Analyzing Average of 7 and 8: 7 Rounded average: 8 A 3 kB file holds 3000 bytes ``` The compiler prints the file's full path where this shows `Src\Main.rux`. ## Common mistakes ::mistake **An `#Error` with no `when` around it.**:br A directive that is always reached always fires. Written straight into a body, `#Error("…");` stops every build, on every target. Put it in the branch that should never be taken. :: ::mistake **A message that is not a literal.**:br`#Warn(Message);` with `Message` a constant fails with: ```text error: '#Warn' message must be a string literal ``` Write the text in place. :: ::mistake **The statement form without its import.**:br Inside a body, `#Warn("…");` without importing it fails with: ```text error: name '#Warn' is not defined in this scope ``` Add it to the `import Core::{ … }` line. :: ::mistake **Misspelling a lint rule.**:br`#Allow("naming.konst")` stops the build with: ```text error: unknown lint rule 'naming.konst'; valid rules are: naming.type, naming.const, docs.missing ``` :: ## Try it yourself 1. Flip the condition to `when #target.pointerBits >= 64` and build. Then flip it back. 2. Delete the `#Allow` line, run `rux lint`, and read the suggestion. 3. Replace the `#Warn` on `Average` with `#Error("Average was removed; call AverageRounded instead")`. Where does the build stop? Change the call to make it build again. 4. Add a statement `#Warn("remember to update the scores table");` at the top of `Main`, and the import it needs. ## Learn more - [Error](https://rux-lang.dev/docs/lang/attributes/error), [Warn](https://rux-lang.dev/docs/lang/attributes/warn) and [Allow](https://rux-lang.dev/docs/lang/attributes/allow) in the Rux Reference - [`#Error`](https://rux-lang.dev/docs/api/core/diagnostics#error) and [`#Warn`](https://rux-lang.dev/docs/api/core/diagnostics#warn) in the Core API reference - [`rux lint`](https://rux-lang.dev/docs/cli/lint) — the rules `#Allow` can silence - [Tooling](https://rux-lang.dev/docs/learn/tooling) — `rux fmt`, `rux lint` and friends - [Extern](https://rux-lang.dev/docs/learn/extern) — an `#Error` that explains why a build for the wrong system stops # Define ::note **You'll need**: [When](https://rux-lang.dev/docs/learn/when), [Build mode](https://rux-lang.dev/docs/learn/build-mode) :: `#target` and `#build` answer questions the compiler already knows: which machine, which kind of build. A **define** is a question you answer yourself — a named value handed to the build, such as a feature switch, a customer's name or the address of a test server. The program reads it while compiling with `#config`, so a `when` can branch on it and keep only the code that applies. ## Handing a value to the build On the command line, `--define` takes a name and, optionally, a value. Repeat it for each define: ```sh rux run --define Name=Ada --define Verbose ``` A define without a value, like `Verbose` here, holds the text `"true"`. Defines that belong to the project rather than to one build go in a `[Build.Defines]` table in `Rux.toml`: ```toml [Build.Defines] Name = "Grace" ``` The two combine: the manifest gives the defaults, and `--define` overrides them for one build. With the table above, `rux run` greets Grace and `rux run --define Name=Ada` greets Ada. A manifest value may be a string, a boolean or an integer, but `#config` always hands it to the program as text — `Retries = 3` reads as `"3"`. ```mermaid flowchart LR m["`Rux.toml`
`[Build.Defines]`"] --> merge{"the build's defines"} c["`--define Name=Value`
on the command line"] -- "overrides" --> merge merge --> has["`Has`: is it
defined at all?"] merge --> get["`Get`: its text,
or empty"] has --> w["`when` picks the code
while compiling"] get --> w ``` ## Has and Get `#config` comes from `Core` and has two questions to ask: - `#config.Has("Name")` says whether the build defines `Name` at all. - `#config.Get("Name")` gives its text, or an empty string when it is not defined. `Get` alone cannot tell "not defined" from "defined as empty", so the program asks `Has` first: ```rux when #config.Has("Name") { let name = #config.Get("Name"); } else { let name = "World"; } PrintLine("Hello, {}!", name); ``` | How the build was started | `Has("Name")` | `Get("Name")` | Greeting | | --------------------------- | ------------- | ------------- | --------------- | | `rux run` | `false` | `""` | `Hello, World!` | | `rux run --define Name=Ada` | `true` | `"Ada"` | `Hello, Ada!` | | `rux run --define Name=` | `true` | `""` | `Hello, !` | As in the [When](https://rux-lang.dev/docs/learn/when) lesson, the `when` opens no scope, so `name` is still there for the `PrintLine` after it. The last line of the program shows `Get` on a name nobody defined: its `length` is 0. ## A feature switch The most common use of a define is to switch a feature on or off: ```rux when #config.Has("Verbose") { PrintLine("Verbose is on (its value is \"{}\")", #config.Get("Verbose")); } else { PrintLine("Verbose is off; rebuild with --define Verbose to turn it on"); } ``` The untaken branch is not part of the program at all — a build without `Verbose` contains no trace of the verbose code. The flip side is that a define is fixed once the program is built. Changing one means **rebuilding**: `rux run` does that for you, but an `.exe` you built earlier keeps the defines it was built with. Because both questions are answered while compiling, the name must be written as a string literal in the source. Even a `const` holding the name is refused. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/CompileTime/Define){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // `#target` and `#build` answer questions the compiler already knows. A define is a question you // answer yourself: a named value handed to the build, such as a feature switch or a customer's // name. Pass one on the command line with `--define Name=Value`, or list it in a `[Build.Defines]` // table in `Rux.toml`. The program reads it with `#config`: // // - `#config.Has("Name")` says whether the build defines `Name` at all. // - `#config.Get("Name")` gives its text, or an empty string when it is not defined. // // A define without a value, such as `--define Verbose`, holds the text "true". Both questions are // answered while compiling, so `when` can branch on them, and changing a define means rebuilding. // For the same reason the name must be written as a string literal: passing a variable is refused // with "the argument to 'Has' must be a string literal written in the source". import Core::{ #config }; import Io::PrintLine; func Main() -> int { // Has tells "not defined" apart from "defined as empty", which Get alone cannot. when #config.Has("Name") { let name = #config.Get("Name"); } else { let name = "World"; } PrintLine("Hello, {}!", name); // A feature switch: the untaken branch is not part of the program at all. when #config.Has("Verbose") { PrintLine("Verbose is on (its value is \"{}\")", #config.Get("Verbose")); } else { PrintLine("Verbose is off; rebuild with --define Verbose to turn it on"); } PrintLine("An undefined name reads as {} characters", #config.Get("Missing").length); return 0; } ``` Besides `Io`, its `Rux.toml` lists `Core` under `[Dependencies]`. ## Run it ```sh cd Examples/CompileTime/Define rux run ``` ```text Hello, World! Verbose is off; rebuild with --define Verbose to turn it on An undefined name reads as 0 characters ``` ```sh rux run --define Name=Ada --define Verbose ``` ```text Hello, Ada! Verbose is on (its value is "true") An undefined name reads as 0 characters ``` ## Common mistakes ::mistake **Naming the define with a variable.**:br`#config.Has(key)` fails with: ```text error: the argument to 'Has' must be a string literal written in the source ``` So does a constant. Inside a `when` condition the same mistake reads: ```text error: 'key' is not a compile-time constant ``` Write the name in quotes. :: ::mistake **Testing presence with `Get`.**:br An empty answer from `Get` means either "not defined" or "defined as empty". Ask `Has` when the difference matters. :: ::mistake **Expecting a built program to see a new define.**:br A define is folded in while compiling. Running an old `.exe` with a new `--define` in mind changes nothing; build again. :: ## Try it yourself 1. Run the program with `--define Name=Ada --define Verbose`, then with `--define Name=` alone. Explain the second greeting. 2. Add a `[Build.Defines]` table to `Rux.toml` with `Name = "Grace"`. Run with and without `--define Name=Ada`. 3. Add a `when #config.Get("Name") == "Ada"` that prints an extra line just for Ada. ## Learn more - [Build context](https://rux-lang.dev/docs/lang/comptime/context) in the Rux Reference — `#config` and the rest of the build context - [`#config`](https://rux-lang.dev/docs/api/core/config#config-constant) in the Core API reference - [Package manifest](https://rux-lang.dev/docs/packaging/manifest) — the `[Build.Defines]` table - [`rux run`](https://rux-lang.dev/docs/cli/run) and [`rux build`](https://rux-lang.dev/docs/cli/build) — the `--define` option - [Build mode](https://rux-lang.dev/docs/learn/build-mode) — the other switch every build has # Intrinsic ::note **You'll need**: [Dependency](https://rux-lang.dev/docs/learn/dependency), [Target](https://rux-lang.dev/docs/learn/target), [Assert](https://rux-lang.dev/docs/learn/assert) :: `int8::Max`, `#target` and `Assert` have come from `Core` in every lesson so far, so it is easy to think of them as part of the language itself. They are not. The type `int8` is built into the compiler, but its constants come from an **extension**, and `#target` and `Assert` from **declarations** of what the compiler implements — the fields of `#target`, the code an `Assert` turns into. `Core` is simply the package that usually provides both. An `intrinsic` declaration names something the compiler supplies and gives its type, with no body. This lesson writes a few of them in `Basis`, a small provider package of its own, and runs a program that takes everything from `Basis` instead of `Core`. Nothing changes: the program works exactly as it would with `Core`. ## An extension and three kinds of intrinsic Open `Basis/Src/Basis.rux` in the code tree below. It is a handful of lines, and each part provides something different. **Constants on a built-in type**. `int8`, like every primitive type, is built into the compiler, so nothing declares it. The constants on it are ordinary source in an extension, so the provider decides which ones to offer: ```rux extend int8 { pub const Min: int8 = -128i8; pub const Max: int8 = 127i8; } ``` A **constant** whose value no literal can spell. There is no way to write infinity in source, so the compiler supplies it: ```rux extend float64 { pub intrinsic const Infinity: float64; } ``` A **compile-time value**. `#target` is declared as an ordinary struct plus one intrinsic line that says "the compiler fills this in". The provider lists only the fields it wants to expose: ```rux pub struct Target { pub pointerBits: uint; } pub intrinsic #target: Target; ``` A **function** the compiler emits inline. The provider writes the signature, which must be the one the compiler expects: ```rux pub intrinsic func Assert(condition: bool, message: char8[..]); ``` `Core` declares all of these in exactly the same way — its own `Assert` is that same line, word for word. The package gets no special powers from being called `Core`. | Kind | The compiler supplies | The provider writes | | ----------------- | --------------------------- | -------------------------------------- | | `extend int8` | the type and its operations | constants and methods, as plain source | | `intrinsic const` | the value | the name and the type | | `intrinsic #name` | each field's value | the struct, with the fields it exposes | | `intrinsic func` | the code at every call | the signature the compiler expects | ## Taking them from a provider `Basis` is a [source library](https://rux-lang.dev/docs/learn/source-library) in a folder beside the program, and the program's `Rux.toml` names it with a path [dependency](https://rux-lang.dev/docs/learn/dependency): `Basis = { Path = "Basis" }`. There is no `Core` in that manifest at all. The program imports from `Basis` the same names it would otherwise import from `Core`; importing `int8` and `float64` imports `Basis`'s extensions of them: ```rux import Basis::{ #target, Assert, float64, int8 }; ``` ```mermaid flowchart LR c(["The compiler implements
`int8`, `Infinity`, `#target`, `Assert`"]) --> core["`Core` declares them
(the usual provider)"] c --> basis["`Basis` declares them
(this lesson's provider)"] core -.->|"every other lesson"| p["`Main.rux` imports
the declarations"] basis -->|"this lesson"| p ``` Since only `Basis` is imported, only what `Basis` declares is available. The type `int16` still exists, but `int16::Max` does not: no provider in this program offers it, and `import Basis::int16;` is refused because `Basis` does not extend it. ## Only real intrinsics `intrinsic` cannot invent new features. Every declaration is checked against what the compiler really implements, and anything else is refused: a function called `Square`, a `wordSize` field on `Target`, an `Assert` whose condition is an `int`. A type cannot be declared at all, since every primitive is built in. Writing a provider is a way to replace `Core`, not a way to extend the language. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/CompileTime/Intrinsic){rel=""nofollow""}. Its comments explain every step. ::code-tree{default-value="Src/Main.rux"} ```toml [Rux.toml] [Manifest] Version = 1 MinRux = "0.4.0" [Package] Name = "Intrinsic" Version = "0.1.0" Type = "Executable" Description = "Declaring compiler-provided constants and values in a provider package of your own" Authors = ["Rux Contributors "] [Dependencies] Basis = { Path = "Basis" } Io = { Namespace = "Rux", Version = "*" } ``` ```toml [Basis/Rux.toml] [Manifest] Version = 1 MinRux = "0.4.0" [Package] Name = "Basis" Version = "0.1.0" Type = "SourceLibrary" Description = "A small provider of primitive extensions and intrinsic declarations, standing in for part of Core" Authors = ["Rux Contributors "] ``` ```rux [Src/Main.rux] // `int8::Max`, `#target` and `Assert` have always come from `Core`, so they can look like part of // the language. They are not. The type `int8` is built in, but its constants come from an // extension, and `#target` and `Assert` from *declarations*; `Core` is simply the package that // usually provides both. An `intrinsic` declaration names something the compiler supplies and // gives its type, with no body. // // This lesson takes the declarations from `Basis`, a small provider package beside this one, // instead of from `Core`. Open `Basis/Src/Basis.rux`: it is a handful of lines, and the program // below works the same as it would with `Core`. // // Only real intrinsics can be declared this way. An `intrinsic func` the compiler does not // implement "is not a supported intrinsic function", and a type cannot be declared at all: every // primitive is built in, so `intrinsic type int7` is refused because "intrinsic type declarations // have been removed". Writing a provider is a way to replace `Core`, not a way to invent new // language features. import Basis::{ #target, Assert, float64, int8 }; import Io::PrintLine; func Main() -> int { PrintLine("int8 runs from {} to {}", int8::Min, int8::Max); PrintLine("float64 can hold {}", float64::Infinity); PrintLine("Pointers on this target are {} bits wide", #target.pointerBits); let level: int8 = 100; Assert(level < int8::Max, "the level must leave room to grow"); PrintLine("Level {} passed the check", level); return 0; } ``` ```rux [Basis/Src/Basis.rux] // Everything here is either an extension of a built-in type or a declaration the compiler already // knows how to implement. `intrinsic` says "the compiler supplies this; here is its name and its // type", and gives it no body. The package gets no special powers from this: Core declares the // same things in exactly the same way. // The one-byte signed integer is built into the compiler, so nothing declares it. Its constants // are ordinary source in an extension, so the provider chooses which ones to offer. extend int8 { pub const Min: int8 = -128i8; pub const Max: int8 = 127i8; } // Infinity cannot be written as a literal, so the compiler supplies its value. extend float64 { pub intrinsic const Infinity: float64; } // A compile-time value. The provider declares only the fields it wants to expose, and only ones // the compiler fills in: a `wordSize` field is refused as "not one the compiler supplies for // '#target'". pub struct Target { pub pointerBits: uint; } pub intrinsic #target: Target; // A function the compiler emits inline. The signature must be the one the compiler expects: // declared with `condition: int`, it is refused with "intrinsic 'Assert' must be declared as // 'func Assert(condition: bool, message: char8[..])'". pub intrinsic func Assert(condition: bool, message: char8[..]); ``` :: ## Run it ```sh cd Examples/CompileTime/Intrinsic rux run ``` ```text int8 runs from -128 to 127 float64 can hold Inf Pointers on this target are 64 bits wide Level 100 passed the check ``` The provider is the companion package in `Basis/`. ## Common mistakes ::mistake **Declaring a type.**:br Every primitive type is built in, so `pub intrinsic type int7;` fails with: ```text error: intrinsic type declarations have been removed; primitive types are built in ``` Likewise, an `intrinsic func` the compiler does not implement fails with: ```text error: 'Square' is not a supported intrinsic function ``` :: ::mistake **Adding a field the compiler does not fill in.**:br A `wordSize` field on `Target` fails with: ```text error: field 'wordSize' of 'Target' is not one the compiler supplies for '#target' ``` Every field of an intrinsic struct must be one the compiler knows. :: ::mistake **Getting an intrinsic signature wrong.**:br Declared with `condition: int`, `Assert` fails with: ```text error: intrinsic 'Assert' must be declared as 'func Assert(condition: bool, message: char8[..])' ``` The message tells you the one signature it accepts. :: ::mistake **Using a constant the provider does not offer.**:br Only what `Basis` declares is in scope. `int16::Max` fails with: ```text error: 'Max' not found in extend for type 'int16' ``` That is because `Basis` declares no constants for `int16`. :: ## Try it yourself 1. Add `pub triple: char8[..];` to the `Target` struct in `Basis` and print `#target.triple` from `Main`. 2. Change `level` to `127` and run. Which line stops the program, and with what message? 3. Add `pub intrinsic type int8;` to `Basis`, read the error and its help, and take it out again. 4. Print `int16::Max` from `Main`. Then add the constants to `Basis`, the way `int8` has them, until it builds. ## Learn more - [Intrinsics](https://rux-lang.dev/docs/lang/comptime/intrinsics) and [Intrinsic constants](https://rux-lang.dev/docs/lang/comptime/context) in the Rux Reference - [The Core package](https://rux-lang.dev/docs/api/core) — the provider every other lesson uses - [Dependency](https://rux-lang.dev/docs/learn/dependency) and [Source library](https://rux-lang.dev/docs/learn/source-library) — how `Basis` reaches the program - [Target](https://rux-lang.dev/docs/learn/target) — the full `#target` that `Core` declares # Part 24: Platform Under every Rux program sits an operating system, full of functions written in C long before your program existed, and a processor that runs nothing but its own instructions. The standard packages usually stand between you and both. This part removes them: you declare and call a system function yourself, use the C runtime directly with its own types and conventions, let C call a Rux function back, and finally write function bodies in assembly for two different processors. Nothing here is everyday code — but after this part you will know what every `Io::PrintLine` eventually turns into, and how to reach a library no package covers yet. ## What you will learn - Declaring a function from a system library with `extern`, and naming the library with `#Link`. - Why the compiler takes such a declaration on trust, and what happens when it is wrong. - Calling the C runtime through the `C` package: C's own types, opaque pointers, C structs and variadic calls. - Checking C's failure values — null pointers and negative counts — because nothing panics for you. - Giving a foreign function a Rux name of its own, and choosing a calling convention with `#Abi`. - Writing an `asm func` in x86-64 assembly, and its AArch64 version, selected with `when #target.arch`. ## The path of a foreign call From the call site, a foreign function looks like any other. Underneath, each lesson adds one piece of the agreement between the two sides: ```mermaid flowchart LR invoke["A Rux call
`GetCurrentProcessId()`"] --> decl["`extern` declaration
name and types,
taken on trust · 24.1"] decl --> conv["calling convention
which registers carry
the arguments · 24.3"] conv --> link["`#Link`
library and symbol
24.1, 24.3"] link --> lib(["at run time:
the function in `Kernel32.dll`
or the C runtime · 24.2"]) lib -.->|"a callback, such as
`qsort`'s comparison · 24.3"| back["a Rux function
marked `#Abi(.C)`"] asm["A call to an `asm func`
24.4, 24.5"] --> pin["`#Abi`: the convention
the body was written for"] pin --> body(["your instructions,
emitted as written"]) ``` | Situation | Tool | Lesson | | ------------------------------------------ | ------------------------- | ------------------------------------------------------ | | a system function no package declares | `extern` and `#Link` | [Extern](https://rux-lang.dev/docs/learn/extern) | | anything in the C runtime | the `C` package | [C interop](https://rux-lang.dev/docs/learn/c-interop) | | a C name you would rather not spell | `#Link`'s second argument | [ABI](https://rux-lang.dev/docs/learn/abi) | | a Rux function that C calls back | `#Abi(.C)` | [ABI](https://rux-lang.dev/docs/learn/abi) | | an instruction the language cannot express | `asm func` | [Assembly](https://rux-lang.dev/docs/learn/asm) | ## Lessons | | Lesson | What you will learn | | ---- | ------------------------------------------------------- | ---------------------------------------------------------------------- | | 24.1 | [Extern](https://rux-lang.dev/docs/learn/extern) | call a platform API directly through an extern declaration and `#Link` | | 24.2 | [C interop](https://rux-lang.dev/docs/learn/c-interop) | C-compatible types, pointers and handles | | 24.3 | [ABI](https://rux-lang.dev/docs/learn/abi) | choose a calling convention with `#Abi` | | 24.4 | [Assembly](https://rux-lang.dev/docs/learn/asm) | write a function body in assembly | | 24.5 | [ARM assembly](https://rux-lang.dev/docs/learn/asm-arm) | the same function in AArch64 assembly, chosen with `when` | ## Before you start Finish [Part 23: Compile time](https://rux-lang.dev/docs/learn/compile-time) first: every lesson here uses `when #target` to keep platform code out of builds it cannot work in, and `#Error` to explain why. The C lessons also lean on [Part 15: Memory](https://rux-lang.dev/docs/learn/memory) — [Pointer](https://rux-lang.dev/docs/learn/pointer), [Pointer slice](https://rux-lang.dev/docs/learn/pointer-slice) and [Layout](https://rux-lang.dev/docs/learn/layout) — and on [Defer](https://rux-lang.dev/docs/learn/defer). Not every lesson runs everywhere. [Extern](https://rux-lang.dev/docs/learn/extern) calls `Kernel32.dll` and is Windows only; [Assembly](https://rux-lang.dev/docs/learn/asm) needs an x86-64 processor; the assembly in [ARM assembly](https://rux-lang.dev/docs/learn/asm-arm) runs only on AArch64, though the lesson builds anywhere. [C interop](https://rux-lang.dev/docs/learn/c-interop) and [ABI](https://rux-lang.dev/docs/learn/abi) run on Windows, Linux, macOS and FreeBSD. Each lesson's package is in the Examples repository's `Platform/` folder: ```sh cd Examples/Platform/Extern rux run ``` ## After this part Two more parts tour the standard packages: [Part 25: Concurrency](https://rux-lang.dev/docs/learn/concurrency) runs work on several threads at once, and [Part 26: Systems](https://rux-lang.dev/docs/learn/systems) talks to other processes, the command line and the network. [Part 27: Projects](https://rux-lang.dev/docs/learn/projects) puts it all together in complete small programs, and this part's checkpoint, [Melody](https://rux-lang.dev/docs/learn/melody), plays the opening of Ode to Joy through the console speaker by calling the Windows `Beep` function with `extern` — so it, too, is Windows only. For the full rules behind this part, see [Foreign function interface](https://rux-lang.dev/docs/lang/ffi/overview), [Link](https://rux-lang.dev/docs/lang/attributes/link), [Abi](https://rux-lang.dev/docs/lang/attributes/abi) and [Assembler functions](https://rux-lang.dev/docs/lang/ffi/assembly) in the Rux Reference, and [the C package](https://rux-lang.dev/docs/api/c) in the API reference. # Extern ::note **You'll need**: [Pointer](https://rux-lang.dev/docs/learn/pointer), [Target](https://rux-lang.dev/docs/learn/target), [Compile error](https://rux-lang.dev/docs/learn/compile-error) :: ::tip **Windows only.**:br The functions in this lesson come from `Kernel32.dll`, which only Windows has. On Linux, macOS or FreeBSD the build stops with an `#Error` that says so. :: Not every function a program calls was written in Rux. The operating system offers thousands of its own — to ask the time, open a window, find out which process you are — compiled long ago and shipped in **shared libraries**: `.dll` files on Windows, `.so` on Linux and FreeBSD, `.dylib` on macOS. The standard packages call them for you all the time. This lesson calls two directly. `extern` declares a function that lives in one of those libraries: its name, its parameters and its result, with no body, because the body is already in the library. `#Link` names the library, and the linker connects the two. ## Declaring a foreign function ```rux // One `#Link` on a block applies to every declaration inside it. #Link("Kernel32.dll") extern { // DWORD GetCurrentProcessId(void): the number Windows gave this running program. func GetCurrentProcessId() -> uint32; // int lstrlenA(const char *text): counts bytes up to the first zero byte. func lstrlenA(text: *char8) -> int32; } ``` The comments show each function as Microsoft's documentation writes it, in C. Writing the Rux declaration means translating that line, type by type: | In the C documentation | Means | In Rux | | ---------------------- | --------------------------------------- | -------- | | `DWORD` | a 32-bit unsigned number | `uint32` | | `int` | a 32-bit signed number | `int32` | | `const char *` | the address of bytes it will not change | `*char8` | | `void` (parameters) | no parameters | `()` | An `extern { }` block holds as many declarations as you like, and one `#Link` above it covers them all. A single function can be declared on its own too: `#Link("Kernel32.dll")` on one line, `extern func GetCurrentProcessId() -> uint32;` on the next. Once declared, a foreign function is called like any other — nothing at the call site says it is unusual: ```rux PrintLine("process id {}", GetCurrentProcessId()); ``` ## The compiler takes it on trust The compiler cannot look inside `Kernel32.dll` to check what you wrote. It takes the declaration on trust: declare `lstrlenA` with an `int64` parameter, and the call goes ahead and hands the function the wrong bytes. Nothing reports it; the program just behaves strangely. So copy a declaration carefully from the library's documentation — the [Windows API pages](https://rux-lang.dev/docs/api/windows) of this site list the declarations the `Windows` package already uses. On Windows the linker does check one thing: that the library really exports a function of that name. A misspelt name stops the build at the linking step instead of failing on the user's machine. ## Strings that end in a zero byte C functions do not receive a length with a string. They find the end by looking for a zero byte. A Rux string literal keeps one after its last character — `.length` does not count it — so `.data`, the address of the first byte, is exactly what a C function expects: ```rux let word = "extern"; PrintLine("Rux length {}", word.length); PrintLine("lstrlenA {}", lstrlenA(word.data)); ``` Both lines print 6: Rux counted the characters it stores, `lstrlenA` counted bytes up to the zero. That is true of string **literals**. A slice cut out of the middle of a string has no zero byte after it, and a C function handed its `.data` would read straight past the end. ## Building for the right system `Kernel32.dll` exists only on Windows, so the declarations are wrapped in a [`when`](https://rux-lang.dev/docs/learn/when) on the [target](https://rux-lang.dev/docs/learn/target), and every other system gets a [compile error](https://rux-lang.dev/docs/learn/compile-error) that explains itself: ```rux when #target.os { .Windows => { // … the extern block above … }, else => #Error("This lesson calls Kernel32.dll, so it builds for Windows only") } ``` Run `rux build --target linux-x86_64` on any machine and the build stops with exactly that message — far better than a program that builds and then cannot find its library. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Platform/Extern){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // Not every function a program calls was written in Rux. The operating system offers thousands // of its own, compiled long ago and shipped in shared libraries. `extern` declares one of them: // its name, its parameters and its result, with no body, because the body is already in the // library. `#Link` names that library, and the linker connects the two. // // The compiler cannot look inside the library to check the declaration. It takes what you wrote // on trust, so a wrong parameter type is not a compile error: the call goes ahead and passes the // wrong bytes. Copy a declaration carefully from the library's documentation. // // The functions below live in Kernel32.dll, which only Windows has. `when #target.os` keeps // them out of every other build, and `#Error` explains why such a build stops. import Core::{ #Error, #target }; import Io::PrintLine; when #target.os { .Windows => { // One `#Link` on a block applies to every declaration inside it. #Link("Kernel32.dll") extern { // DWORD GetCurrentProcessId(void): the number Windows gave this running program. func GetCurrentProcessId() -> uint32; // int lstrlenA(const char *text): counts bytes up to the first zero byte. func lstrlenA(text: *char8) -> int32; } }, else => #Error("This lesson calls Kernel32.dll, so it builds for Windows only") } func Main() -> int { // Called like any other function. Neither of these can fail, which is why they were // chosen: most system functions can, and the next lesson checks for that. PrintLine("process id {}", GetCurrentProcessId()); // C functions find the end of a string by looking for a zero byte. A Rux string literal // keeps one after its last character, though `.length` does not count it, so `.data`, the // address of the first byte, is exactly what a C function expects. let word = "extern"; PrintLine("Rux length {}", word.length); PrintLine("lstrlenA {}", lstrlenA(word.data)); return 0; } ``` Besides `Io`, its `Rux.toml` lists `Core` under `[Dependencies]`. ## Run it ```sh cd Examples/Platform/Extern rux run ``` ```text process id 6640 Rux length 6 lstrlenA 6 ``` The process id is different on every run. ## Common mistakes ::mistake **Passing a Rux string where C expects an address.**:br`lstrlenA(word)` fails with: ```text error: argument 1 to 'lstrlenA' has type 'char8[..]', but parameter 'text' requires '*char8' ``` Pass `word.data`. :: ::mistake **Forgetting `#Link`.**:br Without it the compiler does not know where the function lives: ```text error: extern function 'GetCurrentProcessId' must specify a source DLL via #Link("dll.dll") ``` :: ::mistake **Misspelling the function's name.**:br Library names are exact, capitals included. `GetCurrentProcessID` stops the build when linking: ```text error: cannot link PE/COFF executable 'Extern': import function 'GetCurrentProcessID' was not found in DLL 'Kernel32.dll' ``` :: ::mistake **A declaration that does not match the library.**:br A wrong parameter or result type is not an error at all: the compiler believes the declaration, and the function receives or returns the wrong bytes. Check every type against the documentation. :: ## Try it yourself 1. Add `GetCurrentThreadId`, which also takes nothing and returns a `DWORD`, to the `extern` block and print it. 2. Declare `GetTickCount64() -> uint64` and `Sleep(milliseconds: uint32)` from the same library. Read the tick count, sleep for 500 milliseconds, and print how long the sleep really took. 3. Run `rux build --target linux-x86_64` and read the message. ## Learn more - [Foreign function interface](https://rux-lang.dev/docs/lang/ffi/overview), [Extern declarations](https://rux-lang.dev/docs/lang/ffi/overview) and [Linking libraries](https://rux-lang.dev/docs/lang/ffi/linking) in the Rux Reference - [Link](https://rux-lang.dev/docs/lang/attributes/link) — the attribute in full, including a different symbol name - [`GetCurrentProcessId`](https://rux-lang.dev/docs/api/windows/process#get-current-process-id) and the rest of the [Windows package](https://rux-lang.dev/docs/api/windows) - [Shared library](https://rux-lang.dev/docs/learn/shared-library) — building a library of your own that `extern` can call - [C interop](https://rux-lang.dev/docs/learn/c-interop) — the next lesson, which calls the C runtime on every system # C interop ::note **You'll need**: [Extern](https://rux-lang.dev/docs/learn/extern), [Pointer slice](https://rux-lang.dev/docs/learn/pointer-slice), [Layout](https://rux-lang.dev/docs/learn/layout), [Defer](https://rux-lang.dev/docs/learn/defer) :: ::tip **Runs on Windows, Linux, macOS and FreeBSD.**:br The `C` package picks each system's own C runtime, so the same source builds everywhere. :: The C runtime is the one library almost every system has: memory allocation, formatted text, dates and times, sorting. The [Extern](https://rux-lang.dev/docs/learn/extern) lesson declared foreign functions by hand. For the C runtime you do not have to — the `C` package already declares much of it, and you import functions from it like from any other package: ```rux import C::{ c_int, free, gmtime, malloc, size_t, sprintf, time_t }; ``` What the package cannot do is make C feel like Rux. Every C interface is built from four shapes that Rux code does not otherwise meet, and this lesson uses each of them once. ## C's own types C's `int` is 32 bits, but Rux's `int` is 64. C's `long` is 32 bits on Windows and 64 everywhere else. So bindings are written in aliases named after C, which stand for whichever Rux type matches on the target being built: | Alias | C type | Rux type on Windows | Rux type on Linux, macOS, FreeBSD | | -------- | -------- | ------------------- | --------------------------------- | | `c_int` | `int` | `int32` | `int32` | | `c_long` | `long` | `int32` | `int64` | | `size_t` | `size_t` | `uint` | `uint` | | `time_t` | `time_t` | `int64` | `int64` | The `C` package chooses `c_long` with a `when #target.dataModel` — the same field the [Target](https://rux-lang.dev/docs/learn/target) lesson printed. Write a C binding's types in these aliases, never as `int` or `int64` directly, and it stays right on every system. ## Opaque pointers `malloc` returns C's `void *`: an address with no type. Rux spells it `*opaque`. You convert it with `as` to the type you meant, and check it, because C reports "no memory" by returning null: ```rux let capacity: size_t = 64; let buffer = malloc(capacity) as *var char8; if buffer == null { PrintLine("malloc failed"); return 1; } defer free(buffer as *var opaque); ``` The [`defer`](https://rux-lang.dev/docs/learn/defer) hands the memory back on every path out of `Main`. Handles such as C's `FILE *` go one step further: the package declares `FILE` as an empty struct, so you can hold a `*FILE` and pass it back to C, but there is nothing inside for Rux code to look at. ## Variadic functions `sprintf` writes formatted text into a buffer. The `...` at the end of its C declaration accepts any number of arguments of any type, and **nothing** checks them against the format string. You must pass each one at the type its `%` code reads: ```rux let written = sprintf(buffer, "%s has %d legs and weighs %.1f g".data, "spider".data, 8 as c_int, 0.5); ``` | Code | Reads | Passed as | | ------ | ------------------------------- | --------------- | | `%s` | the address of zero-ended bytes | `"spider".data` | | `%d` | a C `int` | `8 as c_int` | | `%.1f` | a 64-bit float, one decimal | `0.5` | `sprintf` is never told how big the buffer is, so the buffer must be big enough for any result — 64 bytes for 34 here. It returns how many bytes it wrote, and `buffer[..written as uint]` turns the pointer and that count back into a Rux slice that `PrintLine` can print. ## C structs `gmtime` turns a count of seconds since 1970 into a calendar date. It takes the address of a `time_t` — that is what `@stamp` gives it — and returns the address of a `tm` struct: ```rux var stamp: time_t = 1000000000; let calendar = gmtime(@stamp); if calendar == null { PrintLine("gmtime failed"); return 1; } ``` The package declares `tm` field for field in C's order, so Rux reads the struct exactly where C wrote it: `calendar.tm_hour` is C's `tm_hour`. Two of the fields keep C's own habits — `tm_year` counts from 1900 and `tm_mon` from zero — which is why the program adds 1900 and 1. The struct belongs to the C runtime, so the program reads it and does not free it. ## Failure is a value you must check None of these calls panics or returns a [fallible](https://rux-lang.dev/docs/learn/fallible). C reports failure with a sentinel value, and the caller has to check for it: | Function | On success | On failure | | --------- | --------------------- | ---------------- | | `malloc` | an address | `null` | | `sprintf` | the bytes it wrote | a negative count | | `gmtime` | the address of a `tm` | `null` | Skip a check and the program carries on with a null pointer or a negative length, and fails somewhere far from the cause. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Platform/CInterop){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // The C runtime is the library almost every system has, and the `C` package declares much of it // for you. Using it means meeting the four shapes every C interface is made of. // // C's own types. C's `int` is 32 bits, but Rux's `int` is 64, and C's `long` is 32 bits on // Windows and 64 elsewhere. So bindings are written in aliases named after C, such as `c_int`, // `size_t` and `time_t`, which stand for whichever Rux type matches on the target being built. // // Opaque pointers. `malloc` returns C's `void *`, which Rux spells `*opaque`: an address with no // type, which you convert to the type you meant. Handles such as C's `FILE *` go one step // further: `FILE` is declared as an empty struct, so you can hold one and pass it back, but // never look inside. // // C structs. `tm` is declared field for field in C's order, so Rux reads the struct exactly // where C wrote it. // // Variadic functions. The `...` in `sprintf` accepts any arguments, and nothing checks them // against the format. You must pass each one at the type its `%` code reads. // // None of these calls panics or returns a fallible: C reports failure with a sentinel value, // such as null or a negative count, and the caller has to check for it. import C::{ c_int, free, gmtime, malloc, size_t, sprintf, time_t }; import Io::PrintLine; func Main() -> int { // An opaque pointer becomes a typed one with `as`. Null means there was no memory. let capacity: size_t = 64; let buffer = malloc(capacity) as *var char8; if buffer == null { PrintLine("malloc failed"); return 1; } defer free(buffer as *var opaque); // `%s` reads the address of zero-terminated bytes, `%d` a C int and `%f` a 64-bit float. // sprintf is never told how big the buffer is, so it must be big enough for any result. let written = sprintf(buffer, "%s has %d legs and weighs %.1f g".data, "spider".data, 8 as c_int, 0.5); if written < 0 { PrintLine("sprintf failed"); return 1; } PrintLine("{} ({} bytes)", buffer[..written as uint], written); // gmtime fills a `tm` struct that the C runtime owns, and returns its address, or null. var stamp: time_t = 1000000000; let calendar = gmtime(@stamp); if calendar == null { PrintLine("gmtime failed"); return 1; } PrintLine("{} seconds after 1970 began was {}-{}-{}, {}:{}:{} UTC", stamp, calendar.tm_year + 1900, calendar.tm_mon + 1, calendar.tm_mday, calendar.tm_hour, calendar.tm_min, calendar.tm_sec); return 0; } ``` Besides `Io`, its `Rux.toml` lists `C` under `[Dependencies]`. ## Run it ```sh cd Examples/Platform/CInterop rux run ``` ```text spider has 8 legs and weighs 0.5 g (34 bytes) 1000000000 seconds after 1970 began was 2001-9-9, 1:46:40 UTC ``` ## Common mistakes ::mistake **Using the opaque pointer as it is.**:br Without the `as *var char8`, the buffer is still a `*var opaque`, and the `sprintf` call fails with: ```text error: argument 1 to 'sprintf' has type '*var opaque', but parameter 'buffer' requires '*char8' ``` :: ::mistake **Passing a Rux string as the format.**:br A C function takes the address of the bytes, not a Rux slice. Without `.data` the call fails with: ```text error: argument 2 to 'sprintf' has type 'char8[..]', but parameter 'format' requires '*char8' ``` :: ::mistake **An argument that does not match its `%` code.**:br After the format, the compiler checks nothing. Pass the integer `1` where `%.1f` expects a float, or `"spider"` without `.data` where `%s` expects an address, and the program still builds. What it prints is undefined — on Windows x86-64 the first gave `0.0` and the second a few bytes of garbage. :: ::mistake **Skipping the null check.**:br`malloc` and `gmtime` return null when they fail. Reading through a null pointer is never valid, and when it goes wrong it goes wrong a long way from the call that caused it. :: ## Try it yourself 1. Set `stamp` to `0`, then to `2000000000`. Predict both dates before you run. 2. Format `255 as c_int` and `48879 as c_int` with `"%x %X"` into the buffer and print the result. 3. Import `strlen` from `C` and check that `strlen(buffer)` agrees with `written`. 4. Print `calendar.tm_wday`, the day of the week counted from Sunday as 0. Which day was 9 September 2001? ## Learn more - [The C package](https://rux-lang.dev/docs/api/c) — every declaration it offers, with [C types](https://rux-lang.dev/docs/api/c/types), [`malloc`](https://rux-lang.dev/docs/api/c/stdlib#malloc), [`sprintf`](https://rux-lang.dev/docs/api/c/stdio#sprintf) and [`gmtime`](https://rux-lang.dev/docs/api/c/time#gmtime) - [Pointers and `extern`](https://rux-lang.dev/docs/lang/ffi/overview) in the Rux Reference - [Pointer slice](https://rux-lang.dev/docs/learn/pointer-slice) and [Layout](https://rux-lang.dev/docs/learn/layout) — the memory ideas this lesson leans on - [ABI](https://rux-lang.dev/docs/learn/abi) — the next lesson: names, calling conventions, and a Rux function that C calls back # ABI ::note **You'll need**: [Extern](https://rux-lang.dev/docs/learn/extern), [C interop](https://rux-lang.dev/docs/learn/c-interop), [Target](https://rux-lang.dev/docs/learn/target) :: ::tip **Runs on Windows, Linux, macOS and FreeBSD.**:br The program calls each system's C runtime, choosing the library's name with `when`. :: When compiled code calls compiled code, both sides must agree on things no source file shows: what the function is called inside the library, which processor registers carry the arguments, where the result comes back. That agreement is the **ABI**, the application binary interface. Between two Rux functions the compiler handles it silently, because it compiles both sides. Across the border to C it cannot — and two parts of the agreement can be written down in Rux. ## A Rux name for a C symbol The **symbol** is the name a library exports. It is normally the name you declare, but `#Link` takes a second argument when the two should differ, so a terse C name can be given a readable Rux one: ```rux // Rux name first, then the symbol the library exports. #Link(CRuntime, "abs") extern func AbsoluteValue(n: c_int) -> c_int; #Link(CRuntime, "strlen") extern func CStringLength(text: *char8) -> size_t; ``` The program calls `AbsoluteValue(-7)`; the library sees a call to `abs`. The first argument is the library, and `#Link` accepts only a constant declared in the same file, so the program chooses the C runtime's name itself: ```rux when #target.os { .FreeBSD => const CRuntime = "libc.so.7"; .Linux => const CRuntime = "libc.so.6"; .macOS => const CRuntime = "libSystem.B.dylib"; .Windows => const CRuntime = "ucrtbase.dll"; else => #Error("This lesson needs to know the name of this system's C runtime") } ``` ## Calling conventions The **calling convention** decides which registers and stack slots carry the arguments and the result. x86-64 has two in common use, and AArch64 one: | Convention | Used by | First integer arguments | Result | | ---------- | ---------------------------------- | -------------------------------------- | ------ | | Win64 | Windows on x86-64 | `rcx`, `rdx`, `r8`, `r9` | `rax` | | System V | Linux, macOS and FreeBSD on x86-64 | `rdi`, `rsi`, `rdx`, `rcx`, `r8`, `r9` | `rax` | | AAPCS64 | every system on AArch64 | `x0` to `x7` | `x0` | `#Abi` chooses one, with three names: `.Win64`, `.SysV`, and `.C`, which means "the C convention of whatever target is being built". Externs use `.C` unless told otherwise, which is why `AbsoluteValue` needed no `#Abi` — on Windows it is Win64, on Linux System V, and always what the C runtime expects. ## A Rux function that C calls `qsort` sorts an array of anything. It does not know how to compare your values, so you hand it a function that does, and `qsort` calls that function itself, again and again: ```rux #Abi(.C) func Descending(left: *opaque, right: *opaque) -> c_int { let a = *(left as *c_int); let b = *(right as *c_int); if a > b { return -1; } if a < b { return 1; } return 0; } ``` ```rux var values: c_int[5] = [3, 9, 1, 7, 5]; qsort(@values[0] as *var opaque, values.length, sizeof(c_int), Descending); ``` ```mermaid sequenceDiagram participant M as Main (Rux) participant Q as qsort (C runtime) participant D as Descending (Rux, C convention) M->>Q: `qsort(values, 5, 4, Descending)` loop for each pair it compares Q->>D: `Descending(left, right)` D-->>Q: negative, zero or positive end Q-->>M: values sorted in place ``` Now C is the caller, so `Descending` must receive its arguments where C puts them. Rux functions already use the C convention on every target Rux supports, so the program would work without the attribute. `#Abi(.C)` writes the promise down, so that it stays true — and so the next reader knows this function is called from outside Rux. The comparison gets two untyped addresses, because `qsort` works on any type. The function converts them back to `*c_int` and reads the numbers, then answers the way C expects: negative when `left` should come first, positive when `right` should, zero for a tie. Returning −1 for the larger value is what makes the order descending. ## When the two sides disagree If two Rux functions disagree about a convention, the compiler sorts it out. Code it did not compile is different. Change the attribute on `Descending` to `#Abi(.SysV)` and build on Windows: `qsort` puts the two addresses in `rcx` and `rdx`, `Descending` reads `rdi` and `rsi`, and compares whatever happened to be there. Nothing reports it. One run printed `sorted by C 1 3 5 9 7` — not descending, not ascending, just wrong. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Platform/Abi){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // When compiled code calls compiled code, both sides must agree on things no source file shows. // That agreement is the ABI, the application binary interface, and two parts of it can be // written in Rux. // // The symbol: the name the library exports. It is normally the Rux name, but `#Link` takes a // second argument when the two differ, so a terse C name can be given a readable Rux one. // // The calling convention: which registers and stack slots carry the arguments and the result. // `#Abi` chooses it. `.C` is the C convention of whatever target is being built. On x86-64 it // is `.Win64` on Windows and `.SysV` on Linux, macOS and FreeBSD, and those two can be named // directly. Externs use `.C` unless told otherwise. // // If two Rux functions disagree, the compiler sorts it out, since it compiles both sides. Code // it did not compile is different: if a declaration names the wrong convention, the arguments // arrive in the wrong registers. Nothing reports that. The function simply reads whatever // happened to be there. import Core::{ #Error, #target }; import C::{ c_int, qsort, size_t }; import Io::{ Print, PrintLine }; // `#Link` needs a constant from this file, so the C runtime's library name is chosen here. when #target.os { .FreeBSD => const CRuntime = "libc.so.7"; .Linux => const CRuntime = "libc.so.6"; .macOS => const CRuntime = "libSystem.B.dylib"; .Windows => const CRuntime = "ucrtbase.dll"; else => #Error("This lesson needs to know the name of this system's C runtime") } // Rux name first, then the symbol the library exports. #Link(CRuntime, "abs") extern func AbsoluteValue(n: c_int) -> c_int; #Link(CRuntime, "strlen") extern func CStringLength(text: *char8) -> size_t; // C's qsort calls this function itself, so the function must use the convention C expects. // Rux functions already use that convention on every target it supports. `#Abi(.C)` writes the // promise down, so it stays true. #Abi(.C) func Descending(left: *opaque, right: *opaque) -> c_int { let a = *(left as *c_int); let b = *(right as *c_int); if a > b { return -1; } if a < b { return 1; } return 0; } func Main() -> int { PrintLine("AbsoluteValue(-7) {}", AbsoluteValue(-7)); PrintLine("CStringLength(\"abi\") {}", CStringLength("abi".data)); var values: c_int[5] = [3, 9, 1, 7, 5]; qsort(@values[0] as *var opaque, values.length, sizeof(c_int), Descending); Print("sorted by C "); for value in values { Print(" {}", value); } PrintLine(); return 0; } ``` Besides `Io`, its `Rux.toml` lists `C` and `Core` under `[Dependencies]`. ## Run it ```sh cd Examples/Platform/Abi rux run ``` ```text AbsoluteValue(-7) 7 CStringLength("abi") 3 sorted by C 9 7 5 3 1 ``` ## Common mistakes ::mistake **Taking the library name from another package.**:br The `C` package has its own `CRuntime` constant, but `#Link` cannot use it: imported from `C`, it fails with: ```text error: '#Link' library name 'CRuntime' is not a compile-time constant ``` Declare the name in the file that uses it. :: ::mistake **Naming a convention that does not exist.**:br`#Abi(.Fast)` fails with: ```text error: unknown ABI '.Fast'; valid ABIs are: .C, .SysV, .Win64 ``` :: ::mistake **The wrong convention on a callback.**:br A function that C calls must use the convention C uses. Name the wrong one and nothing complains: the arguments arrive in registers the function never reads, and it computes with garbage. Prefer `.C` for anything handed to C. :: ## Try it yourself 1. Bind the C runtime's `toupper` under the Rux name `UpperCase`, taking and returning a `c_int`, and print `UpperCase('r' as c_int) as char8`. 2. Turn `Descending` into `Ascending`, so the program prints `1 3 5 7 9`. 3. On Windows, change `#Abi(.C)` on `Descending` to `#Abi(.SysV)` and run it a few times. On Linux or macOS, try `#Abi(.Win64)` instead. ## Learn more - [Abi](https://rux-lang.dev/docs/lang/attributes/abi) and [Link](https://rux-lang.dev/docs/lang/attributes/link) in the Rux Reference - [`abs`](https://rux-lang.dev/docs/api/c/stdlib#abs) and the rest of [the C package](https://rux-lang.dev/docs/api/c) - [C interop](https://rux-lang.dev/docs/learn/c-interop) — C's types, pointers and structs - [Callback](https://rux-lang.dev/docs/learn/callback) — passing a function as a value, entirely inside Rux - [Assembly](https://rux-lang.dev/docs/learn/asm) — the next lesson, where you write the convention's registers by hand # Assembly ::note **You'll need**: [ABI](https://rux-lang.dev/docs/learn/abi), [When](https://rux-lang.dev/docs/learn/when), [Target](https://rux-lang.dev/docs/learn/target), [Compile error](https://rux-lang.dev/docs/learn/compile-error) :: ::tip **x86-64 only.**:br The program runs on Windows, Linux and macOS on an x86-64 processor. Built for any other architecture, it stops with an `#Error`; the AArch64 version is the next lesson, [ARM assembly](https://rux-lang.dev/docs/learn/asm-arm). :: Every function ends up as machine code: a list of processor instructions. Normally the compiler writes that list for you. Once in a while you need to write it yourself — for an instruction the language has no way to express, or for exact control over what runs. An `asm func` is a function whose body is processor instructions instead of statements. The compiler emits them as written and does not look inside. That is the point, and also the danger. Nothing in the body is checked. Get a register wrong and the function returns the wrong answer without any warning. Read this lesson as a look under the floor, not as a way to write everyday code. ## A body made of instructions ```rux // Win64: the first two integers arrive in rcx and rdx. The result goes back in rax. #Abi(.Win64) asm func AddWin64(a: int64, b: int64) -> int64 { mov rax, rcx add rax, rdx ret } ``` The signature is ordinary Rux: two `int64` parameters, an `int64` result. But `a` and `b` are not names inside the body. The body works on **registers** — the processor's own handful of 64-bit storage slots, named `rax`, `rcx`, `rdx` and so on — and the [calling convention](https://rux-lang.dev/docs/learn/abi) decides which registers the arguments arrive in. Under Win64, `a` is in `rcx`, `b` is in `rdx`, and the caller will look for the result in `rax`. The instructions are written destination first: | Instruction | Means | | -------------- | ------------------------------------------- | | `mov rax, rcx` | copy `rcx` into `rax` — so `rax` is now `a` | | `add rax, rdx` | `rax = rax + rdx` — so `rax` is now `a + b` | | `ret` | return to the caller, which reads `rax` | Nothing is added around the body: no setup, no clean-up, not even the `ret`. Leave out the `ret` and the function still builds — and the processor carries on into whatever bytes happen to follow it. ## The body is written against a convention The convention decides which registers the arguments arrive in, so every body here carries an `#Abi` naming the one it was written for. Here is the same addition for System V, the convention of Linux, macOS and FreeBSD: ```rux // The same addition for System V, whose first two integers arrive in rdi and rsi. #Abi(.SysV) asm func AddSysV(a: int64, b: int64) -> int64 { mov rax, rdi add rax, rsi ret } ``` Pinned like that, the same body works on Windows, Linux and macOS alike: the compiler adapts each call to the function's convention, so on Windows it calls `AddSysV` with the arguments in `rdi` and `rsi`. That is why the program can call both versions and get 42 twice. Without an `#Abi`, an `asm func` uses the target's C convention — Win64 on Windows, System V elsewhere — and a body that reads `rcx` would read the wrong register as soon as it was built for Linux. ## A loop is a label and a jump There is no `while` in assembly. A loop is made of the pieces `while` is built from: a **label** to jump back to, a test, and a **conditional jump**: ```rux // A loop is a label and a conditional jump. These are the pieces `while` is built from. #Abi(.Win64) asm func SumTo(n: int64) -> int64 { xor rax, rax next: test rcx, rcx jle done add rax, rcx dec rcx jmp next done: ret } ``` `xor rax, rax` sets the total to zero. `test rcx, rcx` compares `n` with zero, and `jle done` leaves the loop when it is zero or less. Otherwise `n` is added to the total, `dec` takes one off `n`, and `jmp next` goes round again. Drawn out, it is the `while` loop you would have written in Rux: ```mermaid flowchart LR start(["`total = 0`
`xor rax, rax`"]) --> next{"`next:`
`n ≤ 0?`
`test`, `jle`"} next -- "no" --> body["`total += n`
`n -= 1`
`add`, `dec`"] body -- "`jmp next`" --> next next -- "yes" --> done(["`done:`
`return total`
`ret`"]) ``` ## One architecture, chosen with `when` Assembly belongs to one processor family. These instructions mean nothing to an ARM processor, so the functions sit inside a [`when`](https://rux-lang.dev/docs/learn/when) on the [target](https://rux-lang.dev/docs/learn/target)'s architecture: ```rux when #target.arch { .X86_64 => { // … the three asm functions … }, else => #Error("This lesson is x86-64 assembly; the AArch64 version is the AsmArm lesson") } ``` `rux build --target linux-aarch64` stops with that message. The assembler also knows only a chosen subset of x86-64 — enough for stubs, system calls and arithmetic, but not every instruction the processor has. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Platform/Asm){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // Every function ends up as machine code. Once in a while you need to write that code yourself, // for an instruction the language has no way to express, or for exact control over what runs. // // An `asm func` is a function whose body is processor instructions instead of statements. The // compiler emits them as written and does not look inside. That is the point, and also the // danger: nothing in the body is checked. Get a register wrong and the function returns the // wrong answer without any warning. // // The body is written against a calling convention, because the convention decides which // registers the arguments arrive in and where the result must go. So every x86-64 body here // carries an `#Abi` naming the one it was written for. Pinned like that, the same body works // on Windows, Linux and macOS alike, and the compiler adapts each call to it. // // Assembly also belongs to one architecture. This lesson is x86-64 only, and `when` stops the // build anywhere else. The AArch64 version is the next lesson. import Core::{ #Error, #target }; import Io::PrintLine; when #target.arch { .X86_64 => { // Win64: the first two integers arrive in rcx and rdx. The result goes back in rax. #Abi(.Win64) asm func AddWin64(a: int64, b: int64) -> int64 { mov rax, rcx add rax, rdx ret } // The same addition for System V, whose first two integers arrive in rdi and rsi. #Abi(.SysV) asm func AddSysV(a: int64, b: int64) -> int64 { mov rax, rdi add rax, rsi ret } // A loop is a label and a conditional jump. These are the pieces `while` is built from. #Abi(.Win64) asm func SumTo(n: int64) -> int64 { xor rax, rax next: test rcx, rcx jle done add rax, rcx dec rcx jmp next done: ret } }, else => #Error("This lesson is x86-64 assembly; the AArch64 version is the AsmArm lesson") } func Main() -> int { // Nothing at the call site says these functions are unusual. PrintLine("AddWin64(20, 22) {}", AddWin64(20, 22)); PrintLine("AddSysV(20, 22) {}", AddSysV(20, 22)); PrintLine("SumTo(10) {}", SumTo(10)); PrintLine("SumTo(100) {}", SumTo(100)); return 0; } ``` Besides `Io`, its `Rux.toml` lists `Core` under `[Dependencies]`. ## Run it ```sh cd Examples/Platform/Asm rux run ``` ```text AddWin64(20, 22) 42 AddSysV(20, 22) 42 SumTo(10) 55 SumTo(100) 5050 ``` ## Common mistakes ::mistake **A body written for one convention, pinned to another.**:br Mark `AddSysV` with `#Abi(.Win64)` and it still builds, but the caller now puts the arguments in `rcx` and `rdx` while the body adds `rdi` and `rsi`. On Windows the call then returned 0 instead of 42. Always pin the convention the body was written for. :: ::mistake **An instruction the assembler does not implement.**:br`popcnt rax, rdx` fails with: ```text error: instruction 'popcnt' is recognized for target 'windows-x86_64' but is not implemented by its assembler ``` Stick to the subset in the Reference's assembler page. :: ::mistake **Using a parameter name in the body.**:br The parameters are not names inside an `asm func`; the arguments exist only in their registers. `add rax, b` fails with: ```text error: unsupported operands for 'add' ``` Write `add rax, rdx`. :: ## Try it yourself 1. Write `Subtract(a: int64, b: int64) -> int64` for Win64, using `sub` in place of `add`. Check that `Subtract(50, 8)` is 42. 2. Write `Negate(n: int64) -> int64` with `neg`, which flips the sign of a register. 3. Write a System V version of `SumTo`, reading `n` from `rdi`, and call it on Windows. 4. Write `Max(a: int64, b: int64) -> int64` for Win64: copy `rcx` to `rax`, compare `rcx` with `rdx`, jump to the end with `jge` when `rcx` is already the larger, and otherwise copy `rdx` to `rax`. ## Learn more - [Assembler functions](https://rux-lang.dev/docs/lang/ffi/assembly) in the Rux Reference — operands, labels and the supported instructions - [Abi](https://rux-lang.dev/docs/lang/attributes/abi) — pinning the convention a body is written for - [ABI](https://rux-lang.dev/docs/learn/abi) — calling conventions from the Rux side - [ARM assembly](https://rux-lang.dev/docs/learn/asm-arm) — the same functions for AArch64 # ARM assembly ::note **You'll need**: [Assembly](https://rux-lang.dev/docs/learn/asm), [When](https://rux-lang.dev/docs/learn/when), [Target](https://rux-lang.dev/docs/learn/target) :: ::tip **The assembly runs only on AArch64.**:br That means an Apple silicon Mac, a Windows on ARM laptop or ARM Linux. The lesson still builds and runs on an x86-64 machine, but there `when` leaves the AArch64 functions out and the program prints a note instead. :: The [Assembly](https://rux-lang.dev/docs/learn/asm) lesson wrote its functions in x86-64 assembly, and that code means nothing to an ARM processor. AArch64 — the 64-bit ARM architecture in Apple silicon Macs, Windows on ARM laptops and most phones — has its own instructions, its own registers and its own rules. Code that should run on both needs one body per architecture, and `when #target.arch` picks the right one while compiling. ## A different processor | | x86-64 | AArch64 | | ------------------- | -------------------------------- | -------------------------------------- | | Registers | `rax`, `rcx`, `rdx`, … 16 in all | `x0` to `x30`, plus `xzr`, always zero | | Calling conventions | Win64 or System V, by system | AAPCS64, on every system | | Integer arguments | `rcx`, `rdx` … or `rdi`, `rsi` … | `x0`, `x1`, `x2` … | | Result | `rax` | `x0` | | Arithmetic | two operands: `add rax, rdx` | three: `add x0, x0, x1` | | A number | `0` | `#0` | The second row is good news. With a single calling convention on every operating system, there is no `#Abi` to choose: an AArch64 body works the same on macOS, Windows and Linux. Arguments arrive in `x0`, `x1` and onwards, and the result goes back in `x0` — so the first argument and the result share a register. ## Add, in three operands ```rux asm func Add(a: int64, b: int64) -> int64 { add x0, x0, x1 ret } ``` Most AArch64 instructions take a destination and two sources, so `add x0, x0, x1` means `x0 = x0 + x1`. The first argument is already in `x0`, where the result belongs, so one instruction does the whole job. ## The same loop ```rux // The same loop as the x86-64 lesson. xzr is a register that always reads as zero. asm func SumTo(n: int64) -> int64 { mov x1, x0 mov x0, xzr next: cmp x1, #0 b.le done add x0, x0, x1 sub x1, x1, #1 b next done: ret } ``` Because `x0` is both `n` and the result, the loop first moves `n` aside into `x1`, then zeroes the total by copying `xzr`. After that it is the x86-64 loop word for word: `cmp` and the conditional branch `b.le` (branch if less or equal) leave when `n` runs out, `b` jumps back unconditionally. Note the `#` on numbers written into an instruction: `#0`, `#1`. ## Choosing without a jump ```rux // csel picks one of two registers based on the comparison before it, with no jump. asm func Max(a: int64, b: int64) -> int64 { cmp x0, x1 csel x0, x0, x1, gt ret } ``` `csel` — conditional select — reads "`x0` becomes `x0` if the comparison said greater than, otherwise `x1`". The x86-64 version of `Max` needs a label and a jump; here it is one instruction with no branch at all. ## Building on either machine The three functions sit in an AArch64 arm, and every other architecture gets an empty one: ```rux when #target.arch { .AArch64 => { // … Add, SumTo and Max … }, else => {} } ``` A branch that is not taken is never checked or assembled, so on an x86-64 machine the functions simply do not exist. `Main` must not call them there, so it asks the same question again: ```rux when #target.arch == .AArch64 { PrintLine("Add(20, 22) {}", Add(20, 22)); PrintLine("SumTo(100) {}", SumTo(100)); PrintLine("Max(4, 9) {}", Max(4, 9)); } else { PrintLine("This lesson's assembly is for AArch64, and this machine is not one."); PrintLine("The AArch64 functions were left out of this build, so none of them ran."); } ``` ```mermaid flowchart LR src["`Main.rux`"] --> q{"target `arch`?"} q -- "`.AArch64`" --> a["`Add`, `SumTo` and `Max`
assembled and called"] q -- "anything else" --> x["no AArch64 functions;
`Main` prints a note"] ``` Unlike the Assembly lesson, nothing here stops the build: a program can carry assembly for one architecture and still be useful on another. You do not need an ARM machine to check the AArch64 code, either — `rux build --target linux-aarch64` assembles it on any machine and reports the instructions it cannot encode. Running the result is the only step that needs real AArch64 hardware. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Platform/AsmArm){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // The Asm lesson wrote its functions in x86-64 assembly, and that code means nothing to an ARM // processor. AArch64, the 64-bit ARM architecture in Apple silicon Macs, Windows on ARM laptops // and most phones, has its own instructions, its own registers and its own rules. Code that // should run on both needs one body per architecture. // // `when #target.arch` picks the body while compiling. A branch that is not taken is never // checked or assembled, so this file builds on an x86-64 machine too: the AArch64 functions // below are simply left out, and `Main` says so instead of calling them. // // Unlike x86-64, AArch64 has a single calling convention, AAPCS64, on every operating system, // so there is no `#Abi` to choose. Integer arguments arrive in x0, x1, x2 and so on, and the // result goes back in x0. The instructions are different too: most take a destination and two // sources, so `add x0, x0, x1` means x0 = x0 + x1. import Core::{ #target }; import Io::PrintLine; when #target.arch { .AArch64 => { asm func Add(a: int64, b: int64) -> int64 { add x0, x0, x1 ret } // The same loop as the x86-64 lesson. xzr is a register that always reads as zero. asm func SumTo(n: int64) -> int64 { mov x1, x0 mov x0, xzr next: cmp x1, #0 b.le done add x0, x0, x1 sub x1, x1, #1 b next done: ret } // csel picks one of two registers based on the comparison before it, with no jump. asm func Max(a: int64, b: int64) -> int64 { cmp x0, x1 csel x0, x0, x1, gt ret } }, else => {} } func Main() -> int { when #target.arch == .AArch64 { PrintLine("Add(20, 22) {}", Add(20, 22)); PrintLine("SumTo(100) {}", SumTo(100)); PrintLine("Max(4, 9) {}", Max(4, 9)); } else { PrintLine("This lesson's assembly is for AArch64, and this machine is not one."); PrintLine("The AArch64 functions were left out of this build, so none of them ran."); } return 0; } ``` Besides `Io`, its `Rux.toml` lists `Core` under `[Dependencies]`. ## Run it ```sh cd Examples/Platform/AsmArm rux run ``` On an AArch64 machine it prints the first block below. That output comes from the Examples repository and needs real AArch64 hardware to reproduce; on an x86-64 machine you will see the second block. ```text Add(20, 22) 42 SumTo(100) 5050 Max(4, 9) 9 ``` On an x86-64 machine: ```text This lesson's assembly is for AArch64, and this machine is not one. The AArch64 functions were left out of this build, so none of them ran. ``` ## Common mistakes ::mistake **Calling an AArch64 function outside the guard.**:br On an x86-64 machine the functions were never compiled, so a call to `Add` outside `when #target.arch == .AArch64` fails with: ```text error: name 'Add' is not defined in this scope ``` :: ::mistake **x86-64 habits in an AArch64 body.**:br The register names and operand counts are different. Built for AArch64, `mov rax, rcx` fails with: ```text error: 'mov' takes a register as operand 1, found the symbol 'rax' ``` `add rax, rdx` fails with: ```text error: 'add' takes 3 operands, found 2 ``` :: ::mistake **Trusting an x86-64 build to check the ARM code.**:br`rux run` on an x86-64 machine never looks inside the AArch64 branch, so a mistake there stays hidden. Build with `--target linux-aarch64` to have it assembled. :: ## Try it yourself 1. Run `rux build --target linux-aarch64`, then `rux build --target macos-aarch64`, and find the two programs under `Bin/Debug/`. 2. Add `Subtract(a: int64, b: int64) -> int64` with a single `sub`, and call it from the AArch64 branch of `Main`. Build for `linux-aarch64` to check it assembles. 3. Add `Min` next to `Max`, using `csel` with the condition `lt`. 4. If you have an Apple silicon Mac, a Windows on ARM laptop or an ARM Linux board, run the program there and compare its output with the first block above. ## Learn more - [Assembler functions](https://rux-lang.dev/docs/lang/ffi/assembly) in the Rux Reference - [Assembly](https://rux-lang.dev/docs/learn/asm) — the x86-64 version of these functions - [Target](https://rux-lang.dev/docs/learn/target) — `#target.arch` and building for another machine with `--target` - [`rux build`](https://rux-lang.dev/docs/cli/build) — the targets `--target` accepts # Part 25: Concurrency Every program so far has done one thing at a time. A computer can do several: its processor has a number of cores, and each can run its own line of execution — its own **thread** — at the same moment as the others. Splitting work across threads makes it finish sooner, and lets a program wait for one thing while it gets on with another. The difficulty is not starting threads but letting them share. Two threads that change the same memory at once can each undo the other's work, and the result changes from one run to the next. This part starts with threads themselves and then works through the standard tools that keep them out of each other's way: the `Thread` package starts and joins them, `Atomic` changes one value safely, and `Sync` provides the locks, channels and counters, with `Arc` from `Allocator` to share ownership. ## What you will learn - Starting a thread with `Spawn`, passing it a context, and collecting its result with `Join`. - What a data race is, and why output from several threads comes out in a different order every run. - Changing one shared value in indivisible steps with `Atomic`, the `CompareExchange` retry loop, and memory orders. - Keeping several values consistent under a `Mutex`, whose guard releases the lock for you. - Sharing ownership of one value between threads with `Arc`. - Passing values from thread to thread through a bounded `Channel`, and ending the stream with `Close`. - Waiting for a group of detached workers with `WaitGroup`, and the `Semaphore` and `Barrier` beside it. - One-time initialization with `Once`, and a `thread var` that every thread has its own copy of. - Letting many readers in at once with `RwLock`. ## Which tool when ```mermaid flowchart TD q{"Do the threads
share data?"} q -- "no: they pass it on" --> ch["`Channel`"] q -- "only read it" --> arc["`Arc`"] q -- "change it" --> one{"one number
or several values?"} one -- "one number" --> at["`Atomic`"] one -- "several" --> rw{"mostly read?"} rw -- "yes" --> rwl["`RwLock`"] rw -- "no" --> mx["`Mutex`"] ``` Two more questions are about time rather than data. To wait until a group of threads has finished, use a `WaitGroup` — or simply `Join` each one. To do something exactly once, whichever thread asks first, use a `Once`. ## Lessons | | Lesson | What you will learn | | ---- | ---------------------------------------------------------- | --------------------------------------------------------------------- | | 25.1 | [Thread](https://rux-lang.dev/docs/learn/thread) | start a thread, wait for its result, and ask how many can run at once | | 25.2 | [Atomic](https://rux-lang.dev/docs/learn/atomic) | count across threads without a lock | | 25.3 | [Mutex](https://rux-lang.dev/docs/learn/mutex) | guard shared data with a lock that only one thread holds at a time | | 25.4 | [Arc](https://rux-lang.dev/docs/learn/arc) | share ownership of one value between threads | | 25.5 | [Channel](https://rux-lang.dev/docs/learn/channel) | send values from one thread to another | | 25.6 | [Wait group](https://rux-lang.dev/docs/learn/wait-group) | wait until a group of threads has finished | | 25.7 | [Once](https://rux-lang.dev/docs/learn/once) | run initialization exactly once, whichever thread gets there first | | 25.8 | [Read-write lock](https://rux-lang.dev/docs/learn/rw-lock) | many readers at once, or one writer alone | ## Before you start Threads are given their work as a function and a context value, so this part leans on [Callback](https://rux-lang.dev/docs/learn/callback), [Struct](https://rux-lang.dev/docs/learn/struct) and [Move](https://rux-lang.dev/docs/learn/move). Starting a thread can fail, which brings back the outcomes of [Part 9: Errors](https://rux-lang.dev/docs/learn/errors). Locks hand out their value through a [pointer](https://rux-lang.dev/docs/learn/pointer) and release themselves through a [destructor](https://rux-lang.dev/docs/learn/destructor), and the Arc lesson builds on [Rc](https://rux-lang.dev/docs/learn/rc) from [Part 15: Memory](https://rux-lang.dev/docs/learn/memory). Each lesson's package is in the Examples repository's `Concurrency/` folder: ```sh cd Examples/Concurrency/Thread rux run ``` Threads run in an order nobody chooses, yet every program in this part prints the same lines on every run. Each one prints from a single thread, after the others have finished — a habit worth keeping. ## After this part [Part 26: Systems](https://rux-lang.dev/docs/learn/systems) turns outward, to the world around the program: environment variables, child processes, the command line, logs and the network. For the rules underneath, see [Atomics](https://rux-lang.dev/docs/lang/memory/atomics) and [Module variables](https://rux-lang.dev/docs/lang/bindings/module-variables) in the Rux Reference, and the [Thread](https://rux-lang.dev/docs/api/thread), [Atomic](https://rux-lang.dev/docs/api/atomic) and [Sync](https://rux-lang.dev/docs/api/sync) packages in the API reference. # Thread ::note **You'll need**: [Struct](https://rux-lang.dev/docs/learn/struct), [Variant match](https://rux-lang.dev/docs/learn/variant-match), [Outcome](https://rux-lang.dev/docs/learn/outcome), [Catch fallback](https://rux-lang.dev/docs/learn/catch-fallback), [Move](https://rux-lang.dev/docs/learn/move) :: Every program so far has done one thing at a time: each statement waits for the one before it. A modern processor has several cores, and all but one of them sat idle. A **thread** is a second line of execution inside the same program. It runs at the same time as `Main` — on another core when one is free — and shares the program's memory. Work that splits into independent pieces finishes sooner when each piece gets its own thread. This lesson sums the numbers from 1 to a million in four pieces at once, then collects the four answers: ```rux import Thread::{ AvailableParallelism, CurrentId, JoinHandle, Spawn, SpawnWith, ThreadError, ThreadOptions }; ``` ## Starting a thread Rux has no closures, so a thread cannot capture the variables around the line that started it. Instead, `Spawn` takes two things: a function, and one value to call it with — the **context**. Whatever the thread needs travels in that one value, usually a struct: ```rux struct Span { first: uint64; last: uint64; } func SumSpan(span: Span) -> uint64 { var total: uint64 = 0; for value in span.first..=span.last { total = total + value; } return total; } ``` `Spawn(SumSpan, Span { first: 1, last: 250000 })` starts a new thread that calls `SumSpan` on that span. The context [moves](https://rux-lang.dev/docs/learn/move) to the new thread, so `Main` keeps no copy of it. `Spawn` returns at once, without waiting for the sum, and the new thread runs on beside `Main`. | `Spawn(entry, context)` | Is | | ----------------------------- | -------------------------------------------------------- | | `entry: func(T) -> R` | the function the thread runs — one parameter, one result | | `context: T` | the value it is called with, moved to the new thread | | returns `JoinHandle` | the handle that collects the result later | | or fails with `ThreadError` | when the system could not start a thread | Starting a thread can fail — the system may have no memory or no thread to spare — so the handle comes back as an [outcome](https://rux-lang.dev/docs/learn/outcome). The program starts four threads and gives up with a [`catch`](https://rux-lang.dev/docs/learn/catch-fallback) if any one cannot start: ```rux var handles: JoinHandle[4] = [ Spawn(SumSpan, Span { first: 1, last: 250000 }) catch { else => return 1 }, Spawn(SumSpan, Span { first: 250001, last: 500000 }) catch { else => return 1 }, Spawn(SumSpan, Span { first: 500001, last: 750000 }) catch { else => return 1 }, Spawn(SumSpan, Span { first: 750001, last: 1000000 }) catch { else => return 1 } ]; ``` ## Waiting for the result `Join` waits for the thread to finish and hands back what its function returned. A thread that finished early has nothing to do but wait to be asked: ```rux for index in 0..4 { let part = handles[index].Join(); PrintLine("thread {} summed {:>12}", index + 1, part); total = total + part; } ``` ```mermaid flowchart LR m["`Main`"] -- "Spawn" --> t1["thread 1"] m -- "Spawn" --> t2["thread 2"] m -- "Spawn" --> t3["thread 3"] m -- "Spawn" --> t4["thread 4"] t1 -- "Join" --> s["total"] t2 -- "Join" --> s t3 -- "Join" --> s t4 -- "Join" --> s ``` Joining is more than waiting. Everything the thread wrote before it finished is visible to the thread that joined it, so after `Join` the result — and anything else the thread changed — can be read safely. A handle is joined once. After that `IsJoinable` is `false`, and a second `Join` is a program error. ## Printing in order Notice that the threads print nothing. Threads run in whatever order the system schedules them, and that order changes from run to run. Had each thread printed its own line, the four lines would come out shuffled differently each time. Printing only from `Main`, after each `Join`, keeps the output in one fixed order however the threads ran. Every lesson in this part follows that rule. ## Options and identity `SpawnWith` takes a `ThreadOptions` first. Its one setting is the stack size, for a thread that needs more room than the system's default — or, as here, less: ```rux let options = ThreadOptions().WithStackSize(65536u); match SpawnWith(options, Identify, 0u8) { ``` The `Identify` thread returns `CurrentId()`, the system's number for the thread it runs on, and `Main` compares it with its own. No two live threads share an identifier. The failure arm names the reason with a `match` on `ThreadError`: | `ThreadError` | Means | | ------------------ | ----------------------------------------------------- | | `Exhausted` | the system had no memory, or no thread, to spare | | `InvalidStackSize` | the system refused the stack size, usually too small | | `Failed` | the system reported a failure with no name of its own | `Identify` takes a `uint8` it never uses: every thread function takes exactly one parameter, so a thread that needs nothing is given a placeholder. ## Letting a thread go `Detach` gives up the handle: the thread runs on, nobody can join it, and its result is thrown away when it finishes. Simply dropping a handle does the same. Use it for work whose result nobody needs — and remember that when `Main` returns the program ends, taking any detached thread still running with it. When something must wait for detached threads, a [wait group](https://rux-lang.dev/docs/learn/wait-group) is the tool. ## How many at once `AvailableParallelism()` says how many threads can truly run at the same time: the number of processors online, and never zero. Starting more threads than that is allowed — they take turns — but beyond it, the work no longer finishes any sooner. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Concurrency/Thread){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // A thread is a second line of execution inside the same program: it runs at the same time as // `Main`, on another processor when one is free, and shares the program's memory. Work that splits // into independent pieces finishes sooner when each piece gets its own thread. // // Rux has no closures, so a thread cannot capture the variables around it. `Spawn(entry, context)` // takes a function and one value to call it with; the value moves to the new thread, and the // function's result waits there until someone collects it. Starting a thread can fail when the // system has none to spare, so `Spawn` returns `JoinHandle ! ThreadError`. // // `Join` on the handle waits for the thread to finish and hands back its result. Printing only // after joining keeps the output in a fixed order, however the threads were scheduled. import Io::PrintLine; import Thread::{ AvailableParallelism, CurrentId, JoinHandle, Spawn, SpawnWith, ThreadError, ThreadOptions }; // Everything a thread needs travels in its one context value. struct Span { first: uint64; last: uint64; } // The function each thread runs: it takes the context and returns a result. func SumSpan(span: Span) -> uint64 { var total: uint64 = 0; for value in span.first..=span.last { total = total + value; } return total; } func Identify(unused: uint8) -> uint64 { return CurrentId(); } func Describe(error: ThreadError) -> char8[..] { return match error { .Exhausted => "the system has no thread to spare", .InvalidStackSize => "the stack size was refused", .Failed => "the system could not start it" }; } func Main() -> int { // Four threads, each summing a quarter of 1..=1000000. They start at once and run side by side. // `Spawn` returns an outcome rather than a handle, so the failure is dealt with first; calling // `Join` on the outcome itself is refused: // // error: type 'JoinHandle ! ThreadError' has no field 'Join' var handles: JoinHandle[4] = [ Spawn(SumSpan, Span { first: 1, last: 250000 }) catch { else => return 1 }, Spawn(SumSpan, Span { first: 250001, last: 500000 }) catch { else => return 1 }, Spawn(SumSpan, Span { first: 500001, last: 750000 }) catch { else => return 1 }, Spawn(SumSpan, Span { first: 750001, last: 1000000 }) catch { else => return 1 } ]; // `Join` waits for each thread in turn. A thread that finished early simply waits to be asked. var total: uint64 = 0; for index in 0..4 { let part = handles[index].Join(); PrintLine("thread {} summed {:>12}", index + 1, part); total = total + part; } PrintLine("total {:>12}", total); PrintLine("joinable after join {}", handles[0].IsJoinable()); // `SpawnWith` takes options too: here, a 64 KiB stack instead of the system's default. Every // thread has its own identifier, and this one hands its own back to compare. let options = ThreadOptions().WithStackSize(65536u); match SpawnWith(options, Identify, 0u8) { .Success(handle) => { // A handle is moved, never copied, so `var other = handle;` is refused: // // error: move-only value 'handle' requires an explicit '<-' in initialization var other <- handle; PrintLine("a different id {}", other.Join() != CurrentId()); }, .Failure(error) => PrintLine("no thread: {}", Describe(error)) } // A handle that is detached, or simply dropped, lets its thread run on unwatched. Nothing can // join it any more, so nothing can see its result. var background = Spawn(SumSpan, Span { first: 1, last: 10 }) catch { else => return 1 }; background.Detach(); PrintLine("joinable after detach {}", background.IsJoinable()); // How many threads can usefully run at once: the processors online, never zero. PrintLine("processors {}", AvailableParallelism()); return 0; } ``` Besides `Io`, its `Rux.toml` lists `Thread` under `[Dependencies]`. ## Run it ```sh cd Examples/Concurrency/Thread rux run ``` ```text thread 1 summed 31250125000 thread 2 summed 93750125000 thread 3 summed 156250125000 thread 4 summed 218750125000 total 500000500000 joinable after join false a different id true joinable after detach false processors 16 ``` Every line is the same on each run except the last, which is the number of processors on the machine running it. ## Common mistakes ::mistake **Using the outcome as a handle.**:br`var handle = Spawn(SumSpan, span);` followed by `handle.Join()` fails with: ```text error: type 'JoinHandle ! ThreadError' has no field 'Join' ``` Deal with the failure first, with `catch` or a `match`. :: ::mistake **A thread function with two parameters.**:br`Spawn(Add, 12u64)` with `func Add(a: uint64, b: uint64) -> uint64` fails with: ```text error: argument 1 to 'Spawn' has type 'func(uint64, uint64) -> uint64', but parameter 'entry' requires 'func(T) -> R' ``` A thread function takes exactly one value. Gather what it needs into a struct, as `Span` does. :: ::mistake **Joining twice.**:br A second `Join` on the same handle stops the program: ```text Panic: the thread was already joined or detached ``` Keep the result of the first `Join` instead. :: ::note **A thread that returns nothing.**:br A thread function that returns nothing may leave its result type out, `func Work(value: uint64) {}`, or write `-> ()`; either way `Join` hands nothing back. The two are different types, though, so the handles of one and the other cannot share an array. :: ::mistake **Printing from several threads.**:br Lines printed by different threads come out in a different order on every run. Return the results and print them from one thread, after `Join`. :: ## Try it yourself 1. Split the sum across eight threads instead of four. Does the total change? 2. Make `SumSpan` return a struct holding both the sum and how many numbers it added, and print both. 3. Time the whole sum with a `Stopwatch` from [Stopwatch](https://rux-lang.dev/docs/learn/stopwatch), once with four threads and once with a single thread summing all of it. ## Learn more - [Thread](https://rux-lang.dev/docs/api/thread) — the package in the API reference - [Function types](https://rux-lang.dev/docs/lang/functions/function-types) — passing a function as a value, as `Spawn` takes it - [Copy and move](https://rux-lang.dev/docs/lang/ownership/copy-and-move) — why a handle moves and is never copied - [Callback](https://rux-lang.dev/docs/learn/callback) — functions passed as values, the same idea on one thread - [Atomic](https://rux-lang.dev/docs/learn/atomic) — the next lesson: threads that change the same value # Atomic ::note **You'll need**: [Generic type](https://rux-lang.dev/docs/learn/generic-type), [Pointer](https://rux-lang.dev/docs/learn/pointer), [Thread](https://rux-lang.dev/docs/learn/thread) :: In [Thread](https://rux-lang.dev/docs/learn/thread) every thread kept to its own numbers and handed back a result. Often threads must change the *same* value — a count of requests served, the best answer found so far. That is where the trouble starts. ## The race `total = total + 1` looks like one step. The processor does it in three: read `total`, add one, write it back. Run it on two threads at once and nothing stops the steps from interleaving: | Step | Thread A | Thread B | `total` | | ---- | --------- | --------- | ------- | | 1 | reads 41 | | 41 | | 2 | | reads 41 | 41 | | 3 | writes 42 | | 42 | | 4 | | writes 42 | 42 | Two increments, and `total` went up by one. This is a **data race**: two threads touch the same memory at once and at least one of them writes. The result depends on how the threads happened to be scheduled, so a program with a race can pass every test and then lose a count in production. Rux does not check memory that threads share through a pointer — keeping them apart is your job, and this part's tools are how. ## An atomic value An `Atomic` holds one integer, `bool` or pointer and changes it only in **indivisible** steps. `FetchAdd` reads, adds and writes as one indivisible step — a single instruction on most processors — so no other thread can slip in between, and no increment is ever lost. No lock is taken: the hardware keeps the threads apart. ```rux import Atomic::Atomic; import Core::MemoryOrder; ``` The program's four workers share two atomics, kept together in a struct that lives in `Main`. Each worker is given its address as a read-only [pointer](https://rux-lang.dev/docs/learn/pointer), `*Shared`: ```rux struct Shared { checked: Atomic; longest: Atomic; } struct Span { first: uint64; last: uint64; shared: *Shared; } ``` A read-only pointer is enough, because every method of `Atomic` takes the atomic by shared reference — changing it from many places at once is the whole point. What makes the pointer safe is that `Main` joins every worker before `shared` goes away. The [Arc](https://rux-lang.dev/docs/learn/arc) lesson shows a way to share that does not depend on it. | Method | Does, as one step | Returns | | ------------------------------------ | ------------------------------------------- | ------------------ | | `Load()` | reads the value | the value | | `Store(value)` | writes `value` | nothing | | `Exchange(value)` | writes `value` | the value replaced | | `CompareExchange(expected, desired)` | writes `desired` if the value is `expected` | `T ! T`, see below | | `FetchAdd(n)`, `FetchSub(n)` | adds or subtracts, wrapping on overflow | the value before | | `FetchAnd`, `FetchOr`, `FetchXor` | combines bitwise | the value before | ## Counting Each worker walks its quarter of 1 to 100000 and counts every number it looks at in the one shared counter: ```rux span.shared.checked.FetchAddWith(1, MemoryOrder::Relaxed); ``` `FetchAddWith` is `FetchAdd` with a memory order, which [comes below](https://rux-lang.dev/#memory-orders). Four threads add to `checked` a hundred thousand times between them, and after the joins it reads exactly 100000. Swap the atomic for a plain `uint64` changed through a pointer and the total could come out short, by a different amount from run to run. ## Compare and exchange The second atomic keeps the longest Collatz chain any worker has found — the most steps any number takes to reach 1 when an even number is halved and an odd one tripled plus one. There is no `FetchMax`, and a `Load` followed by a `Store` would be the race all over again: another thread could store a longer chain between the two. `CompareExchange(expected, desired)` closes that gap. It writes `desired` only if the value is still `expected`, and reports which happened: ```rux func RaiseTo(longest: &Atomic, candidate: uint64) { var seen = longest.Load(); while candidate > seen { match longest.CompareExchange(seen, candidate) { .Success(_) => return, .Failure(found) => seen = found } } } ``` It returns `T ! T`. Success carries the value it replaced, which was `expected`. Failure means another thread got there first, and carries the value really there now — so the loop tries again from that, and stops as soon as the candidate is no longer larger. This **retry loop** is how every atomic update that is not built in gets written. ```mermaid flowchart TD a["`seen = Load()`"] --> b{"candidate larger
than seen?"} b -- "no" --> done["done"] b -- "yes" --> c{"`CompareExchange(seen, candidate)`"} c -- "Success" --> done c -- "Failure(found)" --> d["`seen = found`"] d --> b ``` `CompareExchange` never fails spuriously: a failure always means the value was different. ## Memory orders An atomic operation also decides what the *other* memory around it looks like to other threads. Compilers and processors reorder ordinary reads and writes when one thread could not tell the difference, and another thread can. A **memory order** says how much reordering is allowed across the operation. The plain methods — `Load`, `Store`, `FetchAdd` and the rest — use `SequentiallyConsistent`, the strongest order: every thread agrees on one order of all such operations. It is never wrong, and it is the right default. `Load`, `Store`, `FetchAdd`, `FetchSub` and `CompareExchange` also have a `With` form that takes a weaker `MemoryOrder`, for code that has worked out it is enough: | Order | Use it for | | ------------------------ | -------------------------------------------------------------------------- | | `Relaxed` | a count nothing else depends on — only the operation itself is indivisible | | `Release` | a store that publishes the writes made before it | | `Acquire` | a load that sees everything published by the matching release | | `AcquireRelease` | a read-modify-write that does both | | `SequentiallyConsistent` | everything else, and whenever in doubt | The counter here is `Relaxed`: nothing is read on the strength of it, and the final value is read after the joins, which make every write visible anyway. Release and acquire come in pairs, to hand ordinary data from one thread to another: ```rux struct Mailbox { value: uint64; ready: Atomic; } func Deliver(box: *var Mailbox) -> () { box.value = 42; box.ready.StoreWith(true, MemoryOrder::Release); } ``` A thread that sees `ready` with an acquiring load — `box.ready.LoadWith(MemoryOrder::Acquire)` — is guaranteed to see `value` as 42. With `Relaxed` on both sides it could see `true` and still read the old `value`. An order an operation cannot have is strengthened to the nearest one it can, so `LoadWith(MemoryOrder::Release)` loads with `Acquire`. ## The rest After the joins, `Main` has the atomics to itself and tries the remaining operations: `Store` replaces the value, `Exchange` replaces it and hands back the old one, and a `CompareExchange` that expects the wrong value changes nothing and fails with what it found. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Concurrency/Atomic){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // `total = total + 1` looks like one step, but the processor does it in three: read `total`, // add one, write it back. When two threads run it at once, both can read the same old value and // both write the same new one, and one of the two increments is lost. That is a data race, and // the result depends on how the threads happened to be scheduled. // // An `Atomic` holds one integer, `bool` or pointer and changes it only in indivisible steps. // `FetchAdd` reads, adds and writes as one indivisible step, so no other thread can slip in // between, and no increment is ever lost. No lock is taken: the hardware keeps the threads apart. // // `CompareExchange(expected, desired)` is the building block for everything else: it writes // `desired` only if the value is still `expected`. It succeeds with the old value, or fails with // the value it found instead, and a loop tries again from there. import Atomic::Atomic; import Core::MemoryOrder; import Io::PrintLine; import Thread::{ JoinHandle, Spawn }; // The two atomics every worker shares. They live in `Main`, which outlives every worker. An atomic // holds an integer, a `bool` or a pointer and nothing else; `FetchAdd` on an `Atomic` is // refused: // // error: 'AtomicFetchAdd' cannot act on type 'float64' // note: its type argument must be an integer of 8 to 64 bits struct Shared { checked: Atomic; longest: Atomic; } // One worker's share of the numbers, and the address of what it shares with the others. struct Span { first: uint64; last: uint64; shared: *Shared; } // How many steps of the Collatz rule take `value` down to 1: halve it when even, otherwise // triple it and add one. func Steps(value: uint64) -> uint64 { var current = value; var steps: uint64 = 0; while current != 1 { current = current % 2 == 0 ? current / 2 : current * 3 + 1; steps = steps + 1; } return steps; } // Raises `longest` to `candidate` if that is larger. Another thread may change it between the // read and the write, so the exchange is retried from whatever value it actually found. func RaiseTo(longest: &Atomic, candidate: uint64) { var seen = longest.Load(); while candidate > seen { match longest.CompareExchange(seen, candidate) { .Success(_) => return, .Failure(found) => seen = found } } } // Each worker counts every number in its span and offers each chain length as a new longest. func Walk(span: Span) -> () { for value in span.first..=span.last { // A plain count that nothing else depends on, so the cheapest order is enough. span.shared.checked.FetchAddWith(1, MemoryOrder::Relaxed); RaiseTo(span.shared.longest, Steps(value)); } } func Main() -> int { let shared = Shared { checked: Atomic(0), longest: Atomic(0) }; // Four threads explore a quarter of 1..=100000 each, all updating the same two atomics. var workers: JoinHandle<()>[4] = [ Spawn(Walk, Span { first: 1, last: 25000, shared: @shared }) catch { else => return 1 }, Spawn(Walk, Span { first: 25001, last: 50000, shared: @shared }) catch { else => return 1 }, Spawn(Walk, Span { first: 50001, last: 75000, shared: @shared }) catch { else => return 1 }, Spawn(Walk, Span { first: 75001, last: 100000, shared: @shared }) catch { else => return 1 } ]; for index in 0..4 { workers[index].Join(); } // Every worker has finished, so these are the final values: not one update was lost. PrintLine("numbers checked {}", shared.checked.Load()); PrintLine("longest chain {} steps", shared.longest.Load()); // `Store` replaces the value; `Exchange` replaces it and hands back what was there. shared.checked.Store(10); let before = shared.checked.Exchange(20); PrintLine("exchange {} -> {}", before, shared.checked.Load()); // A compare-exchange that expects the wrong value changes nothing and reports what it found. match shared.checked.CompareExchange(10, 30) { .Success(previous) => PrintLine("replaced {}", previous), .Failure(found) => PrintLine("not replaced found {}", found) } return 0; } ``` Besides `Io`, its `Rux.toml` lists `Atomic`, `Core` and `Thread` under `[Dependencies]`. ## Run it ```sh cd Examples/Concurrency/Atomic rux run ``` ```text numbers checked 100000 longest chain 350 steps exchange 10 -> 20 not replaced found 20 ``` ## Common mistakes ::mistake **Giving each thread a copy.**:br A thread function that takes the atomic itself, `func Work(counter: Atomic) -> ()`, compiles — and each thread gets its own copy. Copying an `Atomic` copies its current value into a new, unrelated one, so `Main`'s counter is never touched and still reads `0` after the joins. Share the one atomic through a pointer, or an [Arc](https://rux-lang.dev/docs/learn/arc). :: ::mistake **A load and then a store.**:br`counter.Store(counter.Load() + 1)` is two atomic steps with a gap between them, and is the race from the top of this page again. Use the one-step `FetchAdd`, or a `CompareExchange` loop for an update that has no method of its own. :: ::mistake **An atomic of the wrong type.**:br An `Atomic` holds an integer of 8 to 64 bits, a `bool` or a pointer. `FetchAdd` on an `Atomic` fails with: ```text error: 'AtomicFetchAdd' cannot act on type 'float64' note: its type argument must be an integer of 8 to 64 bits ``` :: ::mistake **A pointer that outlives the atomic.**:br The workers reach `shared` through a raw pointer, which the compiler does not follow. If `Main` returned before joining them, they would go on writing to memory that is no longer `shared`. Join every thread that holds the address before the atomic goes out of scope. :: ## Try it yourself 1. Count the even numbers too: add a third atomic to `Shared` and `FetchAdd` to it from `Walk`. 2. Write `LowerTo`, the mirror image of `RaiseTo`, and keep the shortest chain among the numbers above 1. 3. Make `RaiseTo` record *which* number has the longest chain as well: pack both into one `uint64`, the steps in the upper 32 bits and the number in the lower, so one `CompareExchange` updates both. ## Learn more - [Atomic](https://rux-lang.dev/docs/api/atomic) — the package in the API reference - [Atomics](https://rux-lang.dev/docs/lang/memory/atomics) — the `Core` operations underneath, and every memory order in detail - [Pointer](https://rux-lang.dev/docs/learn/pointer) — the addresses the workers share - [Mutex](https://rux-lang.dev/docs/learn/mutex) — the next lesson: when more than one value must change at once # Mutex ::note **You'll need**: [Destructor](https://rux-lang.dev/docs/learn/destructor), [Pointer](https://rux-lang.dev/docs/learn/pointer), [Thread](https://rux-lang.dev/docs/learn/thread), [Atomic](https://rux-lang.dev/docs/learn/atomic) :: An [atomic](https://rux-lang.dev/docs/learn/atomic) keeps one number safe. Most shared data is more than one number, and its parts must change together. Money moved between two accounts leaves one and arrives in the other, and no thread may ever see it in neither: two atomics, each changed safely on its own, still leave a moment between the two changes. A **lock** closes that moment. While one thread holds it, no other thread can take it, so the whole group of changes made under the lock looks to everyone else like a single step. A `Mutex` — short for *mutual exclusion* — is a lock with the value it guards inside: ```rux import Sync::Mutex; ``` ## Locking `Lock` waits until no other thread holds the lock, takes it, and returns a `MutexGuard`. The guard is the only way to reach the value: its `Get` returns a `*var T`, the value's address, through which the fields are read and written as through any [pointer](https://rux-lang.dev/docs/learn/pointer): ```rux func Transfer(accounts: &Mutex, amount: int64) { let guard = accounts.Lock(); let book = guard.Get(); book.checking = book.checking - amount; book.savings = book.savings + amount; book.transfers = book.transfers + 1; } ``` There is no `Unlock` call at the end. The guard's [destructor](https://rux-lang.dev/docs/learn/destructor) releases the lock when the guard is dropped — here, as `Transfer` returns — so a lock cannot be forgotten, not even on an early `return`. ```mermaid flowchart LR a["`Lock()`"] --> w{"held by
another thread?"} w -- "yes" --> wait["sleep until
it is released"] --> w w -- "no" --> g["a `MutexGuard`:
read and write"] g --> d["guard dropped:
lock released"] ``` A thread waiting for the lock sleeps rather than spinning, so it costs nothing while it waits. Taking a lock nobody holds is one atomic instruction. ## One value, many handles A `Mutex` is a **handle**. The value and its lock live in storage that every handle to them shares, and `Clone` makes another handle to the same storage. Each thread is given its own: ```rux var tellers: JoinHandle<()>[4] = [ Spawn(Work, Teller { amount: 3, accounts: accounts.Clone() }) catch { else => return 1 }, Spawn(Work, Teller { amount: 2, accounts: accounts.Clone() }) catch { else => return 1 }, Spawn(Work, Teller { amount: -1, accounts: accounts.Clone() }) catch { else => return 1 }, Spawn(Work, Teller { amount: -2, accounts: accounts.Clone() }) catch { else => return 1 } ]; ``` | Type | Is | | --------------- | ---------------------------------------------------------------- | | `Mutex` | a handle to the value and its lock; `Clone` makes another | | `MutexGuard` | the lock, held; `Get` reaches the value; dropping it releases it | The value is destroyed when the last handle and the last guard are gone, so it does not matter which thread finishes last. Unlike the pointer in [Atomic](https://rux-lang.dev/docs/learn/atomic), no handle can outlive the value. Four tellers make 4000 transfers between them, moving money in both directions, and `Report` — which takes the lock too — shows the total still at 10000. Every thread saw either all of a transfer or none of it. ## Without waiting `TryLock` takes the lock only if nobody holds it, and returns `MutexGuard?` — none rather than waiting. A guard can also give the lock back early with `Unlock`, before it is dropped: ```rux var held = accounts.Lock(); PrintLine("try while held: {}", accounts.TryLock() != none); held.Unlock(); PrintLine("try after unlock: {}", accounts.TryLock() != none); ``` The first `TryLock` fails although it is the same thread that holds the lock. A `Mutex` is not **reentrant**: it does not remember who holds it, and a thread that calls `Lock` again while holding it waits for itself forever. ## Holding a lock briefly While one thread holds the lock every other thread that wants it is stopped, so do as little as possible under it: change the value and let go. Work out what to write first, and print, sleep or wait for anything else after the guard is gone. Two more tools live beside `Mutex` in the `Sync` package. `Lock` is a bare lock that guards no value — whatever the code between its `Acquire` and `Release` touches. `Condition` lets a thread holding a guard sleep until another thread signals that something it waits for has changed, releasing the lock while it sleeps. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Concurrency/Mutex){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // An atomic keeps one number safe. Most shared data is more than one number, and its parts must // change together: money moved between two accounts leaves one and arrives in the other, and // nobody may see it in neither. A lock makes a group of changes look like one. // // A `Mutex` holds a value that only one thread at a time may reach. `Lock` waits until no // other thread holds the lock, takes it, and returns a `MutexGuard`. The guard is the only way // to the value, and when it is dropped, at the end of its block, the lock is released for the // next thread. Forgetting to unlock is therefore impossible. // // A `Mutex` is a handle: the value lives in storage that every handle shares. `Clone` makes // another handle for another thread, and the value is destroyed when the last handle is gone. import Io::PrintLine; import Sync::Mutex; import Thread::{ JoinHandle, Spawn }; // Two balances that must always add up to the same total. struct Accounts { checking: int64; savings: int64; transfers: uint64; } // A teller moves `amount` from checking to savings, a thousand times over. struct Teller { amount: int64; accounts: Mutex; } func Transfer(accounts: &Mutex, amount: int64) { // The guard holds the lock from here to the end of the function. While it does, no other // thread can see the money half moved. let guard = accounts.Lock(); let book = guard.Get(); book.checking = book.checking - amount; book.savings = book.savings + amount; book.transfers = book.transfers + 1; } func Work(teller: Teller) -> () { for round in 0..1000 { Transfer(teller.accounts, teller.amount); } } func Report(accounts: &Mutex) { let guard = accounts.Lock(); let book = guard.Get(); PrintLine("checking {} savings {} total {} transfers {}", book.checking, book.savings, book.checking + book.savings, book.transfers); } func Main() -> int { let accounts = Mutex(Accounts { checking: 10000, savings: 0, transfers: 0 }); Report(accounts); // Each teller gets its own handle to the same accounts. A negative amount moves money back. // A handle is never copied, so `accounts: accounts` is refused; `Clone` is the way to share: // // error: move-only value 'accounts' requires an explicit '<-' in aggregate var tellers: JoinHandle<()>[4] = [ Spawn(Work, Teller { amount: 3, accounts: accounts.Clone() }) catch { else => return 1 }, Spawn(Work, Teller { amount: 2, accounts: accounts.Clone() }) catch { else => return 1 }, Spawn(Work, Teller { amount: -1, accounts: accounts.Clone() }) catch { else => return 1 }, Spawn(Work, Teller { amount: -2, accounts: accounts.Clone() }) catch { else => return 1 } ]; for index in 0..4 { tellers[index].Join(); } Report(accounts); // `TryLock` never waits: it returns none while the lock is held, even by this same thread. var held = accounts.Lock(); PrintLine("try while held: {}", accounts.TryLock() != none); held.Unlock(); PrintLine("try after unlock: {}", accounts.TryLock() != none); return 0; } ``` Besides `Io`, its `Rux.toml` lists `Sync` and `Thread` under `[Dependencies]`. ## Run it ```sh cd Examples/Concurrency/Mutex rux run ``` ```text checking 10000 savings 0 total 10000 transfers 0 checking 8000 savings 2000 total 10000 transfers 4000 try while held: false try after unlock: true ``` ## Common mistakes ::mistake **Copying the handle.**:br`Teller { amount: 3, accounts: accounts }` fails with: ```text error: move-only value 'accounts' requires an explicit '<-' in aggregate ``` Moving the handle with `<-` would leave `Main` without one. `Clone` gives the teller a handle of its own. :: ::mistake **Assigning to the address.**:br`Get` returns a pointer, not the value. `guard.Get() = 0;` on a `Mutex` fails with: ```text error: operator '=' requires an assignable target, but its left operand has type '*var int64' ``` Write through the pointer: `*guard.Get() = 0;`, or `book.checking = 0;` for a field. :: ::mistake **Locking twice on one thread.**:br`Lock` while the same thread already holds a guard on that mutex never returns: the thread waits for a lock only it can release. Pass the guard, or the value it reaches, to whatever needs it instead of locking again. :: ::mistake **Keeping the address after the guard.**:br The pointer from `Get` is valid only while the guard holds the lock. Kept past that — stored in a variable that outlives the guard — it reaches the value with no lock at all, and the compiler does not notice. Copy out what you need while the guard lives. :: ## Try it yourself 1. Add a fifth teller moving 4 at a time. What should the balances be? 2. Add a `largest: int64` field to `Accounts`, and have `Transfer` record the largest amount moved. 3. Make `Report` use `TryLock` and print `busy` instead of waiting when it fails. Call it while `held` is held. ## Learn more - [Sync](https://rux-lang.dev/docs/api/sync) — the package in the API reference, with `Lock` and `Condition` - [Destructors](https://rux-lang.dev/docs/lang/ownership/destructors) — how a guard releases its lock when dropped - [Atomic](https://rux-lang.dev/docs/learn/atomic) — one value changed without a lock - [Read-write lock](https://rux-lang.dev/docs/learn/rw-lock) — a lock that lets many readers in at once # Arc ::note **You'll need**: [Rc](https://rux-lang.dev/docs/learn/rc), [Thread](https://rux-lang.dev/docs/learn/thread), [Atomic](https://rux-lang.dev/docs/learn/atomic) :: A thread can outlive the line that started it, so whatever it is given must last as long as the thread does. So far there were two ways to arrange that, and both have a catch: - **Moving** a value in, as [Thread](https://rux-lang.dev/docs/learn/thread) did, gives it to one thread. Several threads that need the same large value would each need their own copy. - **A pointer** to a local, as [Atomic](https://rux-lang.dev/docs/learn/atomic) did, shares one value — but only for as long as the local lives, which the compiler does not check. An `Arc` — an *atomically reference-counted* handle — removes the catch. It is the [`Rc`](https://rux-lang.dev/docs/learn/rc) you already know, made safe to use across threads: ```rux import Allocator::{ Arc, SystemAllocator }; ``` ## Making one `Arc::Create` moves a value onto the heap, next to a count of the handles that share it, and returns the first handle. The storage comes from an [allocator](https://rux-lang.dev/docs/learn/allocator), so making one can fail, and it returns `Arc ! AllocError`: ```rux let stock = Shop { prices: [120, 250, 75, 499], sold: Atomic(0) }; var shop = Arc::Create(SystemAllocator(), stock) catch { else => return 1 }; ``` The allocator must be one every thread can use. `SystemAllocator` is. ## Copies are handles Copying an `Arc` copies only the handle: it points at the same value and adds one to the count. The value itself is never duplicated, however large it is. Each till gets a copy, which moves to its thread with the rest of the till: ```rux var tills: JoinHandle[3] = [ Spawn(Ring, Till { orders: [1, 0, 2, 0], shop: shop }) catch { else => return 1 }, Spawn(Ring, Till { orders: [0, 3, 0, 1], shop: shop }) catch { else => return 1 }, Spawn(Ring, Till { orders: [2, 2, 2, 2], shop: shop }) catch { else => return 1 } ]; ``` ```mermaid flowchart LR m["`Main`'s handle"] --> b["count: 4
the `Shop`"] t1["till 1's handle"] --> b t2["till 2's handle"] --> b t3["till 3's handle"] --> b ``` Dropping a handle subtracts one, and whichever handle is last — on whichever thread — destroys the value and returns its storage. That is the one difference from `Rc`: an `Rc` keeps its count with plain arithmetic, and two threads changing it at once would lose a count, just as in the race in [Atomic](https://rux-lang.dev/docs/learn/atomic). An `Arc` changes its count with atomic operations, so copies can be made and dropped on any thread at the same moment. | Method | Returns | | ----------------------- | ---------------------------------------------------------------- | | `Arc::Create(a, value)` | the first handle, `Arc ! AllocError` | | `Get()` | `*T`, the value, for reading | | `GetMutable()` | `(*var T)?`, the value for writing, only while one handle exists | | `Count()` | how many handles share the value right now | | `SameAs(other)` | whether two handles share one value | After the joins, every till has finished and dropped its copy, so `Count` is back to 1. ## Reading, and changing Through an `Arc`, the value is only read: `Get` returns a read-only `*T`. Several threads read it at once, and reading never races with reading. Whatever must change while the value is shared needs synchronization of its own, inside the `Arc`. Here that is the `sold` counter, an `Atomic` in the shared `Shop`: ```rux struct Shop { prices: uint64[4]; sold: Atomic; } ``` ```rux func Ring(till: Till) -> uint64 { let shop = till.shop.Get(); var revenue: uint64 = 0; for index in 0..4 { revenue = revenue + till.orders[index] * shop.prices[index]; shop.sold.FetchAdd(till.orders[index]); } return revenue; } ``` The only other way to write is `GetMutable`, which gives a `*var T` only while a single handle exists — when nobody else could be reading. At the end, `Main` holds the last handle and changes a price. `Mutex` and the other types of the `Sync` package are handles already, with a `Clone` of their own, so they need no `Arc` around them. `Arc` is for everything else: a table, a configuration, a struct of atomics. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Concurrency/Arc){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // A thread outlives the line that started it, so whatever it is given must last as long as the // thread does. Moving a value in works for one thread. Several threads that need the same large // value would each need a copy, and a pointer to a local is only safe while that local lives. // // An `Arc` (atomically reference-counted) puts one value on the heap and shares it between // handles. Copying a handle only adds one to a count; the value itself is never duplicated. // Dropping a handle subtracts one, and the last handle to go destroys the value. It is the `Rc` // of the Rc lesson with one difference: the count changes through atomic operations, so copies // can be made and dropped on different threads at the same time. // // Through an `Arc` the value is only read. Whatever in it must change while it is shared needs // its own synchronization, such as an `Atomic` or a `Mutex` inside it. import Allocator::{ Arc, SystemAllocator }; import Atomic::Atomic; import Io::PrintLine; import Thread::{ JoinHandle, Spawn }; // What every till shares: a price list nobody changes, and a counter they all add to. struct Shop { prices: uint64[4]; sold: Atomic; } // What a till is given: its own orders, and a handle to the shop. struct Till { orders: uint64[4]; shop: Arc; } // Prices the orders from the shared list and counts the items in the shared total. `Get` gives a // read-only `*Shop`, so `shop.prices[0] = 110;` here is refused: // // error: cannot modify data through read-only pointer '*Shop' func Ring(till: Till) -> uint64 { let shop = till.shop.Get(); var revenue: uint64 = 0; for index in 0..4 { revenue = revenue + till.orders[index] * shop.prices[index]; shop.sold.FetchAdd(till.orders[index]); } return revenue; } // A copy shares the value rather than duplicating it. func Inspect(copy: Arc, original: &Arc) { PrintLine("same shop {}", copy.SameAs(original)); PrintLine("handles now {}", original.Count()); } func Main() -> int { // The first handle. Its storage comes from an allocator, so making it can fail. let stock = Shop { prices: [120, 250, 75, 499], sold: Atomic(0) }; var shop = Arc::Create(SystemAllocator(), stock) catch { else => return 1 }; PrintLine("handles before {}", shop.Count()); // Each till gets a copy of the handle. Every copy points at the same shop, and moves to its // thread with the rest of the till. var tills: JoinHandle[3] = [ Spawn(Ring, Till { orders: [1, 0, 2, 0], shop: shop }) catch { else => return 1 }, Spawn(Ring, Till { orders: [0, 3, 0, 1], shop: shop }) catch { else => return 1 }, Spawn(Ring, Till { orders: [2, 2, 2, 2], shop: shop }) catch { else => return 1 } ]; for index in 0..3 { PrintLine("till {} took {}", index + 1, tills[index].Join()); } // Every till has finished and dropped its copy, so only `Main`'s handle is left. PrintLine("items sold {}", shop.Get().sold.Load()); PrintLine("handles after {}", shop.Count()); // Passing a handle by value copies it, so for as long as the call runs there are two. Inspect(shop, shop); // The copy went with the call, so this is the only handle again, and it may change the value. match shop.GetMutable() { value? => value.prices[0] = 110, none => PrintLine("still shared") } PrintLine("first price {}", shop.Get().prices[0]); return 0; } ``` Besides `Io`, its `Rux.toml` lists `Allocator`, `Atomic` and `Thread` under `[Dependencies]`. ## Run it ```sh cd Examples/Concurrency/Arc rux run ``` ```text handles before 1 till 1 took 270 till 2 took 1249 till 3 took 1888 items sold 15 handles after 1 same shop true handles now 2 first price 110 ``` ## Common mistakes ::mistake **Writing through `Get`.**:br`Get` returns a read-only pointer, so `shop.prices[0] = 110;` in `Ring` fails with: ```text error: cannot modify data through read-only pointer '*Shop' ``` Put what changes in an atomic or a mutex inside the shared value, or use `GetMutable` once the handle is the only one. :: ::mistake **Sending an `Rc` to another thread.**:br`Spawn(Read, shared)` with an `Rc` compiles, but the threads then change one count with plain arithmetic, and a lost update frees the value while a handle still points at it — or never frees it. Across threads, use `Arc`. :: ::mistake **Trusting `Count` while threads run.**:br Other threads copy and drop handles at any moment, so the count can be stale as soon as it is read. It is exact only when no other thread holds a handle — as after the joins here. :: ::mistake **A cycle of handles.**:br There are no weak handles. Two values that hold `Arc`s to each other keep each other's count above zero, and neither is ever freed. :: ## Try it yourself 1. Add a fourth till, and check that `handles after` is still 1. 2. Count the revenue in the shop too: add a `revenue: Atomic` field to `Shop`, add to it in `Ring`, and compare it with the sum of what the tills returned. 3. Print `shop.GetMutable() != none` just before the joins instead of after them. Can you predict what it prints? Why not? ## Learn more - [Allocator](https://rux-lang.dev/docs/api/allocator) — the package in the API reference, with `Rc` and `Arc` - [Atomics](https://rux-lang.dev/docs/lang/memory/atomics) — the operations the count is kept with - [Rc](https://rux-lang.dev/docs/learn/rc) — the same handle for one thread - [Mutex](https://rux-lang.dev/docs/learn/mutex) — a shared value every thread may change # Channel ::note **You'll need**: [Presence](https://rux-lang.dev/docs/learn/presence), [Thread](https://rux-lang.dev/docs/learn/thread), [Mutex](https://rux-lang.dev/docs/learn/mutex) :: Atomics and locks let threads share data safely. A **channel** lets them share nothing at all: one thread sends a value, and the value moves to whichever thread receives it. Each value has one owner at a time, so there is nothing to guard. Many concurrent programs are easiest to write as a line of stages, each on its own thread, passing work down the line. ```rux import Sync::Channel; ``` ## A bounded queue A `Channel` is a queue with room for a fixed number of values, its **capacity**, set when it is made. Values come out in the order they went in. | Method | Does | Returns | | -------------- | ---------------------------------------------------------- | ----------------------- | | `Send(v)` | adds `v`, waiting while the channel is full | `! T`: fails if closed | | `TrySend(v)` | adds `v` if there is room, without waiting | `! T`: fails if full | | `Receive()` | takes the oldest value, waiting while the channel is empty | `T?`: none once drained | | `TryReceive()` | takes the oldest value if there is one, without waiting | `T?` | | `Close()` | ends the stream: no more sends | nothing | Because `Send` waits while the channel is full, a fast producer cannot run ahead of a slow consumer and pile up values without limit: it is slowed to the consumer's pace. That is called **backpressure**. The channels here have room for just two values each. Like `Mutex`, a channel is a handle, and `Clone` gives each thread one of its own. ## A pipeline The program is three stages connected by two channels. `Generate` sends the numbers 1 to 10, `Square` squares each one, and `Main` adds them up: ```mermaid flowchart LR g["`Generate`"] -- "numbers" --> s["`Square`"] s -- "squares" --> m["`Main`"] ``` ```rux let numbers = Channel(2); let squares = Channel(2); var producer = Spawn(Generate, numbers.Clone()) catch { else => return 1 }; var squarer = Spawn(Square, Stage { input: numbers.Clone(), output: squares.Clone() }) catch { else => return 1 }; ``` The middle stage holds one end of each channel. It receives until its input runs dry, sends each square on, and then closes its own output: ```rux func Square(stage: Stage) -> () { while true { match stage.input.Receive() { value? => stage.output.Send(value * value) catch { else => return }, none => break } } stage.output.Close(); } ``` `Receive` returns `uint64?`. A value means work to do; [`none`](https://rux-lang.dev/docs/learn/presence) means the channel is closed *and* empty, so nothing more will ever come. Only `Main` prints, and with one sender per channel the squares arrive in exactly the order they were sent. ## Closing A receiver cannot tell "nothing yet" from "nothing ever" on its own. The sender says so by calling `Close` when it is finished, and each stage passes the end of the stream down the line by closing its own output once its input is done. Closing does not throw away what was already sent: receivers still take every value left in the queue, and only then get none. ```rux let late = Channel(4); late.Send(7) catch { else => return 1 }; late.Send(8) catch { else => return 1 }; late.Close(); ``` After the `Close`, `late` still gives 7, then 8, then none. A `Send` to a closed channel fails — and hands the value back as its failure, so nothing is lost silently: ```rux match late.Send(9) { .Success(_) => PrintLine("sent 9"), .Failure(value) => PrintLine("closed, {} came back", value) } ``` Any number of threads may send to one channel and receive from it. With several senders the values of each one still arrive in order, but how the senders' values interleave depends on the scheduling. Close the channel only once *every* sender has finished — for instance after joining them all. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Concurrency/Channel){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // Locks let threads share data. A channel lets them share nothing: one thread sends a value, and // the value moves to whichever thread receives it. Each value has one owner at a time, so there // is nothing to guard. // // A `Channel` is a queue with room for a fixed number of values. `Send` waits while it is full // and `Receive` waits while it is empty, so a fast producer is slowed to the pace of its consumer // instead of piling up values without limit. Values arrive in the order they were sent. // // When the producer has nothing more to send, it calls `Close`. Receivers still take what is left // in the queue, and then `Receive` returns none: that is how a consumer knows the stream is over. // Like `Mutex`, a channel is a handle, and `Clone` gives each thread its own. import Io::{ Print, PrintLine }; import Sync::Channel; import Thread::{ JoinHandle, Spawn }; // The first stage sends 1 to 10, then closes its channel. func Generate(output: Channel) -> () { for value in 1u64..=10u64 { // `Send` fails, handing the value back, only once the channel is closed. output.Send(value) catch { else => return }; } output.Close(); } // The middle stage's two ends. struct Stage { input: Channel; output: Channel; } // The second stage squares each value it receives until its input runs dry, then closes its own // output, so the end of the stream passes down the line. func Square(stage: Stage) -> () { while true { match stage.input.Receive() { value? => stage.output.Send(value * value) catch { else => return }, none => break } } stage.output.Close(); } func Main() -> int { // Two small channels: neither stage can run more than two values ahead of the next. let numbers = Channel(2); let squares = Channel(2); var producer = Spawn(Generate, numbers.Clone()) catch { else => return 1 }; var squarer = Spawn(Square, Stage { input: numbers.Clone(), output: squares.Clone() }) catch { else => return 1 }; // Only `Main` prints. It receives the squares in order, and stops when the stream ends. // `Receive` returns `uint64?`, so `let value: uint64 = squares.Receive();` is refused: // // error: cannot assign 'uint64?' to 'uint64' var total: uint64 = 0; Print("squares:"); while true { match squares.Receive() { value? => { Print(" {}", value); total = total + value; }, none => break } } PrintLine(""); PrintLine("total: {}", total); producer.Join(); squarer.Join(); // Closing does not throw away what was already sent: the queue drains first. let late = Channel(4); late.Send(7) catch { else => return 1 }; late.Send(8) catch { else => return 1 }; late.Close(); let first = late.Receive() ?? 0; let second = late.Receive() ?? 0; let third = late.Receive(); PrintLine("after close: {}, {}, then {}", first, second, third == none ? "none" : "more"); // A send to a closed channel fails and returns the value, so nothing is lost silently. match late.Send(9) { .Success(_) => PrintLine("sent 9"), .Failure(value) => PrintLine("closed, {} came back", value) } return 0; } ``` Besides `Io`, its `Rux.toml` lists `Sync` and `Thread` under `[Dependencies]`. ## Run it ```sh cd Examples/Concurrency/Channel rux run ``` ```text squares: 1 4 9 16 25 36 49 64 81 100 total: 385 after close: 7, 8, then none closed, 9 came back ``` ## Common mistakes ::mistake **Treating `Receive` as a value.**:br`let value: uint64 = squares.Receive();` fails with: ```text error: cannot assign 'uint64?' to 'uint64' ``` The channel may be closed and empty. Say what to do then, with a `match` or `??`. :: ::mistake **Never closing.**:br Dropping every sending handle does not close a channel. A receiver looping on `Receive` waits forever for a value that will never come, and the program hangs. Close it when the last value is sent. :: ::mistake **Closing too early.**:br With several senders, one that closes the channel when *it* is done makes every other sender's `Send` fail from then on. Close it once all of them have finished. :: ::mistake **A channel with no room.**:br`Channel(0)` stops the program: ```text Panic: a channel needs room for at least one value ``` :: ## Try it yourself 1. Add a third stage between `Square` and `Main` that passes on only the even squares. 2. Start two `Square` threads on the same pair of channels. Each closes `squares` when it is done — why can that lose values, and how would `Main` close it instead? 3. Make `Generate` use `TrySend`, and count how often the channel was full. ## Learn more - [Sync](https://rux-lang.dev/docs/api/sync) — the package in the API reference - [Presence](https://rux-lang.dev/docs/learn/presence) — matching `value?` and `none` - [Mutex](https://rux-lang.dev/docs/learn/mutex) — sharing data instead of passing it - [Wait group](https://rux-lang.dev/docs/learn/wait-group) — the next lesson: waiting for a whole group of threads # Wait group ::note **You'll need**: [Move](https://rux-lang.dev/docs/learn/move), [Thread](https://rux-lang.dev/docs/learn/thread), [Mutex](https://rux-lang.dev/docs/learn/mutex) :: `Join` waits for one thread whose handle you kept. Often there is a whole group of them, started in a loop and let go, and all that matters is that every one has finished — before the results are read, before the program moves on to its next phase, before it exits. A `WaitGroup` counts unfinished work: ```rux import Sync::{ Mutex, WaitGroup }; ``` ## Counting the work | Method | Called by | Does | | -------- | ------------------------------------ | ------------------------------- | | `Add(n)` | the starting thread, before starting | adds `n` pieces of pending work | | `Done()` | each worker, as its last step | marks one piece done | | `Wait()` | whoever needs the results | sleeps until nothing is pending | The order matters. All the work is counted in **before** any of it starts: ```rux group.Add(Workers as uint32); ``` Had each worker called `Add` itself, `Main` could reach `Wait` before any worker had started, see a count of zero, and carry on with nothing done. ```mermaid flowchart LR a["`Add(4)`
pending: 4"] --> w1["worker 1 `Done`"] a --> w2["worker 2 `Done`"] a --> w3["worker 3 `Done`"] a --> w4["worker 4 `Done`"] w1 --> z["pending: 0"] w2 --> z w3 --> z w4 --> z z --> r["`Wait` returns"] ``` ## Detached workers `Main` never needs the workers' handles, so it starts them in an ordinary loop and [detaches](https://rux-lang.dev/docs/learn/thread) each one at once. Everything a worker needs travels in its `Job`, with its own handles to the shared results and to the wait group: ```rux let job = Job { slot: index, first: first, last: first + Size - 1, results: results.Clone(), group: group.Clone() }; ``` A `Job` holds handles, which cannot be copied, so the job itself cannot be either. It is [moved](https://rux-lang.dev/docs/learn/move) into `Spawn` with `<-`: ```rux var worker = Spawn(CountPrimes, <-job) catch { else => return 1 }; worker.Detach(); ``` The worker counts the primes in its range, stores the count, and calls `Done` last — after its result is stored, so that whoever `Wait` wakes finds every result in place: ```rux Store(job.results, job.slot, count); job.group.Done(); ``` Like `Mutex`, a `WaitGroup` is a handle, and `Clone` gives each worker its own. ## Results in order The workers finish in whatever order they happen to, and that order changes from run to run. So none of them prints. Each one writes its count into its **own numbered slot** — slot 0 for the first range, slot 1 for the second — under the mutex, and once `Wait` returns, `Main` prints the slots in order. The answers come out the same way every time, whichever worker was quickest. ## Two relatives Two more counters in the `Sync` package coordinate threads by counting. A `Semaphore` holds a number of **permits**. `Acquire` takes one, waiting while none is left, and `Release` gives it back — so a semaphore of two lets at most two threads into a stretch of code at once, which suits a resource that only so many may use: ```rux let permits = Semaphore(2); ``` ```rux crew.permits.Acquire(); crew.permits.Release(); ``` A `Barrier` is a meeting point for a fixed number of threads: each `Wait` blocks until all of them have arrived, and then they all go on together. It suits work done in phases, where nobody may start phase two until everyone has finished phase one. `Wait` returns `true` on exactly one thread of each round — the last to arrive — for work to do once per round: ```rux if crew.barrier.Wait() { PrintLine("last"); } ``` | Type | Waits until | Suits | | ----------- | ------------------------------------ | ------------------------------- | | `WaitGroup` | the pending work reaches zero | waiting for a group to finish | | `Semaphore` | a permit is free | limiting how many run at once | | `Barrier` | every party of the round has arrived | phases that must start together | ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Concurrency/WaitGroup){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // `Join` waits for one thread whose handle you kept. Often there is a whole group of them, started // in a loop and let go, and what matters is only that all of them are finished. // // A `WaitGroup` counts unfinished work. `Add(n)` raises the count before the work starts, each // worker calls `Done` as its last step, and `Wait` sleeps until the count is back at zero. The // waiting thread never needs the workers' handles, so they can be detached. // // Workers that finish in any order must not print as they go, or the lines come out shuffled. // Here each one writes its answer into its own numbered slot, and `Main` prints the slots in // order once `Wait` returns. import Io::PrintLine; import Sync::{ Mutex, WaitGroup }; import Thread::Spawn; const Workers: uint = 4; const Size: uint64 = 25000; // One slot per worker, filled in whatever order the workers finish. struct Results { primes: uint64[4]; } // Everything one worker needs: its slot and its range, and handles to what the group shares. struct Job { slot: uint; first: uint64; last: uint64; results: Mutex; group: WaitGroup; } func IsPrime(value: uint64) -> bool { if value < 2 { return false; } var divisor: uint64 = 2; while divisor * divisor <= value { if value % divisor == 0 { return false; } divisor = divisor + 1; } return true; } func Store(results: &Mutex, slot: uint, count: uint64) { let guard = results.Lock(); guard.Get().primes[slot] = count; } func CountPrimes(job: Job) -> () { var count: uint64 = 0; for value in job.first..=job.last { if IsPrime(value) { count = count + 1; } } Store(job.results, job.slot, count); // The last step: once every worker has called this, `Wait` returns. job.group.Done(); } func Main() -> int { let results = Mutex(Results { primes: [0, 0, 0, 0] }); let group = WaitGroup(); // Count all the work in before starting any of it, so `Wait` cannot see zero too early. group.Add(Workers as uint32); for index in 0..Workers { let first = index as uint64 * Size + 1; let job = Job { slot: index, first: first, last: first + Size - 1, results: results.Clone(), group: group.Clone() }; // The job holds handles, so it cannot be copied and is moved in. `Spawn(CountPrimes, job)` // is refused: // // error: move-only value 'job' requires an explicit '<-' in argument // help: prefix the argument with '<-', as in 'Take(<-job)' // // Nobody joins these threads, so their handles are let go at once. var worker = Spawn(CountPrimes, <-job) catch { else => return 1 }; worker.Detach(); } // Sleeps until every worker has called `Done`. group.Wait(); let guard = results.Lock(); var total: uint64 = 0; for index in 0..Workers { let first = index as uint64 * Size + 1; let count = guard.Get().primes[index]; PrintLine("{:>6} to {:>6}: {} primes", first, first + Size - 1, count); total = total + count; } PrintLine("all {} workers done: {} primes up to {}", Workers, total, Workers as uint64 * Size); return 0; } ``` Besides `Io`, its `Rux.toml` lists `Sync` and `Thread` under `[Dependencies]`. ## Run it ```sh cd Examples/Concurrency/WaitGroup rux run ``` ```text 1 to 25000: 2762 primes 25001 to 50000: 2371 primes 50001 to 75000: 2260 primes 75001 to 100000: 2199 primes all 4 workers done: 9592 primes up to 100000 ``` ## Common mistakes ::mistake **Passing the job without moving it.**:br`Spawn(CountPrimes, job)` fails with: ```text error: move-only value 'job' requires an explicit '<-' in argument help: prefix the argument with '<-', as in 'Take(<-job)' ``` The job holds handles, so it can only be moved: `Spawn(CountPrimes, <-job)`. :: ::mistake **Adding inside the worker.**:br A worker that calls `Add` as its first step may not have run yet when `Main` reaches `Wait`, which then sees zero and returns at once. Call `Add` before starting the work. :: ::mistake **One `Done` too many.**:br Marking more work done than was added is a program error: ```text Panic: a wait group was marked done more times than work was added ``` :: ::mistake **A worker that never calls `Done`.**:br A worker that returns early — on an error, say — without calling `Done` leaves the count above zero, and `Wait` sleeps forever. Make `Done` the last thing on every path out of the worker — `defer job.group.Done();` as the worker's first line does exactly that. :: ## Try it yourself 1. Use eight workers of 12500 numbers each. You will need eight slots in `Results`. 2. Have each worker also record the largest prime in its range, in a second array of slots. 3. Give each `Job` a clone of one `Barrier(4)`, and have the workers wait at it between counting and storing. Does the same worker's `Wait` return `true` on every run? ## Learn more - [Sync](https://rux-lang.dev/docs/api/sync) — the package in the API reference, with `Semaphore` and `Barrier` - [Thread](https://rux-lang.dev/docs/learn/thread) — joining one thread, and detaching - [Mutex](https://rux-lang.dev/docs/learn/mutex) — the lock around the slots - [Once](https://rux-lang.dev/docs/learn/once) — the next lesson: work done exactly once, whoever asks first # Once ::note **You'll need**: [Callback](https://rux-lang.dev/docs/learn/callback), [Thread](https://rux-lang.dev/docs/learn/thread) :: Some work should happen once and only once: building a lookup table, reading a configuration file, opening a log. The simplest place for it is `Main`, before any thread starts. Sometimes that is not possible — a library cannot know when its first caller arrives, or on which thread — and the work must be done by whoever needs it first. ```rux import Sync::Once; ``` ## The race The obvious way is a flag: ```rux if !Built { Build(); Built = true; } ``` On one thread that is fine. On several it is the [race](https://rux-lang.dev/docs/learn/atomic) again: two threads can both read `Built` as `false` before either sets it, and both build. Worse, a third thread may see `Built` become `true` before it sees what `Build` wrote, and read a half-built table. ## Once A `Once` settles both problems. Its `Call` takes a function with no parameters and no result: ```rux func IsPrime(value: uint) -> bool { Setup.Call(BuildTable); Lookups = Lookups + 1; return !Composite[value]; } ``` - The **first** `Call` runs `BuildTable`. - Any thread that calls **while it runs** waits until it has finished. - Every **later** call returns at once — one atomic load, so a `Call` on every lookup costs next to nothing. Everything `BuildTable` wrote is visible to every thread that `Call` returns on, so the table may then be read without any further locking. `IsCompleted` says whether the work has been done. ```mermaid flowchart LR i["incomplete"] -- "first `Call`" --> r["running:
other callers wait"] r -- "function returns" --> c["complete:
every `Call` returns at once"] ``` ## A module variable A `Once` lives where it is declared and needs no destroying, so — unlike a `Mutex` — it can be a **module variable**, which every thread names directly with no handle to pass around. A module variable starts from a compile-time value, and `Once::Incomplete` is a constant for exactly that: ```rux var Composite: bool[1001] = [false; 1001]; var Builds: uint64 = 0; ``` ```rux var Setup: Once = Once::Incomplete; ``` `Composite` and `Builds` are plain module variables too. They are written only inside `BuildTable`, by one thread, and read only after `Call` has returned, so they need no lock of their own. The program counts the builds to show that four threads asking at once built the table once. `Lock` in the `Sync` package works the same way: a bare lock that can be a module variable, starting as `Lock::Unlocked`. ## Each thread's own Next to them is a different kind of module variable: ```rux thread var Lookups: uint64 = 0; ``` A `thread var` gives **every thread its own copy**. Each copy starts at the initial value, whether its thread is `Main` or one started later, and a thread only ever sees its own. So each worker counts its own 250 lookups without any atomic or lock — nobody else touches its copy — and `Main`'s copy is still 0 at the end. | Declaration | Copies | Sharing it between threads needs | | ------------------------ | -------------------- | -------------------------------- | | `var Name: T = …` | one, for the program | an atomic, a lock or a `Once` | | `thread var Name: T = …` | one per thread | nothing — it is never shared | ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Concurrency/Once){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // Some work should happen once and only once: building a lookup table, reading a configuration // file, opening a log. Doing it in `Main` before any thread starts is simplest. When that is not // possible, because the first user may be any thread at any time, a check like // `if !Built { Build(); }` is a race: two threads can both see `false` and both build. // // A `Once` settles it. The first `Call` runs its function; any other thread that calls meanwhile // waits until that has finished, and every later call returns at once. Everything the function // wrote is visible to every thread that `Call` returns on. // // A `Once` needs no destroying, so it can be a module variable, starting as `Once::Incomplete`, // which every thread names directly. Next to it is a `thread var`: a module variable of which // every thread has its own copy. import Io::PrintLine; import Sync::Once; import Thread::{ JoinHandle, Spawn }; const Limit: uint = 1000; // The table every thread reads, built on first use, and how many times it was built. var Composite: bool[1001] = [false; 1001]; var Builds: uint64 = 0; // What guards the building. A module variable starts from a compile-time value, which is why // `Once::Incomplete` is a constant; `var Setup: Once = Once();` is refused: // // error: call to 'Once' is not a compile-time value var Setup: Once = Once::Incomplete; // Each thread's own count of the lookups it made. Every thread's copy starts at 0. thread var Lookups: uint64 = 0; // The sieve of Eratosthenes: cross out every multiple of each prime. func BuildTable() { Builds = Builds + 1; Composite[0] = true; Composite[1] = true; for value in 2..=Limit { if Composite[value] { continue; } var multiple = value * value; while multiple <= Limit { Composite[multiple] = true; multiple = multiple + value; } } } func IsPrime(value: uint) -> bool { // Whichever thread gets here first builds the table; the others wait for it. Setup.Call(BuildTable); Lookups = Lookups + 1; return !Composite[value]; } struct Span { first: uint; last: uint; } struct Report { primes: uint; lookups: uint64; } func CountPrimes(span: Span) -> Report { var primes: uint = 0; for value in span.first..=span.last { if IsPrime(value) { primes = primes + 1; } } return Report { primes: primes, lookups: Lookups }; } func Main() -> int { // Four threads all need the table at once, and none of them builds it in advance. var counters: JoinHandle[4] = [ Spawn(CountPrimes, Span { first: 1, last: 250 }) catch { else => return 1 }, Spawn(CountPrimes, Span { first: 251, last: 500 }) catch { else => return 1 }, Spawn(CountPrimes, Span { first: 501, last: 750 }) catch { else => return 1 }, Spawn(CountPrimes, Span { first: 751, last: 1000 }) catch { else => return 1 } ]; var total: uint = 0; for index in 0..4 { let report = counters[index].Join(); PrintLine("thread {}: {} primes in {} lookups", index + 1, report.primes, report.lookups); total = total + report.primes; } PrintLine("primes up to {}: {}", Limit, total); PrintLine("table built: {} time", Builds); PrintLine("completed: {}", Setup.IsCompleted()); // `Main` made no lookups, so its own copy of `Lookups` is untouched. PrintLine("lookups in Main: {}", Lookups); return 0; } ``` Besides `Io`, its `Rux.toml` lists `Sync` and `Thread` under `[Dependencies]`. ## Run it ```sh cd Examples/Concurrency/Once rux run ``` ```text thread 1: 53 primes in 250 lookups thread 2: 42 primes in 250 lookups thread 3: 37 primes in 250 lookups thread 4: 36 primes in 250 lookups primes up to 1000: 168 table built: 1 time completed: true lookups in Main: 0 ``` ## Common mistakes ::mistake **Making the `Once` with a call.**:br`var Setup: Once = Once();` fails with: ```text error: call to 'Once' is not a compile-time value help: initialize 'Setup' from literals, operators, casts, and constants, and assign it from a function at run time ``` Start it as the constant `Once::Incomplete`. :: ::mistake **An initializer with parameters.**:br`Call` takes a `func()`: no parameters and no result. A function such as `Build(limit: uint)` is refused. Put what it needs in module variables or constants, as `Limit` is here. :: ::mistake **A flag instead of a `Once`.**:br`if !Built { Build(); Built = true; }` compiles and usually works — until two threads arrive together. Then the table is built twice, or read half built. The bug appears rarely and never on demand, which is what makes it expensive. :: ::mistake **Expecting a `thread var` to be shared.**:br Each thread changes only its own copy. A count kept in a `thread var` is that thread's count; to add up all of them, return each one, as `CountPrimes` does in its `Report`. :: ## Try it yourself 1. Call `IsPrime` once in `Main` before starting the threads. What changes in the output, and what does not? 2. Add a second `Once` that fills a table of squares, used by a second function. 3. Remove `Setup.Call` and call `BuildTable` from `Main` before starting the threads instead. Why is that also correct? ## Learn more - [Sync](https://rux-lang.dev/docs/api/sync) — the package in the API reference, with `Once` and `Lock` - [Module variables](https://rux-lang.dev/docs/lang/bindings/module-variables) — `var` and `thread var` at module level, and their initial values - [Callback](https://rux-lang.dev/docs/learn/callback) — passing `BuildTable` as a value - [Read-write lock](https://rux-lang.dev/docs/learn/rw-lock) — the next lesson: many readers or one writer # Read-write lock ::note **You'll need**: [Mutex](https://rux-lang.dev/docs/learn/mutex) :: Many shared values are read far more often than they change: a configuration, a price list, a routing table, a cache. A [`Mutex`](https://rux-lang.dev/docs/learn/mutex) makes every reader wait for every other reader — yet readers alone could never disturb each other. Only a writer can. A **read-write lock** tells the two apart. Any number of threads may read at the same time; a writer waits until nobody is reading and then has the value to itself. ```rux import Sync::RwLock; ``` ## Two kinds of guard | Method | Returns | `Get` gives | Shared with | | --------- | --------------- | ----------- | --------------------------- | | `Read()` | `ReadGuard` | `*T` | any number of other readers | | `Write()` | `WriteGuard` | `*var T` | nobody | `Read` waits only while a writer holds the lock. `Write` waits until no reader and no writer holds it. Either guard releases its hold when it is dropped, as a `MutexGuard` does. A read guard's `Get` returns a read-only `*T`, so a reader cannot write by mistake: the compiler refuses it. The writer moves stock from one warehouse to the other under a write guard: ```rux let guard = stock.Write(); let bins = guard.Get(); bins.north = bins.north - 1; bins.south = bins.south + 1; ``` and each reader checks the total under a read guard: ```rux let guard = stock.Read(); let bins = guard.Get(); if bins.north + bins.south == 1000 { correct = correct + 1; } ``` ```mermaid flowchart LR free["free"] -- "`Read`" --> r["read: 1, 2, 3 … readers"] r -- "`Read`" --> r r -- "last reader leaves" --> free free -- "`Write`" --> w["write: one writer alone"] w -- "writer leaves" --> free ``` ## What it buys One writer and three readers run at once. The readers never wait for each other, and between them they look at the total 6000 times while the writer moves 500 items — and every single look sees 1000, because no reader can hold the lock while the writer is halfway through a move. At the end, `Main` takes two read guards on the same lock at once, which a `Mutex` could never give: ```rux let first = stock.Read(); let second = stock.Read(); ``` Like `Mutex`, an `RwLock` is a handle: `Clone` gives each thread its own, and the value lives until the last handle and the last guard are gone. ## Choosing between them An `RwLock` does more bookkeeping than a `Mutex`, so it pays off only when reads are frequent, take a while, and far outnumber writes. It also queues nobody: a steady stream of readers can keep a writer waiting for a long time. For short, balanced access, a `Mutex` is simpler and usually just as fast. A thread that must wait under a lock until some condition holds — until a queue is non-empty, until a flag is set — wants a `Condition` from the same package. It is used with a `Mutex`: `Wait` releases the guard's lock while the thread sleeps and takes it back before returning, and another thread calls `NotifyOne` or `NotifyAll` after changing the value. A wait can return without a notification, so it is always written in a loop that checks the condition. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Concurrency/RwLock){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // Many shared values are read far more often than they change: a configuration, a price list, a // routing table. A `Mutex` makes every reader wait for every other reader, although readers // alone could never disturb each other. // // An `RwLock` tells the two apart. `Read` returns a `ReadGuard`, and any number of threads // may hold one at the same time. `Write` returns a `WriteGuard`, which waits until nobody holds // the lock at all and then keeps everyone else out until it is dropped. A read guard's `Get` gives // a `*T`, so a reader cannot write by mistake; only a write guard gives a `*var T`. // // Like `Mutex`, an `RwLock` is a handle: `Clone` gives each thread its own, and the value // lives until the last handle and the last guard are gone. import Io::PrintLine; import Sync::RwLock; import Thread::{ JoinHandle, Spawn }; // Stock in two warehouses. Moving stock changes both, and the total must never look different. struct Stock { north: int64; south: int64; } // The writer moves one item at a time from north to south, 500 times. func Move(stock: RwLock) -> uint64 { var moves: uint64 = 0; for round in 0..500 { let guard = stock.Write(); let bins = guard.Get(); bins.north = bins.north - 1; bins.south = bins.south + 1; moves = moves + 1; } return moves; } // A reader looks at the total over and over, and counts how often it saw the right one. Its guard // gives a read-only `*Stock`, so `bins.north = 0;` here is refused: // // error: cannot modify data through read-only pointer '*Stock' func Audit(stock: RwLock) -> uint64 { var correct: uint64 = 0; for round in 0..2000 { let guard = stock.Read(); let bins = guard.Get(); if bins.north + bins.south == 1000 { correct = correct + 1; } } return correct; } func Main() -> int { let stock = RwLock(Stock { north: 1000, south: 0 }); // One writer and three readers, all at once. The readers share the lock with each other, and // wait only while the writer holds it. var writer = Spawn(Move, stock.Clone()) catch { else => return 1 }; var readers: JoinHandle[3] = [ Spawn(Audit, stock.Clone()) catch { else => return 1 }, Spawn(Audit, stock.Clone()) catch { else => return 1 }, Spawn(Audit, stock.Clone()) catch { else => return 1 } ]; PrintLine("writer moved {} items", writer.Join()); for index in 0..3 { PrintLine("reader {} saw {} of 2000 totals right", index + 1, readers[index].Join()); } // Two read guards on one lock at the same time: reading is shared. let first = stock.Read(); let second = stock.Read(); PrintLine("north {} south {} (read twice: {})", first.Get().north, first.Get().south, second.Get().north == first.Get().north); return 0; } ``` Besides `Io`, its `Rux.toml` lists `Sync` and `Thread` under `[Dependencies]`. ## Run it ```sh cd Examples/Concurrency/RwLock rux run ``` ```text writer moved 500 items reader 1 saw 2000 of 2000 totals right reader 2 saw 2000 of 2000 totals right reader 3 saw 2000 of 2000 totals right north 500 south 500 (read twice: true) ``` ## Common mistakes ::mistake **Writing through a read guard.**:br`bins.north = 0;` in `Audit` fails with: ```text error: cannot modify data through read-only pointer '*Stock' ``` Take a write guard to change the value. :: ::mistake **Upgrading on one thread.**:br Calling `Write` while the same thread still holds a read guard never returns: the writer waits for every reader to leave, and one of them is itself. Drop the read guard first — and since another thread may write in between, read the value again under the write guard. :: ::mistake **Holding a read guard for long.**:br While any reader holds the lock, no writer gets in. A reader that keeps its guard while it does slow work — prints, sleeps, waits for something — holds every writer up. Copy out what you need and let the guard go. :: ## Try it yourself 1. Add a second writer that moves stock back from south to north. Do the readers still always see 1000? 2. Make `Audit` also return the smallest `north` it saw. Is it the same on every run? 3. Change `RwLock` to `Mutex` throughout, with `Lock` in place of `Read` and `Write`. What still works, and what does the last part of `Main` do now? Be ready to stop the program with Ctrl+C. ## Learn more - [Sync](https://rux-lang.dev/docs/api/sync) — the package in the API reference, with `RwLock` and `Condition` - [Mutex](https://rux-lang.dev/docs/learn/mutex) — the lock with one kind of guard - [Arc](https://rux-lang.dev/docs/learn/arc) — sharing a value that nobody changes, with no lock at all - [Concurrency](https://rux-lang.dev/docs/learn/concurrency) — the part overview, to choose between all of these # Part 26: Systems So far every program has been a world of its own: it computed, read a file or two, and printed. Real programs live among others. They are started by a shell with arguments and an environment, and they answer with an exit status. They start programs of their own. They are driven by options typed on a command line, they keep a log for whoever has to find out later what happened, and they talk to other programs over the network. This part covers that boundary, with four standard packages: `Process` for the program's own arguments, environment and exit, and for child processes; `CommandLine` for options and help text; `Log` for structured records; and `Net` for addresses, TCP and UDP. Everything in it runs on one machine — the network lessons use the loopback address, which never leaves it — so every program prints the same on every run. ## What you will learn - Reading the arguments and environment a program was started with, as native text, and ending it early with `Exit`. - Starting another program with a `Command`: waiting for its exit status, capturing what it prints, giving it an environment, and talking to it through pipes. - Describing a command's options, positional arguments and subcommands once, and getting parsing, error messages and `--help` from that one description. - Writing log records with a level and typed fields, as text for people or JSON lines for tools, and keeping log files from growing without end. - Reading, writing and classifying IPv4, IPv6 and socket addresses. - A TCP server and client exchanging lines over a stream, and the framing a stream needs. - UDP datagrams, which keep their boundaries but promise nothing, and a timeout for an answer that never comes. ## The part at a glance ```mermaid flowchart LR shell(["Shell"]) -- "arguments
environment" --> p["Your program"] p -- "exit status" --> shell p -- "Command" --> child["Child process"] p -- "Logger" --> log[("Log")] p -- "TcpStream
UdpSocket" --> peer["Another program"] ``` | Package | Lessons | What it is for | | ------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------ | | `Process` | [Environment](https://rux-lang.dev/docs/learn/environment), [Child process](https://rux-lang.dev/docs/learn/child-process) | this process, and the processes it starts | | `CommandLine` | [Command line](https://rux-lang.dev/docs/learn/command-line) | options, positionals, subcommands and help | | `Log` | [Log](https://rux-lang.dev/docs/learn/log) | records with levels and typed fields | | `Net` | [IP addresses](https://rux-lang.dev/docs/learn/ip-address), [TCP](https://rux-lang.dev/docs/learn/tcp), [UDP](https://rux-lang.dev/docs/learn/udp) | addresses, streams and datagrams | ## Lessons | | Lesson | What you will learn | | ---- | -------------------------------------------------------------- | -------------------------------------------------------------- | | 26.1 | [Environment](https://rux-lang.dev/docs/learn/environment) | the program's arguments, environment variables and exit status | | 26.2 | [Child process](https://rux-lang.dev/docs/learn/child-process) | run another program and capture its output | | 26.3 | [Command line](https://rux-lang.dev/docs/learn/command-line) | declare options and arguments, and get the help text for free | | 26.4 | [Log](https://rux-lang.dev/docs/learn/log) | structured log records with levels and typed fields | | 26.5 | [IP addresses](https://rux-lang.dev/docs/learn/ip-address) | IPv4 and IPv6 addresses, and socket addresses with a port | | 26.6 | [TCP](https://rux-lang.dev/docs/learn/tcp) | a TCP server and client talking over the loopback interface | | 26.7 | [UDP](https://rux-lang.dev/docs/learn/udp) | datagrams between two UDP sockets | ## Before you start Arguments, environment values and file names are all native text, so this part starts from [Path](https://rux-lang.dev/docs/learn/path) in [Part 19: Files](https://rux-lang.dev/docs/learn/files), and its streams — pipes and sockets — are the same readers and writers as files, read with [Input](https://rux-lang.dev/docs/learn/input)'s `ReadLineFrom`. Almost every call can fail, which brings back [Part 9: Errors](https://rux-lang.dev/docs/learn/errors). The TCP lesson runs its client on a [thread](https://rux-lang.dev/docs/learn/thread) from [Part 25: Concurrency](https://rux-lang.dev/docs/learn/concurrency). Each lesson's package is in the Examples repository's `Systems/` folder: ```sh cd Examples/Systems/Environment rux run ``` Two lessons are best tried with arguments of your own as well, given after `--`: ```sh rux run -- --quit ``` Only one line in the whole part changes between runs — the process identifier in Environment — and its page says so. ## After this part Try the checkpoint project: [Grep](https://rux-lang.dev/docs/learn/grep) is a small version of the Unix tool that prints the lines of files matching a regular expression, with options read by the CommandLine package and an exit status that scripts can rely on. Then go on to [Part 27: Projects](https://rux-lang.dev/docs/learn/projects), the complete programs that close the course — each one a checkpoint for an earlier part. For the rules underneath, see [The `Main` function](https://rux-lang.dev/docs/lang/functions/main) and [Conditional compilation](https://rux-lang.dev/docs/lang/comptime/conditional) in the Rux Reference, and the [Process](https://rux-lang.dev/docs/api/process), [CommandLine](https://rux-lang.dev/docs/api/commandline), [Log](https://rux-lang.dev/docs/api/log) and [Net](https://rux-lang.dev/docs/api/net) packages in the API reference. # Environment ::note **You'll need**: [Optional](https://rux-lang.dev/docs/learn/optional), [Guard](https://rux-lang.dev/docs/learn/guard), [Error sum](https://rux-lang.dev/docs/learn/error-sum), [Path](https://rux-lang.dev/docs/learn/path) :: Every program is started by another one — a shell, an editor, a service manager — and it is handed two lists on the way in. The **arguments** are the words typed after the program's name: `--verbose`, a file to open, a port. The **environment** is a set of `NAME=value` pairs, such as `PATH` and `HOME`, inherited from the parent and passed on to every child. On the way out the program hands back one number, its **exit status**: zero for success, anything else for a failure. This lesson reads and changes all three with the `Process` package: ```rux import Process::{ Argument, ArgumentCount, Arguments, CurrentId, Environment, Exit, RemoveVariable, SetVariable, Variable }; ``` ```mermaid flowchart LR parent(["Parent: a shell"]) -- "arguments
environment" --> program["This program"] program -- "exit status" --> parent ``` ## Native text, not strings An argument looks like text, and usually is — but nothing promises it. On Linux and macOS an argument is bytes, on Windows it is 16-bit units, and neither has to be valid UTF-8 or UTF-16. So every argument and every environment value is an `OsStringView`, the same view of native units that names files in [Path](https://rux-lang.dev/docs/learn/path): | You want to… | Use | | ------------------------------- | -------------------------------------------------- | | print it | `{}` — anything that is not text shows as `�` | | turn it into a `String` | `ToText(allocator)`, which can fail | | compare it with a word you know | `Equals`, against `OsString::FromText` of the word | | use it as a path | `Path::FromView`, with no conversion at all | Reading allocates nothing. Every view borrows storage the process owns for its whole life, so a view can be kept as long as you like. ## Arguments `ArgumentCount()` counts the arguments, and `Argument(index)` returns one as an optional — `none` past the end. Argument zero is the program itself, as the parent spelled it: a bare name, a relative path or an absolute one. That differs from machine to machine, so the program prints only its stem: ```rux PrintLine("arguments {}", ArgumentCount() - 1); let program = Path::FromView(Argument(0) ?? OsStringView()); PrintLine("program {}", program.Stem() ?? OsStringView()); var index: uint = 1; for argument in Arguments().Skip(1) { PrintLine("argument {} {}", index, argument); index = index + 1; } ``` `Arguments()` walks them all in order; `Skip(1)` leaves out the program's own name. To give a program arguments under `rux run`, put them after `--`: ```sh rux run -- --quit two ``` ```text arguments 2 program Environment argument 1 --quit argument 2 two leaving early with status 3 ``` ## Comparing with a word An argument cannot be compared with a string literal directly — one is native units, the other UTF-8. `OsString::FromText` turns the literal into this system's units, and `Equals` compares the two: ```rux var quit = OsString::FromText(allocator, "--quit")?; let wanted = quit.View(); let first = Argument(1) ?? OsStringView(); if first.Equals(wanted) { PrintLine("leaving early with status 3"); Exit(3); } ``` `Equals` takes a reference, which is why the view gets a name of its own first. For more than a word or two, the next lesson's [Command line](https://rux-lang.dev/docs/learn/command-line) package does all of this from a description. ## Environment variables `Variable(name)` looks a variable up by its UTF-8 name and returns `OsStringView?`. A missing variable is `none`; a variable set to the empty string is present, with an empty value — the two are different: ```rux func Show(name: char8[..]) { match Variable(name) { value? => PrintLine("{:<13} = \"{}\"", name, value), none => PrintLine("{:<13} is not set", name) } } ``` `SetVariable` and `RemoveVariable` change the environment, and both return `! IoError`: a name that is empty or contains `=` is refused as `InvalidInput`. A change is seen by this process and by every child it starts from now on — never by the parent that started it. `Environment()` walks every variable as an `EnvironmentVariable`, a pair of `name` and `value`. Names are matched the way each system matches them: exactly on Linux and macOS, without regard to ASCII case on Windows, where `Path` and `PATH` are the same variable. ## Exit status There are two ways to end a program with a status: | How | Status | What happens on the way out | | ------------------ | ------------------------------------ | ------------------------------------------------- | | return from `Main` | `0`, or `1` for a failure from `! E` | an ordinary return: destructors run | | `Exit(code)` | `code` | every thread stops at once; nothing is cleaned up | Returning from `Main` is the ordinary way — see [Fallible main](https://rux-lang.dev/docs/learn/fallible-main). `Exit` is for leaving from deep inside a program, and its `code` is an `int32`; Linux and macOS pass only its low eight bits to the parent. `CurrentId()` is the number the system gave this run of the program, different every time. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Systems/Environment){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // Every program starts with two lists handed to it by whoever started it. The arguments are the // words typed after the program's name, such as `--verbose` or a file to open. The environment // is a set of `NAME=value` pairs, such as `PATH` or `HOME`, inherited from the parent process and // passed on to every child. When the program ends it hands one number back: its exit status, // zero for success. // // The `Process` package reads both lists. Neither is guaranteed to be text: on Linux and macOS // an argument is bytes, on Windows it is 16-bit units, and nothing obliges either to be valid // UTF-8 or UTF-16. So every argument and value is an `OsStringView`, a view of the native units // the system handed over, which `{}` prints and `ToText` converts when real text is needed. // // Reading allocates nothing: every view borrows storage the process owns for its whole life. import Allocator::{ Allocator, SystemAllocator }; import Io::{ IoError, IoErrorKind, PrintLine }; import Path::{ OsString, OsStringView, Path }; import Process::{ Argument, ArgumentCount, Arguments, CurrentId, Environment, Exit, RemoveVariable, SetVariable, Variable }; import Text::TextError; // `Variable` returns an optional: a variable that is not set is `none`, which is different // from one set to the empty string. func Show(name: char8[..]) { match Variable(name) { value? => PrintLine("{:<13} = \"{}\"", name, value), none => PrintLine("{:<13} is not set", name) } } func Main() -> ! (IoError | TextError) { var system = SystemAllocator(); let allocator: Allocator = system; // Argument zero is the program itself, as it was started: a name or a path the parent chose, // so it differs from one machine to the next. The real arguments start at one. PrintLine("arguments {}", ArgumentCount() - 1); let program = Path::FromView(Argument(0) ?? OsStringView()); PrintLine("program {}", program.Stem() ?? OsStringView()); var index: uint = 1; for argument in Arguments().Skip(1) { PrintLine("argument {} {}", index, argument); index = index + 1; } // An argument is native text, so it is compared with native text: `OsString::FromText` // turns a literal into the units this system uses. Run `rux run -- --quit` to take this // branch. `Exit` ends the process at once with a status; nothing after it runs. var quit = OsString::FromText(allocator, "--quit")?; let wanted = quit.View(); let first = Argument(1) ?? OsStringView(); if first.Equals(wanted) { PrintLine("leaving early with status 3"); Exit(3); } // A variable this program sets itself, so the output is the same on every machine. The // change is seen by this process and by every child it starts from now on, never by the // parent that started it. Show("LESSON_COLOUR"); SetVariable("LESSON_COLOUR", "teal")?; Show("LESSON_COLOUR"); SetVariable("LESSON_COLOUR", "")?; Show("LESSON_COLOUR"); // `Environment` walks every variable, as `EnvironmentVariable` pairs of name and value. var found = false; var count: uint = 0; var holder = OsString::FromText(allocator, "LESSON_COLOUR")?; let name = holder.View(); for variable in Environment() { count = count + 1; if variable.name.Equals(name) { found = true; } } PrintLine("found in walk {}", found); PrintLine("any at all {}", count > 0); RemoveVariable("LESSON_COLOUR")?; Show("LESSON_COLOUR"); // A name may not contain `=`, since `=` is what ends a name in the environment. match SetVariable("LESSON=COLOUR", "teal") { .Success(_) => PrintLine("a name with = was accepted?"), .Failure(error) if error.kind == IoErrorKind::InvalidInput => PrintLine("LESSON=COLOUR refused as invalid input"), .Failure(error) => fail error } // The process identifier is the system's number for this run, and changes every time. PrintLine("process id {}", CurrentId()); // Returning from `Main` is the ordinary way to finish: a success here is exit status 0, and // a failure passed out with `?` is status 1. // // let home: OsStringView = Variable("HOME"); // error: cannot assign 'OsStringView?' to 'OsStringView' } ``` Besides `Io`, its `Rux.toml` lists `Allocator`, `Path`, `Process` and `Text` under `[Dependencies]`. ## Run it ```sh cd Examples/Systems/Environment rux run ``` ```text arguments 0 program Environment LESSON_COLOUR is not set LESSON_COLOUR = "teal" LESSON_COLOUR = "" found in walk true any at all true LESSON_COLOUR is not set LESSON=COLOUR refused as invalid input process id 14624 ``` The process id on the last line is different on every run. Run `rux run -- --quit` to see the program list its arguments and end early with exit status 3. ## Common mistakes ::mistake **Treating a variable as always set.**:br`Variable` returns an optional, so `let home: OsStringView = Variable("HOME");` is refused: ```text error: cannot assign 'OsStringView?' to 'OsStringView' ``` Match it, or give a fallback with `??`. `HOME` in particular is usually not set at all on Windows, which keeps the same folder in `USERPROFILE`. :: ::mistake **Comparing an optional view with `none`.**:br`Argument(1) == none` does not compile, because views have no `==`. On Windows the message is: ```text error: structural equality for 'OsStringView?' is unavailable because element type 'uint16[..]' has no '==' operator ``` The element type it names is the native unit, so it differs on Linux and macOS. Use `match`, or `ArgumentCount()`. :: ::mistake **Passing a temporary where a reference is wanted.**:br`first.Equals(quit.View())` is refused: ```text error: argument 1 to 'Equals' has type 'OsStringView', but parameter 'other' requires '&OsStringView' ``` Name the view first — `let wanted = quit.View();` — and pass `wanted`. :: ::mistake **Expecting the parent to see a change.**:br`SetVariable` changes this process's environment and its future children's. The shell that ran `rux run` never sees it: when the program ends, the change ends with it. :: ## Try it yourself 1. Run `rux run -- "two words" x` and count the arguments. How does the shell decide where one ends? 2. Print the value of `PATH`, or say that it is not set. Run the program on Windows and Linux if you can: is the separator between directories the same? 3. Count how many environment variables have a name starting with `RUX`. 4. Make `--quit` take a number, so that `rux run -- --quit 5` exits with status 5. Check the status with `echo $?`. ## Learn more - [Process API](https://rux-lang.dev/docs/api/process) — every function in the package - [Path](https://rux-lang.dev/docs/learn/path) — `OsStringView` and the other native-text types - [Fallible main](https://rux-lang.dev/docs/learn/fallible-main) — the exit status of a `Main` that can fail - [The `Main` function](https://rux-lang.dev/docs/lang/functions/main) in the Rux Reference - Next: [Child process](https://rux-lang.dev/docs/learn/child-process), which starts another program and hands it arguments and an environment # Child process ::note **You'll need**: [Environment](https://rux-lang.dev/docs/learn/environment), [Move](https://rux-lang.dev/docs/learn/move), [Input](https://rux-lang.dev/docs/learn/input), [Catch](https://rux-lang.dev/docs/learn/catch) :: Sooner or later a program needs another program: a build tool runs the compiler, an editor runs a formatter, a test runner runs every test in a fresh process so that one crash cannot take down the rest. The program started is a **child process**. It runs on its own, with its own memory, and the two can talk only through what the system connects between them: arguments and an environment on the way in, three standard streams while it runs, and an exit status at the end. ```mermaid flowchart LR parent["Parent"] -- "arguments
environment" --> child["Child"] parent -- "standard input" --> child child -- "standard output
standard error" --> parent child -- "exit status" --> parent ``` The `Process` package starts one with a `Command`: ```rux import Process::{ Argument, ArgumentCount, Command, Exit, Stdio, Variable }; ``` ## A program that is its own child A lesson that runs `ls` or `dir` would print something different on every system and every machine. So this program starts *itself*. [Argument zero](https://rux-lang.dev/docs/learn/environment) is how it was started, and a `Command` built from it starts the same executable again. An extra argument — the **role** — tells the second copy which part to play: ```rux func Myself(allocator: Allocator, role: char8[..]) -> Command { var command = Command::FromNative(allocator, Argument(0) ?? OsStringView()); command.Argument(role); return <-command; } ``` `Command(allocator, program)` takes a UTF-8 name and looks it up through `PATH` when it names no directory; `Command::FromNative` takes native text as it is, which suits a value that came from the system. `Argument` adds one argument — it arrives in the child exactly as given, spaces and quotes included, with no shell in between. A `Command` owns its parts and is not copied, so `Myself` hands it back with `<-`. `Main` then starts by asking which copy it is: ```rux if ArgumentCount() > 1 { Exit(RunChild(Argument(1) ?? OsStringView())); } ``` ## Three ways to start it | Method | Waits for the child? | Returns | Use it when | | --------- | -------------------- | -------------------------- | ---------------------------- | | `Run` | yes | `ExitStatus ! IoError` | only the outcome matters | | `Capture` | yes | `CapturedOutput ! IoError` | you want what it printed | | `Spawn` | no | `Child ! IoError` | you talk to it while it runs | All three fail with an `IoError` when the program cannot be started at all — a missing program is `NotFound`, not a child that exits with an error code. An `ExitStatus` says how the child finished. `Success()` is true only for exit code zero. `Code()` is an optional, because on Linux and macOS a child ended by a signal has no code — `Signal()` gives the signal instead: ```rux let failing = Myself(allocator, "fail"); let status = failing.Run()?; PrintLine("fail: success {}, code {}", status.Success(), status.Code() ?? -1); ``` `Capture` keeps both output streams whole, reading standard error on a second thread while it reads standard output, so a child that fills one pipe while the other is being read cannot get stuck. `Output()` and `Error()` are the bytes, which a careful program does not assume are text: ```rux let greeting = Myself(allocator, "greet"); let captured = greeting.Capture(allocator)?; PrintLine("greet: success {}", captured.Status().Success()); PrintLine(" output [{}]", captured.Output()); PrintLine(" error [{}]", captured.Error()); ``` ## An environment for one child `SetVariable` on a command, unlike the process-wide one from the last lesson, changes only that child's environment. `RemoveVariable` and `ClearEnvironment` take variables away from it, and `Directory` sets the folder it starts in: ```rux var colour = Myself(allocator, "colour"); colour.SetVariable("LESSON_COLOUR", "teal"); let painted = colour.Capture(allocator)?; ``` The child sees `teal`; this process still has no such variable. ## Pipes `Stdio` says what each of the child's streams is connected to: `Inherit`, this process's own (the default), `Null`, nothing at all, or `Pipe`, a new pipe whose other end this process takes from the `Child`: ```rux var shout = Myself(allocator, "shout"); shout.StandardInput(Stdio::Pipe); shout.StandardOutput(Stdio::Pipe); var child = shout.Spawn()?; var input = child.TakeInput() ?? fail IoError::Of(IoErrorKind::Other); var output = child.TakeOutput() ?? fail IoError::Of(IoErrorKind::Other); WriteAll(input, "quiet words\nstill quiet\n")?; input.Close(); ``` The ends are ordinary `Io` streams — a `PipeWriter` and a `PipeReader` — so `WriteAll` and `ReadLineFrom` work on them as on a file. `TakeInput` returns an optional because there is only a pipe to take when one was asked for, and only once. Closing the input is how the child learns that no more is coming: its `ReadLine` then reports the end, and it exits. ## Waiting, and not waiting `Wait` blocks until the child finishes. `TryWait` only asks: it returns `ExitStatus?`, `none` while the child is still running. `Kill` ends a child that would otherwise never finish: ```rux var waiting = Myself(allocator, "wait"); waiting.StandardInput(Stdio::Pipe); var sleeper = waiting.Spawn()?; PrintLine("wait: finished yet? {}", sleeper.TryWait()? != none); sleeper.Kill()?; PrintLine(" killed, success {}", sleeper.Wait()?.Success()); ``` Always `Wait` for a child you `Spawn`. A child dropped without waiting keeps running, and on Linux and macOS its status lingers with the system until this process ends. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Systems/ChildProcess){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // A program can start another program: a child process. The child runs on its own, with its own // memory, and the two can talk only through what the system connects between them — the child's // arguments and environment on the way in, its three standard streams while it runs, and its // exit status at the end. // // `Command` describes the child: the program, its arguments, environment changes and where each // stream goes. `Run` starts it and waits, `Spawn` starts it and hands back a `Child` to talk to, // and `Capture` starts it and keeps everything it writes. Starting a program can fail — it may // not exist — so each returns a fallible with an `IoError`. // // To read the same on Windows, Linux and macOS, this program is its own child. Argument zero is // how it was started, so a `Command` built from it starts this executable again; an extra // argument tells that second copy which part to play. import Allocator::{ Allocator, SystemAllocator }; import Io::{ IoError, IoErrorKind, Print, PrintLine, ReadLine, ReadLineFrom, StandardError, WriteAll }; import Path::{ OsString, OsStringView }; import Process::{ Argument, ArgumentCount, Command, Exit, Stdio, Variable }; import Text::{ StringBuilder, ToAsciiUpper }; // Whether a native argument is the ASCII word `text`. func Is(argument: OsStringView, text: char8[..]) -> bool { var holder = OsString::FromText(SystemAllocator(), text) catch { else => return false }; let wanted = holder.View(); return argument.Equals(wanted); } // The child's side. Each part is a few lines of an ordinary program. func RunChild(role: OsStringView) -> int32 { if Is(role, "greet") { Print("hello from the child"); var errors = StandardError::Acquire(); WriteAll(errors, "and a note on standard error") catch { else => return 2 }; return 0; } if Is(role, "fail") { return 7; } if Is(role, "colour") { Print("{}", Variable("LESSON_COLOUR") ?? OsStringView()); return 0; } if Is(role, "shout") { // Reads lines until its input ends, and writes each back in capitals. var line = StringBuilder(SystemAllocator()); while true { ReadLine(line) catch { else => return 0 }; let loud = ToAsciiUpper(SystemAllocator(), line.View()) catch { else => return 3 }; PrintLine("{}", loud); line.Clear(); } } if Is(role, "wait") { // Waits for a line that never comes, until it is killed. var line = StringBuilder(SystemAllocator()); ReadLine(line) catch { else => return 0 }; } return 99; } // A command that starts this same program in `role`. func Myself(allocator: Allocator, role: char8[..]) -> Command { var command = Command::FromNative(allocator, Argument(0) ?? OsStringView()); command.Argument(role); return <-command; } func Main() -> ! IoError { if ArgumentCount() > 1 { Exit(RunChild(Argument(1) ?? OsStringView())); } var system = SystemAllocator(); let allocator: Allocator = system; // `Run` waits for the child and returns how it finished. A status is a success only for // exit code zero; `Code` is optional because a child ended by a signal has none. let failing = Myself(allocator, "fail"); let status = failing.Run()?; PrintLine("fail: success {}, code {}", status.Success(), status.Code() ?? -1); // `Capture` keeps both output streams and the status. The bytes are only bytes: a child may // write anything, so they are shown, not trusted to be text. let greeting = Myself(allocator, "greet"); let captured = greeting.Capture(allocator)?; PrintLine("greet: success {}", captured.Status().Success()); PrintLine(" output [{}]", captured.Output()); PrintLine(" error [{}]", captured.Error()); // Environment changes made on the command reach only that child. var colour = Myself(allocator, "colour"); colour.SetVariable("LESSON_COLOUR", "teal"); let painted = colour.Capture(allocator)?; PrintLine("colour: the child saw [{}]", painted.Output()); PrintLine(" this process sees [{}]", Variable("LESSON_COLOUR") ?? OsStringView()); // Pipes: the parent writes to the child's input and reads its output while it runs. // Closing the input is how the child learns that no more is coming. var shout = Myself(allocator, "shout"); shout.StandardInput(Stdio::Pipe); shout.StandardOutput(Stdio::Pipe); var child = shout.Spawn()?; var input = child.TakeInput() ?? fail IoError::Of(IoErrorKind::Other); var output = child.TakeOutput() ?? fail IoError::Of(IoErrorKind::Other); WriteAll(input, "quiet words\nstill quiet\n")?; input.Close(); var line = StringBuilder(allocator); while true { ReadLineFrom(output, line) catch { error if error.IsEnd() => break, error => fail error }; PrintLine("shout: {}", line.View()); line.Clear(); } PrintLine(" success {}", child.Wait()?.Success()); // `TryWait` asks without waiting; `Kill` ends a child that would never finish. var waiting = Myself(allocator, "wait"); waiting.StandardInput(Stdio::Pipe); var sleeper = waiting.Spawn()?; PrintLine("wait: finished yet? {}", sleeper.TryWait()? != none); sleeper.Kill()?; PrintLine(" killed, success {}", sleeper.Wait()?.Success()); // A program that does not exist fails to start; it is not a child that exits. let missing = Command(allocator, "no-such-program-anywhere"); match missing.Run() { .Success(_) => PrintLine("missing: it ran?"), .Failure(error) => PrintLine("missing: not found? {}", error.kind == IoErrorKind::NotFound) } // Starting a child can fail, so its status is only reachable through the fallible: // // let status = failing.Run(); // PrintLine("{}", status.Success()); // error: type 'ExitStatus ! IoError' has no field 'Success' // // And an exit status is an `int32`, the width every system reports: // // func RunChild(role: OsStringView) -> int { ... } // Exit(RunChild(role)); // error: argument 1 to 'Exit' has type 'int', but parameter 'code' requires 'int32' } ``` Besides `Io`, its `Rux.toml` lists `Allocator`, `Path`, `Process` and `Text` under `[Dependencies]`. ## Run it ```sh cd Examples/Systems/ChildProcess rux run ``` ```text fail: success false, code 7 greet: success true output [hello from the child] error [and a note on standard error] colour: the child saw [teal] this process sees [] shout: QUIET WORDS shout: STILL QUIET success true wait: finished yet? false killed, success false missing: not found? true ``` Every line is the same on every system. The child writes its greeting and its note without a final newline, which is why the brackets close on the same line. ## Common mistakes ::mistake **Reading the status of a start that may have failed.**:br`Run` returns `ExitStatus ! IoError`, so `let status = failing.Run();` followed by `status.Success()` is refused: ```text error: type 'ExitStatus ! IoError' has no field 'Success' ``` Handle the failure to start first, with `?` or a `match`. :: ::mistake **Exiting with an `int`.**:br An exit status is an `int32` on every system. With `RunChild` declared `-> int`, `Exit(RunChild(role))` fails with: ```text error: argument 1 to 'Exit' has type 'int', but parameter 'code' requires 'int32' ``` :: ::mistake **Copying a command.**:br A `Command` owns its parts, so `let again = command;` is refused: ```text error: move-only value 'command' requires an explicit '<-' in initialization ``` A command can be started more than once, so there is rarely a need for a second one: call `Run` on it again. :: ::mistake **Forgetting to close the input.**:br A child that reads until its input ends will wait forever while the parent keeps the `PipeWriter` open — and a parent reading the child's output waits with it. Call `Close` on the writer once everything is written. `Wait` closes it too, but only if the writer was never taken. :: ## Try it yourself 1. Add a role that prints its arguments, and start it with an argument containing spaces and quotes, such as `say "hi"`. Does it arrive whole? 2. Give the `greet` child `StandardError(Stdio::Null)` and `Run` it instead of capturing it. What appears on the screen? 3. Start a real program found through `PATH` — `git --version` if you have Git — and print its captured output. What happens on a machine without it? 4. Make the `shout` child exit with status 1 when a line is empty, and report the status in the parent. ## Learn more - [Process API](https://rux-lang.dev/docs/api/process) — `Command`, `Child`, `ExitStatus` and `CapturedOutput` - [Environment](https://rux-lang.dev/docs/learn/environment) — the arguments and environment a child receives - [Input](https://rux-lang.dev/docs/learn/input) — `ReadLine`, which the child uses on its standard input - [Move](https://rux-lang.dev/docs/learn/move) — why a `Command` is returned with `<-` - [Thread](https://rux-lang.dev/docs/learn/thread) — a second line of work inside one process, instead of a second process # Command line ::note **You'll need**: [Environment](https://rux-lang.dev/docs/learn/environment), [Pointer](https://rux-lang.dev/docs/learn/pointer), [Writable slice](https://rux-lang.dev/docs/learn/writable-slice), [Interface parameter](https://rux-lang.dev/docs/learn/interface-parameter) :: The [Environment](https://rux-lang.dev/docs/learn/environment) lesson read arguments one at a time. That is fine for one flag, and a chore for a real tool: `-v` and `--verbose` must mean the same, `-vv` must mean "more verbose", `--priority=1`, `--priority 1`, `-p 1` and `-p1` must all give `1`, `--` must end the options — and every mistake deserves a message that names the argument at fault, plus a `--help` that lists everything. The `CommandLine` package does all of that from a **description** of what the command accepts. You describe; it parses, checks, and writes the help: ```rux import CommandLine::{ Command, CommandSpec, Flag, OptionSpec, Optional, Parse, Parsed, ParseProcess, PositionalSpec, Remaining, Required, ValueOption, WriteUsage }; ``` ```mermaid flowchart LR spec["CommandSpec
the description"] --> parse["Parse"] args["arguments"] --> parse parse -- "Success" --> parsed["Parsed
Has, Count, Value,
Positional, Integer"] parse -- "Failure" --> error["CommandLineError"] spec --> help["WriteHelp
WriteUsage"] ``` ## Describing a command A command is a `CommandSpec`: a name, a one-line summary, and then — each added with a `With` method — a version, options, positional arguments and subcommands. Options and positionals are made by small functions: | Function | Accepts | Help shows | | ------------------------------------ | ------------------------------------------ | ---------------- | | `Flag(name, short, help)` | `--all`, `-a`, present or absent | `-a, --all` | | `ValueOption(name, short, value, …)` | `--priority 1`, `--priority=1`, `-p1` | `--priority ` | | `Required(name, help)` | exactly one positional argument | `` | | `Optional(name, help)` | at most one | `[filter]` | | `Remaining(name, help)` | every positional argument left, maybe none | `[tags...]` | The lesson's command is a little to-do tool with two subcommands, each with options and positionals of its own: ```rux let addOptions: OptionSpec[1] = [ValueOption("priority", 'p', "N", "How urgent, 1 to 5")]; let addPositionals: PositionalSpec[2] = [ Required("title", "What to do"), Remaining("tags", "Words to file it under") ]; let listOptions: OptionSpec[1] = [Flag("all", 'a', "Include finished items")]; let listPositionals: PositionalSpec[1] = [Optional("filter", "Only items with this tag")]; let commands: CommandSpec[2] = [ Command("add", "Add an item").WithOptions(addOptions[..]).WithPositionals(addPositionals[..]), Command("list", "Show the items").WithOptions(listOptions[..]) .WithPositionals(listPositionals[..]) ]; let options: OptionSpec[1] = [Flag("verbose", 'v', "Say more; repeat for even more")]; let todo = Command("todo", "Keeps a to-do list").WithVersion("1.0.0") .WithOptions(options[..]).WithCommands(commands[..]); ``` Nothing here allocates. A spec only **borrows** its arrays and text, so the arrays are locals that must live as long as the spec and every parse made from it. Every command also understands `-h` and `--help`, and one with a version `-V` and `--version`, without declaring them. ## Parsing `Parse(@spec, arguments)` checks a list of `OsStringView` arguments — without the program's name — and returns `Parsed ! CommandLineError`. `ParseProcess(@spec)` does the same with the program's own arguments. Both take the spec by pointer, because the parse keeps pointing at it. To print the same thing on every run, the lesson parses fixed lines rather than real ones. `Split` cuts a line at its spaces into native views — a crude shell, enough for words without quotes: ```rux match Parse(spec, words[..count]) { .Success(parsed) => Describe(parsed, screen)?, .Failure(error) => PrintLine(" error: {}", error) } ``` A `CommandLineError` describes itself through `Display`, in lower case and naming the argument as it was typed — `unknown option '-x'`, `missing argument <title>` — ready to follow a program's own `error: `. ## Asking the parse A `Parsed` holds nothing but where the arguments are, and each question walks them again: | Question | Returns | Answers | | --------------------- | --------------------------- | ------------------------------------------------- | | `Has("all")` | `bool` | was the option given at all? | | `Count("verbose")` | `uint` | how many times — `-vv` is 2 | | `Value("priority")` | `OsStringView?` | the option's value; the last one when repeated | | `Positional("title")` | `OsStringView?` | the positional argument | | `Positionals("tags")` | an iterator | every argument a `Remaining` positional took | | `Integer("priority")` | `int64? ! CommandLineError` | the value as a number — `none` if not given | | `Subcommand()` | `Parsed?` | the parse of everything after the subcommand name | `Integer` is the one question that can fail: `todo add -p high milk` is a valid command line — `-p` has a value — but `high` is not a number, so the error appears only when the program asks for one: ```rux match sub.Integer("priority") { .Success(priority) => PrintLine(" add [{}] priority {}, verbosity {}", sub.Positional("title") ?? OsStringView(), priority ?? 3, verbose), .Failure(error) => PrintLine(" error: {}", error) } ``` ## Subcommands A command with subcommands takes its first positional argument as the subcommand's name, and everything after the name belongs to the subcommand. So in `-vv add --priority=1 milk shop home`, `-vv` is the top-level `todo`'s option and `--priority` is `add`'s. `CommandName()` names the subcommand chosen, and `Subcommand()` is its own `Parsed`, already checked with the first. A slice has no `==`, so `IsCommand` compares the name as two `StringView`s: ```rux func IsCommand(parsed: &Parsed, word: char8[..]) -> bool { let name = StringView::FromValidated(parsed.CommandName() ?? ""); let wanted = StringView::FromValidated(word); return name.Equals(wanted); } ``` ## Help for free Asking for help is a successful parse: `HelpRequested()` says so, and succeeds even when a required argument is missing. `WriteHelp` writes the help from the description into any `TextWriter`; `ConsoleWriter` is the one over standard output. On a subcommand's parse, the usage line names the command above it — `todo add [options] <title> [tags...]`. `WriteUsage` writes only the usage line, the conventional reply to a mistake: ```rux match ParseProcess(@todo) { .Success(parsed) => Describe(parsed, screen)?, .Failure(error) => { PrintLine("error: {}", error); WriteUsage(todo, screen)?; } } ``` Give the program real arguments to see it take the first branch: ```sh rux run -- -v add --priority 2 "buy milk" home ``` The last lines then read `add [buy milk] priority 2, verbosity 1` and `tag home`: the shell kept `buy milk` together. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Systems/CommandLine){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // Reading arguments one by one, as the Environment lesson did, gets tedious quickly: options // in any order, `-v` and `--verbose` meaning the same, `--jobs=4` and `--jobs 4` too, and a // helpful message for every mistake. The `CommandLine` package does it from a description. // // A program describes what it accepts as plain values: a `CommandSpec` with its options — // `Flag`s that are present or not, `ValueOption`s that take a value — its positional // arguments — `Required`, `Optional` or `Remaining` — and its subcommands. `Parse` checks a // list of arguments against that description and returns `Parsed ! CommandLineError`; the // parse then answers questions such as `Has`, `Count`, `Value` and `Positional`. The same // description writes the help text, so the two can never disagree. // // `ParseProcess` reads the program's own arguments. To print the same thing on every run, this // lesson mostly parses fixed lists instead, written as one string and split at the spaces. import Allocator::{ Allocator, SystemAllocator }; import CommandLine::{ Command, CommandSpec, Flag, OptionSpec, Optional, Parse, Parsed, ParseProcess, PositionalSpec, Remaining, Required, ValueOption, WriteUsage }; import Io::{ ConsoleWriter, IoError, PrintLine }; import Path::{ OsString, OsStringView }; import Text::{ FormatError, StringView, TextError, TextWriter }; // Splits native text at its spaces, the way a shell splits what you type, into `words`. func Split(text: OsStringView, words: var OsStringView[..]) -> uint { let units = text.Units(); var count: uint = 0; var start: uint = 0; for at in 0..=units.length { if at == units.length || units[at] as uint32 == 0x20 { if at > start && count < words.length { words[count] = OsStringView::FromUnits(units[start..at]); count = count + 1; } start = at + 1; } } return count; } func IsCommand(parsed: &Parsed, word: char8[..]) -> bool { let name = StringView::FromValidated(parsed.CommandName() ?? ""); let wanted = StringView::FromValidated(word); return name.Equals(wanted); } // What the program would do with a successful parse. Asking for help is a successful parse too, // and `WriteHelp` on a subcommand's parse names the command above it. func Describe(parsed: &Parsed, screen: &var TextWriter) -> ! FormatError { if parsed.HelpRequested() { parsed.WriteHelp(screen)?; return; } let verbose = parsed.Count("verbose"); let sub = parsed.Subcommand() ?? return; if sub.HelpRequested() { sub.WriteHelp(screen)?; return; } if IsCommand(parsed, "add") { // `Integer` reads a value as a number, and fails when it is not one. match sub.Integer("priority") { .Success(priority) => PrintLine(" add [{}] priority {}, verbosity {}", sub.Positional("title") ?? OsStringView(), priority ?? 3, verbose), .Failure(error) => PrintLine(" error: {}", error) } for tag in sub.Positionals("tags") { PrintLine(" tag {}", tag); } } else if IsCommand(parsed, "list") { PrintLine(" list, all {}, filter [{}]", sub.Has("all"), sub.Positional("filter") ?? OsStringView()); } } func Try(spec: *CommandSpec, allocator: Allocator, line: char8[..]) -> ! (TextError | FormatError) { PrintLine("$ todo {}", line); var holder = OsString::FromText(allocator, line)?; var words: OsStringView[8] = [OsStringView(); 8]; let count = Split(holder.View(), words[..]); // `ConsoleWriter` is a `TextWriter` over standard output, for the help text. var failure: IoError? = none; var console = ConsoleWriter(@failure); let screen: &var TextWriter = console; match Parse(spec, words[..count]) { .Success(parsed) => Describe(parsed, screen)?, .Failure(error) => PrintLine(" error: {}", error) } } func Main() -> ! (TextError | FormatError) { var system = SystemAllocator(); let allocator: Allocator = system; // The description: two subcommands, each with its own options and positionals. let addOptions: OptionSpec[1] = [ValueOption("priority", 'p', "N", "How urgent, 1 to 5")]; let addPositionals: PositionalSpec[2] = [ Required("title", "What to do"), Remaining("tags", "Words to file it under") ]; let listOptions: OptionSpec[1] = [Flag("all", 'a', "Include finished items")]; let listPositionals: PositionalSpec[1] = [Optional("filter", "Only items with this tag")]; let commands: CommandSpec[2] = [ Command("add", "Add an item").WithOptions(addOptions[..]).WithPositionals(addPositionals[..]), Command("list", "Show the items").WithOptions(listOptions[..]) .WithPositionals(listPositionals[..]) ]; let options: OptionSpec[1] = [Flag("verbose", 'v', "Say more; repeat for even more")]; let todo = Command("todo", "Keeps a to-do list").WithVersion("1.0.0") .WithOptions(options[..]).WithCommands(commands[..]); // Lines that parse, and lines that do not. Try(@todo, allocator, "add milk")?; Try(@todo, allocator, "-vv add --priority=1 milk shop home")?; Try(@todo, allocator, "list -a home")?; Try(@todo, allocator, "add -p high milk")?; Try(@todo, allocator, "add")?; Try(@todo, allocator, "add -x milk")?; Try(@todo, allocator, "remove milk")?; Try(@todo, allocator, "list home work")?; // The help text, written from the same description, for the program and for a subcommand. Try(@todo, allocator, "--help")?; Try(@todo, allocator, "add -h")?; // And this run's own arguments. `rux run` passes none, and a command is required, so this // ends the way a real program would: the reason, then the usage line. PrintLine("$ todo"); var failure: IoError? = none; var console = ConsoleWriter(@failure); let screen: &var TextWriter = console; match ParseProcess(@todo) { .Success(parsed) => Describe(parsed, screen)?, .Failure(error) => { PrintLine("error: {}", error); WriteUsage(todo, screen)?; } } // A slice cannot be compared with `==`, which is why `IsCommand` compares `StringView`s: // // let name = parsed.CommandName() ?? ""; // if name == "add" { ... } // error: operator '==' is not defined for slice type 'char8[..]' } ``` Besides `Io`, its `Rux.toml` lists `Allocator`, `CommandLine`, `Path` and `Text` under `[Dependencies]`. ## Run it ```sh cd Examples/Systems/CommandLine rux run ``` ```text $ todo add milk add [milk] priority 3, verbosity 0 $ todo -vv add --priority=1 milk shop home add [milk] priority 1, verbosity 2 tag shop tag home $ todo list -a home list, all true, filter [home] $ todo add -p high milk error: invalid value 'high' for 'priority' $ todo add error: missing argument <title> $ todo add -x milk error: unknown option '-x' $ todo remove milk error: unknown command 'remove' $ todo list home work error: unexpected argument 'work' $ todo --help Keeps a to-do list Usage: todo [options] <command> Options: -v, --verbose Say more; repeat for even more -h, --help Print this help -V, --version Print the version Commands: add Add an item list Show the items $ todo add -h Add an item Usage: todo add [options] <title> [tags...] Arguments: <title> What to do [tags...] Words to file it under Options: -p, --priority <N> How urgent, 1 to 5 -h, --help Print this help $ todo error: a command is required Usage: todo [options] <command> ``` ## Common mistakes ::mistake **Passing the spec by value.**:br`ParseProcess(todo)` is refused: ```text error: argument 1 to 'ParseProcess' has type 'CommandSpec', but parameter 'spec' requires '*CommandSpec' ``` The parse keeps a pointer to the spec, so pass its address: `ParseProcess(@todo)`. :: ::mistake **Comparing a subcommand's name with `==`.**:br`let name = parsed.CommandName() ?? "";` followed by `if name == "add"` fails with: ```text error: operator '==' is not defined for slice type 'char8[..]' ``` Comparing two slices would compare where they are, not what they hold. Compare `StringView`s with `Equals`, as `IsCommand` does. :: ::mistake **A spec that outlives its arrays.**:br`WithOptions(options[..])` borrows the array; it does not copy it. Build the arrays in a function, return only the `CommandSpec`, and the spec points at memory that is gone — which compiles without a word. Keep the arrays and the spec in the same scope, as `Main` does here. :: ::mistake **Treating a parse as proof that a value is valid.**:br`Parse` checks the shape — an option has its value, a required argument is there — but not what the values mean. `-p high` parses; only `Integer` notices it is not a number. Check values when you read them. :: ## Try it yourself 1. Run `rux run -- --version`. Nothing is printed: make `Describe` notice `VersionRequested()` and print `todo 1.0.0` with `WriteVersion`. 2. Give `add` a `--due DATE` option, and print it when it is given. What does the help look like now? 3. Make `add` refuse a priority outside 1 to 5 with a message of your own. 4. Add a third subcommand, `done <number>`, that reads its number with `Integer`. ## Learn more - [CommandLine API](https://rux-lang.dev/docs/api/commandline) — every builder, query and error case - [Environment](https://rux-lang.dev/docs/learn/environment) — the raw arguments this package reads - [Pointer](https://rux-lang.dev/docs/learn/pointer) — why `Parse` takes `@todo` - [Interface parameter](https://rux-lang.dev/docs/learn/interface-parameter) — the `&var TextWriter` the help is written to - [Grep](https://rux-lang.dev/docs/learn/grep) — the checkpoint project, a command-line tool built on this package # Log ::note **You'll need**: [Interface value](https://rux-lang.dev/docs/learn/interface-value), [Slice](https://rux-lang.dev/docs/learn/slice), [Enum](https://rux-lang.dev/docs/learn/enum), [JSON](https://rux-lang.dev/docs/learn/json) :: A program that runs for a long time — a server, a background job, a build — needs a diary: a line for each thing worth knowing later, read when something has gone wrong and nobody was watching. `PrintLine` can write such lines, but a log wants two things more. Each record has a **level**, so the routine ones can be switched off without touching the code. And its details are **fields** with names and types — `port=8080`, not "listening on port 8080" — so a tool can search, filter and count them. The `Log` package builds those records: ```rux import Log::{ Enabled, Field, Info, Level, LogFormat, Logger, SetFormat, SetLevel, SetTimestamps, Warn }; ``` ## A logger A `Logger` writes records to any `Io::Writer`: a file, a socket, a pipe — or, here, standard output, so you can see them: ```rux var log = Logger::New(allocator, StandardOut::Acquire(), LogFormat::Text); log.SetTimestamps(false); ``` Every record normally starts with the time, in RFC 3339 and UTC to the millisecond, such as `2026-10-15T09:41:07.312Z`. The lesson turns times off so that its output is the same on every run; a real program leaves them on, unless something downstream adds its own, as a service manager's journal does. Logging **never fails**. A record that cannot be written is dropped, and the logger keeps the first failure for `Failure()` to report — a log that stops the program when the disk fills up would be worse than no log. ## Records and fields A record is a level, a message and a slice of fields. `Field` has one constructor for each type a value can have: | Constructor | Value type | Written as | | ------------------------------ | ---------- | ------------- | | `Field::Text("path", "/a b")` | text | `path="/a b"` | | `Field::Integer("status", -1)` | `int64` | `status=-1` | | `Field::Unsigned("port", 80)` | `uint64` | `port=80` | | `Field::Float("ratio", 0.5)` | `float64` | `ratio=0.5` | | `Field::Boolean("tls", true)` | `bool` | `tls=true` | ```rux log.Info("server started", [Field::Unsigned("port", 8080), Field::Boolean("tls", false)]); log.Warn("slow request", [Field::Text("path", "/search"), Field::Float("seconds", 2.5)]); log.Error("cannot open file", [Field::Text("name", "my notes.txt")]); ``` In text, a value with a space, a quote or `=` in it is quoted, and a line break is written as `\n`, so a record is always exactly one line — even when a message comes from somewhere you do not control. ## Levels The levels run from the finest detail to the most serious: | Level | For | | ------- | ------------------------------------------------ | | `Trace` | following a program step by step | | `Debug` | diagnosing a problem | | `Info` | the ordinary progress of a program — the default | | `Warn` | something unexpected that the program survived | | `Error` | something that failed | A logger writes records at its level and above. A record below it is dropped before any of it is built, and `Enabled` asks the question first — worth it when a field is costly to work out: ```rux log.Debug("cache lookup", [Field::Text("key", "user:7")]); PrintLine("debug enabled? {}", log.Enabled(Level::Debug)); log.SetLevel(Level::Debug); log.Debug("cache lookup", [Field::Text("key", "user:7")]); ``` The first `Debug` writes nothing; the second, after `SetLevel`, does. A build can go further. The `LogLevel` define — `rux run --define LogLevel=info`, or `LogLevel = "info"` under `[Build.Defines]` in `Rux.toml` — drops everything below that level whatever a logger is set to, so the second `Debug` disappears too. ## Context `SetContext` gives a logger fields that start every record from then on. A server handling a request sets the request's identifier once, and every line it logs while handling it can be found by that one value: ```rux let context = [Field::Text("request", "r-42")]; log.SetContext(context[..]); log.Info("handled", [Field::Integer("status", 200)]); ``` The logger borrows the slice, so `context` must outlive the records that use it. ## Text or JSON lines `LogFormat::Text` is for people. `LogFormat::JsonLines` is for programs: one JSON object per line, with `level` and `message` members followed by the fields, their types intact — a log collector reads it without guessing where a value ends: ```text INFO server started port=8080 tls=false {"level":"info","message":"server started","port":8080,"tls":false} ``` ## The process-wide log A program does not need a `Logger` to log. The free functions `Info`, `Warn` and the rest write to **standard error**, with settings of their own — `SetLevel`, `SetFormat`, `SetTimestamps` — that every thread shares. A lock is held only while a finished record is written, so records from different threads never mix within a line: ```rux SetTimestamps(false); SetLevel(Level::Warn); SetFormat(LogFormat::Text); PrintLine("global info enabled? {}", Enabled(Level::Info)); Info("not written: below the level"); Warn("disk almost full", [Field::Unsigned("free-mb", 120)]); ``` Standard error is the right place for a log: it reaches the screen, but stays out of the program's real output, so `rux run > out.txt` captures only what the program printed. ## Logs that do not fill the disk A log file that is only ever appended to grows until the disk is full. `RotatingFile` is a `Writer` that starts a fresh file before a write would take the current one past a size, keeping a few of the older ones as `app.log.1`, `app.log.2` and so on. A record is never split between two files: ```rux var holder = OsString::FromText(allocator, "Bin/app.log")?; var file = RotatingFile::Open(allocator, Path::FromView(holder.View()), 1048576, 3)?; var log = Logger::New(allocator, (@file).Stream(), LogFormat::JsonLines); log.Info("started"); ``` Here the file starts afresh at 1 MiB and three older files are kept. `Stream` lends the logger the file through a pointer, so `file` must stay in place while the logger uses it. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Systems/Log){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // A log is a program's diary: one line for each thing worth knowing later, such as a request // served, a file skipped or a retry. `PrintLine` can write such lines, but a log wants more. Each // record has a level, so the noisy ones can be switched off; and its details are fields with // names and types, `port=8080` rather than prose, so a tool can search and count them. // // The `Log` package builds those records. A `Logger` writes them to any `Io::Writer` — a file, a // socket, or here standard output — as one line of text or one JSON object per line. Logging // never fails: a record that cannot be written is dropped, and the logger remembers the first // failure for `Failure` to report. // // Every record normally starts with the time. This program turns times off so that its output is // the same on every run. import Allocator::{ Allocator, SystemAllocator }; import Io::{ PrintLine, StandardOut }; import Log::{ Enabled, Field, Info, Level, LogFormat, Logger, SetFormat, SetLevel, SetTimestamps, Warn }; func Main() -> int { var system = SystemAllocator(); let allocator: Allocator = system; // A logger over standard output, writing text. Its level starts at `Info`. var log = Logger::New(allocator, StandardOut::Acquire(), LogFormat::Text); log.SetTimestamps(false); // A message, then typed fields. Text with a space or a quote in it is quoted. log.Info("server started", [Field::Unsigned("port", 8080), Field::Boolean("tls", false)]); log.Warn("slow request", [Field::Text("path", "/search"), Field::Float("seconds", 2.5)]); log.Error("cannot open file", [Field::Text("name", "my notes.txt")]); // Levels run Trace, Debug, Info, Warn, Error. Records below the logger's level are dropped // before any of them is built; `Enabled` asks first, for a field that is costly to compute. log.Debug("cache lookup", [Field::Text("key", "user:7")]); PrintLine("debug enabled? {}", log.Enabled(Level::Debug)); log.SetLevel(Level::Debug); log.Debug("cache lookup", [Field::Text("key", "user:7")]); // Context fields start every record from now on — handy for the request being handled. let context = [Field::Text("request", "r-42")]; log.SetContext(context[..]); log.Info("handled", [Field::Integer("status", 200)]); // The same records as JSON lines: one object per line, ready for a log collector. var json = Logger::New(allocator, StandardOut::Acquire(), LogFormat::JsonLines); json.SetTimestamps(false); json.Info("server started", [Field::Unsigned("port", 8080), Field::Boolean("tls", false)]); json.Warn("slow request", [Field::Text("path", "/search"), Field::Float("seconds", 2.5)]); let failed = log.Failure() != none || json.Failure() != none; PrintLine("write failures: {}", failed ? "some" : "none"); // The process-wide log needs no logger: `Info`, `Warn` and the rest write to standard error, // from any thread, with settings of their own. SetTimestamps(false); SetLevel(Level::Warn); SetFormat(LogFormat::Text); PrintLine("global info enabled? {}", Enabled(Level::Info)); Info("not written: below the level"); Warn("disk almost full", [Field::Unsigned("free-mb", 120)]); // A field is built from a key and a value of one type. The value's type picks the function: // // Field::Integer("port", 8080u64) // error: argument 2 to 'Field::Integer' has type 'uint64', but parameter 'value' requires 'int64' return 0; } ``` Besides `Io`, its `Rux.toml` lists `Allocator` and `Log` under `[Dependencies]`. ## Run it ```sh cd Examples/Systems/Log rux run ``` ```text INFO server started port=8080 tls=false WARN slow request path=/search seconds=2.5 ERROR cannot open file name="my notes.txt" debug enabled? false DEBUG cache lookup key=user:7 INFO handled request=r-42 status=200 {"level":"info","message":"server started","port":8080,"tls":false} {"level":"warn","message":"slow request","path":"/search","seconds":2.5} write failures: none global info enabled? false ``` The program also writes one record to standard error, through the process-wide log, which the block above leaves out: ```text WARN disk almost full free-mb=120 ``` ## Common mistakes ::mistake **A field of the wrong type.**:br The constructor decides the type, so a `uint64` must go through `Unsigned`. `Field::Integer("port", 8080u64)` fails with: ```text error: argument 2 to 'Field::Integer' has type 'uint64', but parameter 'value' requires 'int64' ``` :: ::mistake **A logger declared with `let`.**:br Logging changes the logger — it builds each record in a buffer it owns — so `let log = Logger::New(…)` followed by `log.Info("x")` is refused: ```text error: cannot call 'Info' on immutable 'log' ``` Declare it with `var`. :: ::mistake **One field without brackets.**:br The fields are a slice, even when there is only one. `Info("started", Field::Unsigned("port", 8080))` fails with: ```text error: no matching overload for 'Info' with argument types (char8[..], Field) ``` Write `[Field::Unsigned("port", 8080)]`. :: ::mistake **Looking for the process-wide log on standard output.**:br`Info` and `Warn` without a logger write to standard error. Redirecting the output with `>` does not capture them, and a test that reads standard output does not see them. :: ## Try it yourself 1. Turn timestamps back on for `log` and run the program twice. Which part of each line changes? 2. Make a `Logger` over `StandardError::Acquire()` in JSON lines, and run the program with `rux run 2> log.txt`. What ends up in the file? 3. Log a message with a line break in it, such as `"first\nsecond"`, in both formats. How is it kept on one line? 4. Write a log to `Bin/app.log` through a `RotatingFile` with a limit of 200 bytes and one older file, log twenty records, and look at both files. ## Learn more - [Log API](https://rux-lang.dev/docs/api/log) — `Logger`, `Field`, `Level`, `RotatingFile` and the process-wide functions - [Interface value](https://rux-lang.dev/docs/learn/interface-value) — the `Writer` a logger keeps - [JSON](https://rux-lang.dev/docs/learn/json) — the format of a `JsonLines` record - [Define](https://rux-lang.dev/docs/learn/define) — compile-time values such as `LogLevel` - [Atomic file](https://rux-lang.dev/docs/learn/atomic-file) and [Buffered I/O](https://rux-lang.dev/docs/learn/buffered-io) — other ways to write files # IP addresses ::note **You'll need**: [Optional](https://rux-lang.dev/docs/learn/optional), [Presence](https://rux-lang.dev/docs/learn/presence), [Struct](https://rux-lang.dev/docs/learn/struct), [Bitwise](https://rux-lang.dev/docs/learn/bitwise) :: Before two programs can talk over a network, one has to name the other. The name is an **IP address**, and once a port is added, a **socket address**. This lesson reads, writes and sorts both, with no network involved — they are plain values, and the next two lessons put them to work: ```rux import Net::{ IpAddress, Ipv4Address, Ipv6Address, SocketAddress }; ``` ## Two kinds of address | Kind | Size | Written as | Example | | ---- | -------- | ------------------------------------------------- | -------------- | | IPv4 | 4 bytes | four decimal numbers from 0 to 255 | `192.168.1.20` | | IPv6 | 16 bytes | eight groups of hex digits; `::` for one zero run | `2001:db8::1` | IPv4 has room for about four billion addresses, which the world ran out of long ago; IPv6 has room for 3.4 × 10³⁸. Both are in use side by side, so `Net` has a type for each — `Ipv4Address` and `Ipv6Address`, whose `octets` are public arrays of bytes — and `IpAddress`, which holds either. `IsIpv6()`, `AsIpv4()` and `AsIpv6()` say which, the last two as optionals. ## Reading and writing `IpAddress::Parse` reads either kind, and returns `IpAddress?`: text that is not an address is `none`, with no reason attached. It is strict on purpose: - no leading zeros — `192.168.01.20` is refused, because some systems read `01` as octal; - no shortened IPv4 such as `127.1`, which some C libraries quietly expand to `127.0.0.1`; - no host names — `example.com` is a name to look up, not an address. An address has no `{}` form. `WriteText` writes its one canonical form into a buffer and returns the length — at most 15 characters for IPv4 and 39 for IPv6 — so `buffer[..length]` is the text: ```rux match IpAddress::Parse(text) { address? => { // An IPv6 address takes at most 39 characters, so the buffer always has room. var buffer: char8[39]; let length = address.WriteText(buffer[..]); let version = address.IsIpv6() ? "IPv6" : "IPv4"; PrintLine("{:<26} {} {:<16} {}", text, version, buffer[..length], Kind(address)); }, none => PrintLine("{:<26} not an IP address", text) } ``` The canonical IPv6 form is lower case, drops leading zeros in each group, and shortens the longest run of zero groups to `::`. So `2001:DB8:0:0:0:0:0:1` comes back as `2001:db8::1` — compare addresses, never their text. ## Classifying Some address ranges have a meaning of their own: | Range | Meaning | | ----------------------------------------------- | ----------------------------------------------------------- | | `127.0.0.0/8`, `::1` | loopback: this machine, never on the wire | | `10.0.0.0/8`, `172.16.0.0/12`, `192.168.0.0/16` | private: a home or office network, not the internet | | `fc00::/7` | IPv6's private range, "unique local" | | `fe80::/10` | link-local: only the cable or Wi-Fi you are on | | `0.0.0.0`, `::` | unspecified: "every address of this machine" when listening | `/8` means "the first 8 bits are fixed". `IsLoopback` is built in; the rest are read from the octets, which is where [bitwise operators](https://rux-lang.dev/docs/learn/bitwise) earn their keep — `fc00::/7` fixes only the first seven bits, so the last bit of the first byte is masked off: ```rux if (v6.octets[0] & 0xFE) == 0xFC { return "private network"; } if v6.octets[0] == 0xFE && (v6.octets[1] & 0xC0) == 0x80 { return "link-local"; } ``` Everything else the program calls public, although `2001:db8::/32` — like `192.0.2.0/24` for IPv4 — is in fact set aside for examples in documentation, and never used on a real network. ## Socket addresses An IP address finds a machine; a **port**, a number from 0 to 65535, finds one program on it. Together they are a `SocketAddress`, with public `ip` and `port` fields. Its text is `address:port`, and an IPv6 address goes in brackets so that its colons are not mistaken for the port's — `[::1]:443`, never `::1:443`: ```rux let local = SocketAddress::New(IpAddress::FromIpv4(Ipv4Address::Localhost()), 3000); let text = local.ToString(allocator)?; ``` `ToString` allocates a `String`, so it can fail with a `TextError`; `WriteText` into a buffer cannot. `Equals` compares two addresses — and an IPv4 and an IPv6 address are never equal, even `127.0.0.1` and `::1`, which both mean this machine. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Systems/IpAddress){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // Every machine on a network has an IP address. IPv4 writes one as four numbers from 0 to 255, // `192.168.1.20`; IPv6, which has room for far more machines, writes 16 bytes as eight groups of // hexadecimal digits, `2001:db8:0:0:0:0:0:1`, where `::` may stand for one run of zero groups: // `2001:db8::1`. Add a port, the number that picks one program on that machine, and you have a // socket address: `192.168.1.20:8080`, or `[2001:db8::1]:443`, with IPv6 in brackets so its // colons are not mistaken for the port's. // // The `Net` package keeps these as plain values. `Parse` reads the text and returns an optional: // text that is not an address is `none`. It is strict on purpose — no leading zeros, which some // systems read as octal, and no shortened forms such as `127.1`. `WriteText` writes the one // canonical form into a buffer, IPv6 in lower case with the longest run of zeros shortened. import Allocator::{ Allocator, SystemAllocator }; import Io::PrintLine; import Net::{ IpAddress, Ipv4Address, Ipv6Address, SocketAddress }; import Text::TextError; // What kind of address it is. `IsLoopback` is built in; the private ranges are read from the // octets, which are public fields. func Kind(address: IpAddress) -> char8[..] { if address.IsLoopback() { return "loopback, this machine"; } match address.AsIpv4() { v4? => { let o = v4.octets; if v4.Equals(Ipv4Address::Unspecified()) { return "unspecified, any address"; } let ten = o[0] == 10; let oneSevenTwo = o[0] == 172 && o[1] >= 16 && o[1] <= 31; let oneNineTwo = o[0] == 192 && o[1] == 168; if ten || oneSevenTwo || oneNineTwo { return "private network"; } return "public"; }, none => {} } let v6 = address.AsIpv6() ?? Ipv6Address::Unspecified(); if v6.Equals(Ipv6Address::Unspecified()) { return "unspecified, any address"; } if (v6.octets[0] & 0xFE) == 0xFC { return "private network"; } if v6.octets[0] == 0xFE && (v6.octets[1] & 0xC0) == 0x80 { return "link-local"; } return "public"; } func Show(text: char8[..]) { match IpAddress::Parse(text) { address? => { // An IPv6 address takes at most 39 characters, so the buffer always has room. var buffer: char8[39]; let length = address.WriteText(buffer[..]); let version = address.IsIpv6() ? "IPv6" : "IPv4"; PrintLine("{:<26} {} {:<16} {}", text, version, buffer[..length], Kind(address)); }, none => PrintLine("{:<26} not an IP address", text) } } func ShowSocket(text: char8[..]) { match SocketAddress::Parse(text) { socket? => { var buffer: char8[47]; let length = socket.WriteText(buffer[..]); PrintLine("{:<26} port {:<5} {}", text, socket.port, buffer[..length]); }, none => PrintLine("{:<26} not a socket address", text) } } func Main() -> ! TextError { var system = SystemAllocator(); let allocator: Allocator = system; Show("127.0.0.1"); Show("192.168.1.20"); Show("172.20.0.5"); Show("8.8.8.8"); Show("0.0.0.0"); Show("::1"); Show("2001:DB8:0:0:0:0:0:1"); Show("fd12:3456::7"); Show("fe80::1"); Show("256.1.1.1"); Show("192.168.01.20"); Show("127.1"); Show("example.com"); ShowSocket("127.0.0.1:8080"); ShowSocket("[::1]:443"); ShowSocket("::1:443"); ShowSocket("127.0.0.1:70000"); ShowSocket("localhost:80"); // Built from parts. `ToString` allocates the text, so it can fail. let local = SocketAddress::New(IpAddress::FromIpv4(Ipv4Address::Localhost()), 3000); let text = local.ToString(allocator)?; PrintLine("built from parts {}", text); match SocketAddress::Parse("127.0.0.1:3000") { parsed? => PrintLine("same as 127.0.0.1:3000? {}", local.Equals(parsed)), none => PrintLine("127.0.0.1:3000 did not parse") } // An IPv4 and an IPv6 address are never equal, even for the same machine: let four = IpAddress::FromIpv4(Ipv4Address::Localhost()); let six = IpAddress::FromIpv6(Ipv6Address::Localhost()); PrintLine("127.0.0.1 equals ::1? {}", four.Equals(six)); // An address is not text, and has no `{}` form of its own; `WriteText` is how it is shown. // And `Parse` may find no address, so its result is an optional: // // PrintLine("{}", four); // error: no matching overload for 'PrintLine' with argument types (char8[..], IpAddress) // // let other: IpAddress = IpAddress::Parse("::1"); // error: cannot assign 'IpAddress?' to 'IpAddress' } ``` Besides `Io`, its `Rux.toml` lists `Allocator`, `Net` and `Text` under `[Dependencies]`. ## Run it ```sh cd Examples/Systems/IpAddress rux run ``` ```text 127.0.0.1 IPv4 127.0.0.1 loopback, this machine 192.168.1.20 IPv4 192.168.1.20 private network 172.20.0.5 IPv4 172.20.0.5 private network 8.8.8.8 IPv4 8.8.8.8 public 0.0.0.0 IPv4 0.0.0.0 unspecified, any address ::1 IPv6 ::1 loopback, this machine 2001:DB8:0:0:0:0:0:1 IPv6 2001:db8::1 public fd12:3456::7 IPv6 fd12:3456::7 private network fe80::1 IPv6 fe80::1 link-local 256.1.1.1 not an IP address 192.168.01.20 not an IP address 127.1 not an IP address example.com not an IP address 127.0.0.1:8080 port 8080 127.0.0.1:8080 [::1]:443 port 443 [::1]:443 ::1:443 not a socket address 127.0.0.1:70000 not a socket address localhost:80 not a socket address built from parts 127.0.0.1:3000 same as 127.0.0.1:3000? true 127.0.0.1 equals ::1? false ``` ## Common mistakes ::mistake **Printing an address with `{}`.**:br Addresses do not implement `Display`, so `PrintLine("{}", four)` is refused: ```text error: no matching overload for 'PrintLine' with argument types (char8[..], IpAddress) ``` Write it into a buffer with `WriteText` and print the slice, or use `SocketAddress::ToString`. :: ::mistake **Using a parse as an address.**:br`Parse` may find no address, so `let other: IpAddress = IpAddress::Parse("::1");` fails with: ```text error: cannot assign 'IpAddress?' to 'IpAddress' ``` :: ::mistake **Expecting a host name to parse.**:br`localhost:80` is not a socket address: `localhost` is a name, and turning a name into addresses means asking the system's resolver — `Resolve` in the same package, which the [UDP](https://rux-lang.dev/docs/learn/udp) lesson describes. :: ::mistake **Comparing the text of two addresses.**:br`2001:DB8::1`, `2001:db8:0:0:0:0:0:1` and `2001:0db8::0001` are one address. Parse both and compare with `Equals`. :: ## Try it yourself 1. Add `192.0.2.1` and `2001:db8::1` to a "documentation" class of their own. 2. `Show("100.64.0.1")` prints public. Look up what `100.64.0.0/10` is for, and classify it. 3. Parse a socket address, change its `port` field, and write it back with `WriteText`. 4. Write a function that returns `true` when two socket addresses are on the same machine, whatever their ports. ## Learn more - [Net API](https://rux-lang.dev/docs/api/net) — the address types and everything else in the package - [Presence](https://rux-lang.dev/docs/learn/presence) — matching `address?` and `none` - [Bitwise](https://rux-lang.dev/docs/learn/bitwise) — the masks behind every `/n` range - [Bitwise operators](https://rux-lang.dev/docs/lang/expressions/bitwise) in the Rux Reference - Next: [TCP](https://rux-lang.dev/docs/learn/tcp), which listens and connects at these addresses # TCP ::note **You'll need**: [IP addresses](https://rux-lang.dev/docs/learn/ip-address), [Thread](https://rux-lang.dev/docs/learn/thread), [Input](https://rux-lang.dev/docs/learn/input), [Catch](https://rux-lang.dev/docs/learn/catch) :: **TCP** is how most programs talk over a network: a browser and a web server, a database and its clients, `git` and the forge it pushes to. One side **listens** on a port. The other **connects** to it. From then on each side has a **stream** — it writes bytes in, and the other side reads them out, all of them, in the order they were written. Lost packets are resent and shuffled ones put back in order before your program sees anything. This lesson runs both sides in one program, on the loopback address, which never leaves the machine: ```rux import Net::{ IpAddress, Ipv4Address, ShutdownDirection, SocketAddress, TcpListener, TcpStream }; ``` ```mermaid sequenceDiagram participant C as Client thread participant S as Server, in Main S->>S: Bind 127.0.0.1:0 C->>S: Connect S->>S: Accept C->>S: hello S->>C: HELLO C->>S: Shutdown(Write) S->>S: end of stream ``` ## Listening `TcpListener::Bind` takes the [socket address](https://rux-lang.dev/docs/learn/ip-address) to listen at. Port 0 asks the system for any free port, and `LocalAddress` says which one it chose — a different one on each run, which is why this program never prints it: ```rux let loopback = IpAddress::FromIpv4(Ipv4Address::Localhost()); let listener = TcpListener::Bind(SocketAddress::New(loopback, 0))?; let address = listener.LocalAddress()?; ``` A real server binds a fixed port, such as 8080, and `0.0.0.0` instead of `127.0.0.1` to accept connections from other machines too. Binding a port that is already taken fails with `AddressInUse`. ## Two sides, two threads A server waits; so does a client. In one program, each needs its own line of execution, so the client runs on a [thread](https://rux-lang.dev/docs/learn/thread). `Spawn` passes it the address to connect to: ```rux var client = Spawn(Client, address) catch { else => fail IoError::Of(IoErrorKind::Other) }; ``` The client prints nothing — two threads printing at once would mix their lines in an order that changes from run to run. It returns how many replies it read, and `Main` prints that after `Join`. ## Accepting and connecting `Accept` waits until a client connects, and returns a `TcpStream` for that one connection. The listener goes on listening, and a server that serves many clients calls `Accept` in a loop. On the other side, `TcpStream::Connect` makes the connection: ```rux var stream = listener.Accept()?; let peer = stream.PeerAddress()?; ``` `PeerAddress` is the other end's socket address — `127.0.0.1` and a port the system picked for the client. ## A stream is a reader and a writer A `TcpStream` is an `Io` `Reader` and `Writer`, so everything from the [files](https://rux-lang.dev/docs/learn/files) and [input](https://rux-lang.dev/docs/learn/input) lessons works on it: `WriteAll` to send, `ReadLineFrom` to read a line. That matters because a stream is only bytes. TCP keeps no message boundaries: three writes may arrive as one read, or one write as three. The two sides agree on their own framing — here, one message per line: ```rux for message in messages { WriteAll(stream, message) catch { else => return replies }; ReadLineFrom(stream, reply) catch { else => return replies }; replies = replies + 1; reply.Clear(); } ``` ## Saying goodbye `Shutdown(ShutdownDirection::Write)` tells the other side that nothing more is coming, while the stream stays open for reading. The server's next read then reports the end of the stream, and the loop stops: ```rux match ReadLineFrom(stream, line) { .Success(_) => {}, .Failure(error) if error.IsEnd() => break, .Failure(error) => fail error } ``` Dropping a stream closes it altogether, which the other side also sees as the end. Writing to a connection the other side has closed fails with `BrokenPipe`, and connecting to a port where nobody listens with `ConnectionRefused` — on Windows only after a few seconds of retrying. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Systems/Tcp){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // TCP is how most programs talk over a network: a web browser and a server, a database and its // clients. One side listens on a port; the other connects to it; then each has a stream it can // write bytes into and read the other side's bytes from, in order and without loss. // // The `Net` package gives each side a type. A `TcpListener` is bound to an address and accepts // connections, one `TcpStream` each; a client makes its `TcpStream` with `Connect`. A stream is // an `Io` reader and writer, so `WriteAll`, `ReadLineFrom` and everything else from the files // lessons works on it. Every failure is an `IoError`, with kinds such as `ConnectionRefused`. // // A stream is only bytes: TCP keeps no message boundaries, so the two sides agree on their own. // Here each message is one line. Both sides run in this one program — the server in `Main`, the // client on a second thread — and talk over the loopback address, 127.0.0.1, which never leaves // the machine. import Allocator::SystemAllocator; import Io::{ IoError, IoErrorKind, PrintLine, ReadLineFrom, WriteAll }; import Net::{ IpAddress, Ipv4Address, ShutdownDirection, SocketAddress, TcpListener, TcpStream }; import Text::{ StringBuilder, ToAsciiUpper }; import Thread::Spawn; // The client: connect, send three lines, read a reply to each, then say it has finished. // It returns how many replies it read, so it prints nothing and the output stays in order. func Client(server: SocketAddress) -> uint { var stream = TcpStream::Connect(server) catch { else => return 0 }; let messages: char8[..][3] = ["hello\n", "how are you?\n", "bye\n"]; var reply = StringBuilder(SystemAllocator()); var replies: uint = 0; for message in messages { WriteAll(stream, message) catch { else => return replies }; ReadLineFrom(stream, reply) catch { else => return replies }; replies = replies + 1; reply.Clear(); } // Shutting down the writing half tells the server no more is coming; the stream itself // closes when `stream` is dropped at the end of the function. stream.Shutdown(ShutdownDirection::Write) catch { else => return replies }; return replies; } func Main() -> ! IoError { // Port 0 asks the system for any free port; `LocalAddress` says which one it chose. It // differs between runs, so this program never prints it. let loopback = IpAddress::FromIpv4(Ipv4Address::Localhost()); let listener = TcpListener::Bind(SocketAddress::New(loopback, 0))?; let address = listener.LocalAddress()?; PrintLine("server: listening on 127.0.0.1, port chosen? {}", address.port != 0); // The client runs on its own thread, so the server can wait for it here. var client = Spawn(Client, address) catch { else => fail IoError::Of(IoErrorKind::Other) }; // `Accept` waits for a connection and hands back a stream for it. var stream = listener.Accept()?; let peer = stream.PeerAddress()?; PrintLine("server: a client connected from loopback? {}", peer.ip.IsLoopback()); // Read a line, answer it, and go on until the client shuts its side down. var line = StringBuilder(SystemAllocator()); while true { match ReadLineFrom(stream, line) { .Success(_) => {}, .Failure(error) if error.IsEnd() => break, .Failure(error) => fail error } let loud = ToAsciiUpper(SystemAllocator(), line.View()) catch { else => fail IoError::Of(IoErrorKind::Other) }; PrintLine("server: received [{}], replying [{}]", line.View(), loud); WriteAll(stream, loud.Bytes())?; WriteAll(stream, "\n")?; line.Clear(); } PrintLine("server: the client has finished"); PrintLine("client: read {} replies", client.Join()); // A stream is a reader and a writer, but it is not copied — each one owns its connection: // // let other = stream; // error: move-only value 'stream' requires an explicit '<-' in initialization } ``` Besides `Io`, its `Rux.toml` lists `Allocator`, `Net`, `Text` and `Thread` under `[Dependencies]`. ## Run it ```sh cd Examples/Systems/Tcp rux run ``` ```text server: listening on 127.0.0.1, port chosen? true server: a client connected from loopback? true server: received [hello], replying [HELLO] server: received [how are you?], replying [HOW ARE YOU?] server: received [bye], replying [BYE] server: the client has finished client: read 3 replies ``` ## Common mistakes ::mistake **Copying a stream.**:br A `TcpStream` owns its connection, so `let other = stream;` is refused: ```text error: move-only value 'stream' requires an explicit '<-' in initialization ``` Move it with `<-`, or pass it by reference. :: ::mistake **Treating each read as one message.**:br A `Read` returns whatever has arrived — part of a message, or several. On loopback it usually looks like one write per read, which is exactly why the bug survives testing. Frame your messages — by lines, or with a length in front — and read whole frames. :: ::mistake **Both sides waiting.**:br If the client waits for a reply that the server only sends once the client has finished, neither moves. Here the server replies to every line at once, and the client shuts down its writing half when it has nothing more to say. :: ::mistake **Printing from two threads.**:br Had the client printed its replies, its lines and the server's would interleave differently from one run to the next. Collect results on the thread and print them after `Join`. :: ## Try it yourself 1. Make the server count the lines and reply with the count instead of the line in capitals. 2. Accept two clients one after the other: spawn two client threads and call `Accept` twice. 3. Give the client a read timeout of 100 milliseconds with `SetReadTimeout`, and make the server sleep before replying to `bye`. What does the client see? 4. Drop the `Shutdown` call. Does the server still finish? Why? ## Learn more - [Net API](https://rux-lang.dev/docs/api/net) — `TcpListener`, `TcpStream`, timeouts and non-blocking sockets - [IP addresses](https://rux-lang.dev/docs/learn/ip-address) — the addresses a server binds and a client connects to - [Thread](https://rux-lang.dev/docs/learn/thread) — `Spawn` and `Join` - [Input](https://rux-lang.dev/docs/learn/input) — `ReadLineFrom` and the end of a stream - Next: [UDP](https://rux-lang.dev/docs/learn/udp), messages without a connection # UDP ::note **You'll need**: [IP addresses](https://rux-lang.dev/docs/learn/ip-address), [TCP](https://rux-lang.dev/docs/learn/tcp), [Duration](https://rux-lang.dev/docs/learn/duration), [Guard](https://rux-lang.dev/docs/learn/guard) :: **UDP** is TCP's plainer sibling. There is no connection and no stream: a program sends a **datagram** — one self-contained message, up to about 64 KB — to an address, and the other side receives it whole, or not at all. Nothing is resent if it is lost, and nothing keeps datagrams in order. That sounds worse, and for a file transfer it is. But each message costs one packet and no handshake, and a late answer is often worth nothing anyway: games, voice and video calls, clock synchronisation and DNS look-ups all use UDP. | | TCP | UDP | | ------------- | --------------------------------- | ------------------------------ | | Setting up | `Bind` and `Accept`, or `Connect` | `Bind`, and send straight away | | What you send | a stream of bytes | separate datagrams | | Boundaries | none — you frame messages | kept — one send is one receive | | Lost data | resent automatically | lost | | Order | kept | not promised | ```rux import Net::{ IpAddress, Ipv4Address, SocketAddress, UdpSocket }; ``` ## Sockets that send and receive A `UdpSocket` is bound to an address, like a TCP listener, and can then both send and receive. There is no server or client in the type — only two sockets that know each other's addresses: ```rux let loopback = SocketAddress::New(IpAddress::FromIpv4(Ipv4Address::Localhost()), 0); let alice = UdpSocket::Bind(loopback)?; let bob = UdpSocket::Bind(loopback)?; let aliceAddress = alice.LocalAddress()?; let bobAddress = bob.LocalAddress()?; ``` Both live in this one program, and one thread is enough: a datagram sent to a socket on the same machine waits in that socket's queue until it is received. ## Sending to, receiving from `SendTo` names where each datagram goes. `ReceiveFrom` waits for the next one, copies it into a buffer and returns a `Datagram`: its `length`, and its `source` — the address to reply to: ```rux alice.SendTo("ping", bobAddress)?; var buffer: char8[64]; let received = bob.ReceiveFrom(buffer[..])?; PrintLine("bob got [{}] from alice? {}", buffer[..received.length], received.source.Equals(aliceAddress)); bob.SendTo("pong", received.source)?; ``` Replying to `source` is how a UDP server works: it never connects to anyone, it answers whoever asked. Make the buffer big enough for the largest datagram you expect. One that does not fit is lost either way, but not in the same way everywhere: on Linux and macOS the receive returns the part that fitted, while on Windows it fails with an `IoError` of kind `Other`. ## Boundaries survive Two sends are two datagrams, and each receive takes exactly one — the opposite of TCP, where the two would run together into one stream: ```rux alice.SendTo("first", bobAddress)?; alice.SendTo("second", bobAddress)?; for _ in 0..2 { let datagram = bob.ReceiveFrom(buffer[..])?; PrintLine("bob got [{}], {} bytes", buffer[..datagram.length], datagram.length); } ``` ## A connected pair `Connect` on a UDP socket sends nothing. It fixes the one peer the socket talks to, so that `Send` and `Receive` need no address, and datagrams from anyone else are dropped: ```rux alice.Connect(bobAddress)?; bob.Connect(aliceAddress)?; alice.Send("over the connected pair")?; let length = bob.Receive(buffer[..])?; ``` ## Not waiting forever Since nothing promises an answer, a receive that waits without a limit can wait for good. `SetReadTimeout` gives up after a [duration](https://rux-lang.dev/docs/learn/duration), with an `IoError` of kind `TimedOut`, which a [guard](https://rux-lang.dev/docs/learn/guard) picks out: ```rux bob.SetReadTimeout(Duration::FromMilliseconds(100))?; match bob.Receive(buffer[..]) { .Success(_) => PrintLine("bob got something unexpected"), .Failure(error) if error.kind == IoErrorKind::TimedOut => PrintLine("bob waited 100 ms: nothing"), .Failure(error) => fail error } ``` A program that asks over UDP usually sends again after a timeout, a few times, before giving up. ## Names and many sockets Two more parts of `Net` round it out. Neither runs here, because the lesson stays off the real network. **Names.** Real programs connect to names, not numbers. `Resolve(allocator, host, port)` asks the system's resolver and returns a `Vector<SocketAddress>` — often an IPv6 and an IPv4 address for the same name — to try in turn: ```rux let addresses = Resolve(allocator, "localhost", 5353)?; ``` `Resolver` is the package's own DNS client, which asks name servers of your choosing over UDP, falling back to TCP for a long answer — and is a real example of the send, wait, retry pattern above. **Many sockets at once.** A server with hundreds of clients cannot block on each in turn. `SetNonBlocking(true)` makes a socket's calls fail with `WouldBlock` instead of waiting, and a `Poller` watches many sockets: `Register` each with a token, then `Wait` reports which ones are ready to read or write. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Systems/Udp){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // UDP is TCP's simpler sibling. There is no connection to set up and no stream: a program sends // a datagram — one self-contained message of up to about 64 KB — to an address, and the other // side receives it whole, or not at all. Nothing is resent if it is lost and nothing keeps // datagrams in order. In exchange each message costs one packet and no handshake, which suits // games, voice, time and name lookups: small messages where a late answer is worth nothing. // // A `UdpSocket` is bound to an address, like a TCP listener, and can then both send and // receive. `SendTo` names where each datagram goes; `ReceiveFrom` waits for the next one and // returns a `Datagram`: its length and the address it came from, which is where to reply. // // Both sockets live in this one program, on the loopback address. Datagrams sent to a socket on // the same machine wait in its queue until it receives them, so one thread is enough. import Io::{ IoError, IoErrorKind, PrintLine }; import Net::{ IpAddress, Ipv4Address, SocketAddress, UdpSocket }; import Time::Duration; func Main() -> ! IoError { // Port 0 again lets the system choose; the ports differ between runs and are not printed. let loopback = SocketAddress::New(IpAddress::FromIpv4(Ipv4Address::Localhost()), 0); let alice = UdpSocket::Bind(loopback)?; let bob = UdpSocket::Bind(loopback)?; let aliceAddress = alice.LocalAddress()?; let bobAddress = bob.LocalAddress()?; // One datagram there, and a reply to whoever sent it. alice.SendTo("ping", bobAddress)?; var buffer: char8[64]; let received = bob.ReceiveFrom(buffer[..])?; PrintLine("bob got [{}] from alice? {}", buffer[..received.length], received.source.Equals(aliceAddress)); bob.SendTo("pong", received.source)?; let answer = alice.ReceiveFrom(buffer[..])?; PrintLine("alice got [{}]", buffer[..answer.length]); // Each send is its own datagram, and each receive takes exactly one: the boundaries stay. alice.SendTo("first", bobAddress)?; alice.SendTo("second", bobAddress)?; for _ in 0..2 { let datagram = bob.ReceiveFrom(buffer[..])?; PrintLine("bob got [{}], {} bytes", buffer[..datagram.length], datagram.length); } // `Connect` fixes the one peer a socket talks to, so `Send` and `Receive` need no address. // Nothing is sent: for UDP, connecting only sets a default and filters what arrives. alice.Connect(bobAddress)?; bob.Connect(aliceAddress)?; alice.Send("over the connected pair")?; let length = bob.Receive(buffer[..])?; PrintLine("bob got [{}]", buffer[..length]); // Nobody promises an answer, so a receive that must not wait forever gets a timeout. bob.SetReadTimeout(Duration::FromMilliseconds(100))?; match bob.Receive(buffer[..]) { .Success(_) => PrintLine("bob got something unexpected"), .Failure(error) if error.kind == IoErrorKind::TimedOut => PrintLine("bob waited 100 ms: nothing"), .Failure(error) => fail error } // A socket owns what the system gave it, so it is moved, never copied: // // let carol = alice; // error: move-only value 'alice' requires an explicit '<-' in initialization } ``` Besides `Io`, its `Rux.toml` lists `Net` and `Time` under `[Dependencies]`. ## Run it ```sh cd Examples/Systems/Udp rux run ``` ```text bob got [ping] from alice? true alice got [pong] bob got [first], 5 bytes bob got [second], 6 bytes bob got [over the connected pair] bob waited 100 ms: nothing ``` ## Common mistakes ::mistake **Copying a socket.**:br A socket owns what the system gave it, so `let carol = alice;` is refused: ```text error: move-only value 'alice' requires an explicit '<-' in initialization ``` :: ::mistake **Expecting every datagram to arrive.**:br On loopback nothing is lost, so a program can look reliable here and fail on a real network. Anything that matters needs a reply, a timeout and a retry — or TCP. :: ::mistake **A buffer too small for the datagram.**:br`ReceiveFrom` takes one whole datagram. If it does not fit, the rest is gone — there is no second read for it, as there would be on a stream — and on Windows the receive fails instead of returning the part that fitted. :: ::mistake **Receiving without a timeout.**:br If the other side is gone, `Receive` waits forever. Set a read timeout on any socket that waits for an answer. :: ## Try it yourself 1. Make Bob reply to every datagram with its length, and have Alice print the replies. 2. Bind a third socket, Carol, and have her send to Bob after Bob has connected to Alice. Does Bob receive it? Use a read timeout so the program cannot hang. 3. Send a 20-byte datagram and receive it into an 8-byte buffer. What comes back on your system — a short datagram or a failure? 4. Write a tiny request–reply loop: Alice sends a question, waits up to 50 milliseconds, and tries again up to three times before giving up. ## Learn more - [Net API](https://rux-lang.dev/docs/api/net) — `UdpSocket`, `Resolve`, `Resolver` and `Poller` - [TCP](https://rux-lang.dev/docs/learn/tcp) — the connected, reliable alternative - [IP addresses](https://rux-lang.dev/docs/learn/ip-address) — the addresses on every datagram - [Duration](https://rux-lang.dev/docs/learn/duration) — the timeout's type - Checkpoint: [Grep](https://rux-lang.dev/docs/learn/grep), a command-line tool that puts this part to work # Part 27: Projects Every other part of the course teaches one idea per lesson. This part does the opposite: each project is a complete small program that puts many ideas to work at once — a calculator that explains its errors, a word counter, a guessing game, a to-do list kept in a file, a command-line search tool. They are not meant to be read after Part 26. Each one is a **checkpoint** for an earlier part, and uses nothing the course has not taught by then, so you can stop after that part and build something real. ## What you will learn - How the single ideas of the lessons combine into a program with a design: small functions with one job each, data described by types, and `Main` reading like a summary. - How to treat input as hostile: reading lines, parsing numbers, and telling the end of the input, a read error, a malformed number and an out-of-range one apart. - How to model every way a program can fail as an error type, and when to stop, pass a failure on, or skip it and carry on. - How to choose the right standard package for a job — collections, algorithms, time, randomness, entropy, files, JSON, regular expressions and the command line. - How to run interactive programs and command-line tools, and which projects need a keyboard, a sound card or Windows. ## Which part unlocks which project The arrows point from the part you need to have finished to the projects you can build after it: ```mermaid flowchart LR p3["Part 3<br/>Control flow"] --> thanks["Thanks"] p3 --> fizz["FizzBuzz"] p4["Part 4<br/>Functions"] --> temp["Temperature"] p5["Part 5<br/>Sequences"] --> prime["Prime"] p9["Part 9<br/>Errors"] --> calc["Calculator"] p16["Part 16<br/>Numbers"] --> circle["Circle"] p16 --> quad["Quadratic"] p17["Part 17<br/>Collections"] --> words["Word count"] p17 --> inv["Inventory"] p18["Part 18<br/>Algorithms"] --> stats["Statistics"] p20["Part 20<br/>Utilities"] --> guess["Guess"] p20 --> age["Age"] p20 --> pass["Password"] p20 --> launch["Launch"] p21["Part 21<br/>Data formats"] --> notes["Notes"] p24["Part 24<br/>Platform"] --> melody["Melody"] p26["Part 26<br/>Systems"] --> grep["Grep"] ``` | After part | Project | What it practises | | --------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------ | | [3 Control flow](https://rux-lang.dev/docs/learn/control-flow) | [Thanks](https://rux-lang.dev/docs/learn/thanks), [FizzBuzz](https://rux-lang.dev/docs/learn/fizz-buzz) | Loops, `match` expressions, the order of an `else if` chain | | [4 Functions](https://rux-lang.dev/docs/learn/functions) | [Temperature](https://rux-lang.dev/docs/learn/temperature) | Small functions, recursion, default arguments | | [5 Sequences](https://rux-lang.dev/docs/learn/sequences) | [Prime](https://rux-lang.dev/docs/learn/prime) | An array of flags and the sieve of Eratosthenes | | [9 Errors](https://rux-lang.dev/docs/learn/errors) | [Calculator](https://rux-lang.dev/docs/learn/calculator) | An error variant, `fail`, `?`, `match` and `catch` in one program | | [16 Numbers](https://rux-lang.dev/docs/learn/numbers) | [Circle](https://rux-lang.dev/docs/learn/circle), [Quadratic](https://rux-lang.dev/docs/learn/quadratic) | Reading and checking numbers, infinity, NaN and floating-point accuracy | | [17 Collections](https://rux-lang.dev/docs/learn/collections) | [Word count](https://rux-lang.dev/docs/learn/word-count), [Inventory](https://rux-lang.dev/docs/learn/inventory) | Hash and tree maps, a vector of structs, two kinds of failure | | [18 Algorithms](https://rux-lang.dev/docs/learn/algorithms) | [Statistics](https://rux-lang.dev/docs/learn/statistics) | Sorting, folding and extremes, and the empty case | | [20 Utilities](https://rux-lang.dev/docs/learn/utilities) | [Guess](https://rux-lang.dev/docs/learn/guess), [Age](https://rux-lang.dev/docs/learn/age), [Password](https://rux-lang.dev/docs/learn/password), [Launch](https://rux-lang.dev/docs/learn/launch) | Randomness, entropy, calendar arithmetic, pauses and a game loop | | [21 Data formats](https://rux-lang.dev/docs/learn/data-formats) | [Notes](https://rux-lang.dev/docs/learn/notes) | JSON saved to a file atomically, and loaded back | | [24 Platform](https://rux-lang.dev/docs/learn/platform) | [Melody](https://rux-lang.dev/docs/learn/melody) | Calling a Windows function directly, chosen while compiling | | [26 Systems](https://rux-lang.dev/docs/learn/systems) | [Grep](https://rux-lang.dev/docs/learn/grep) | Options and help from CommandLine, a regular expression, files read line by line, an exit status | Circle and Quadratic are really about [Part 14: Text](https://rux-lang.dev/docs/learn/text) — reading and parsing a line — but they also borrow `IsFinite` and the Math package from Part 16, so they unlock there. ## Lessons | | Lesson | What you will learn | | ----- | ---------------------------------------------------------- | ---------------------------------------------------------------------------------- | | 27.1 | [Thanks](https://rux-lang.dev/docs/learn/thanks) | draw RUX as an ASCII banner and thank everyone who helps build it | | 27.2 | [FizzBuzz](https://rux-lang.dev/docs/learn/fizz-buzz) | the classic counting game | | 27.3 | [Temperature](https://rux-lang.dev/docs/learn/temperature) | a table of Celsius and Fahrenheit temperatures | | 27.4 | [Prime](https://rux-lang.dev/docs/learn/prime) | every prime below 100, found with the sieve of Eratosthenes | | 27.5 | [Calculator](https://rux-lang.dev/docs/learn/calculator) | evaluate expressions and report every way they can go wrong | | 27.6 | [Circle](https://rux-lang.dev/docs/learn/circle) | read a radius, check it, and print the circle's measurements | | 27.7 | [Quadratic](https://rux-lang.dev/docs/learn/quadratic) | solve a quadratic equation, including linear and degenerate cases | | 27.8 | [Word count](https://rux-lang.dev/docs/learn/word-count) | count how often each word appears | | 27.9 | [Inventory](https://rux-lang.dev/docs/learn/inventory) | keep a stock list of items, with updates that can fail | | 27.10 | [Statistics](https://rux-lang.dev/docs/learn/statistics) | count, extremes, mean, variance and median, including empty and single-value input | | 27.11 | [Guess](https://rux-lang.dev/docs/learn/guess) | a number guessing game with seven valid guesses from 1 to 100 | | 27.12 | [Age](https://rux-lang.dev/docs/learn/age) | an age in completed years, months and days, with month-end clamping | | 27.13 | [Password](https://rux-lang.dev/docs/learn/password) | a 16-character password drawn from system entropy with rejection sampling | | 27.14 | [Launch](https://rux-lang.dev/docs/learn/launch) | a mission checklist, a bounded countdown and a launch | | 27.15 | [Notes](https://rux-lang.dev/docs/learn/notes) | keep notes in a JSON file | | 27.16 | [Melody](https://rux-lang.dev/docs/learn/melody) | play a tune through the Windows console speaker (Windows only) | | 27.17 | [Grep](https://rux-lang.dev/docs/learn/grep) | search files for lines that match a regular expression, with command-line options | ## Before you start Pick the project for the part you have just finished, rather than reading this part in order. Each project page lists exactly which lessons it leans on, links them where they are used, and ends with exercises that extend the program — those are the real work. Each project is a package in the Examples repository's `Projects/` folder: ```sh cd Examples/Projects/FizzBuzz rux run ``` Most projects print the same output on every run. A few are different: | Project | What to expect | | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------- | | [Circle](https://rux-lang.dev/docs/learn/circle), [Quadratic](https://rux-lang.dev/docs/learn/quadratic), [Guess](https://rux-lang.dev/docs/learn/guess), [Launch](https://rux-lang.dev/docs/learn/launch) | They wait for you to type. Answer the prompt and press Enter, or pipe the input in | | [Guess](https://rux-lang.dev/docs/learn/guess), [Password](https://rux-lang.dev/docs/learn/password) | A different number or password on every run | | [Notes](https://rux-lang.dev/docs/learn/notes) | Writes a file in the package's `Bin/` folder, and deletes it again | | [Melody](https://rux-lang.dev/docs/learn/melody) | Windows only, and plays sound through the console speaker | | [Grep](https://rux-lang.dev/docs/learn/grep) | With no arguments it searches its own source; give it arguments after `--` to search your own files | ## After this part This is the end of the course. From here, the best next step is a program of your own — take the project closest to what you want to build and change it until it is yours. The [Rux Reference](https://rux-lang.dev/docs/lang/introduction) has the full rules behind every lesson, the [API reference](https://rux-lang.dev/docs/api) covers the standard packages, and the [cheat sheet](https://rux-lang.dev/docs/learn/cheatsheet) keeps the syntax on one page. When you want to share what you made, [Part 22: Packages](https://rux-lang.dev/docs/learn/packages) shows how to turn it into a package others can depend on. # Thanks ::note **You'll need**: Parts 1–3 — this project is the checkpoint for Control flow, and leans on [Console](https://rux-lang.dev/docs/learn/console), [For](https://rux-lang.dev/docs/learn/for) and [Match expression](https://rux-lang.dev/docs/learn/match-expression). :: This is the first checkpoint project of the course. It prints the word RUX in large letters, draws a rule under it, and lists everything that goes into building a language — a thank-you card written in code. Nothing here is new. The program uses only what Parts 1–3 taught: `Print` and `PrintLine`, `for` over a range, and `match` used as an expression. The point of the project is to see those few tools add up to something that looks designed. If you can read every line of it, you have Control flow under your belt. ## How it is put together `Main` does three jobs, one after another, and each is a loop: ```mermaid flowchart LR banner["Banner<br/>`for row in 0..6`<br/>`match row` → one line"] --> rule["Rule<br/>`for i in 0..width`<br/>one `=` per pass"] rule --> list["List<br/>`for item in 1..=count`<br/>`match item` → one line"] ``` | Piece | What it does | Lessons it uses | | --------------- | ------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Banner | Picks the text of each row of the big letters | [For](https://rux-lang.dev/docs/learn/for), [Range](https://rux-lang.dev/docs/learn/range), [Match expression](https://rux-lang.dev/docs/learn/match-expression) | | Rule | Repeats one character `width` times | [For](https://rux-lang.dev/docs/learn/for), [Console](https://rux-lang.dev/docs/learn/console), [Variable](https://rux-lang.dev/docs/learn/variable) | | Thank-you list | Picks the text of each numbered item | [Match expression](https://rux-lang.dev/docs/learn/match-expression), [Range](https://rux-lang.dev/docs/learn/range) | | Closing message | Plain `PrintLine` calls, with empty ones as gaps | [Hello, World](https://rux-lang.dev/docs/learn/hello), [Console](https://rux-lang.dev/docs/learn/console) | There are no arrays yet — they arrive in [Part 5](https://rux-lang.dev/docs/learn/sequences) — so a list of lines cannot be stored and walked. Instead a loop counts the rows, and a `match` says what belongs on each one. ## Big letters are rows of characters A large letter is only a few rows of `#` and spaces printed one under another. Each row here runs across all three letters at once: ```rux for row in 0..6 { let line = match row { 0 => " #### ## ## ## ## ", 1 => " ## ## ## ## ## ## ", 2 => " ## ## ## ## ### ", 3 => " ##### ## ## ### ", 4 => " ## ## ## ## ## ## ", else => " ## ## #### ## ## " }; PrintLine("{}", line); } ``` Read the arms from top to bottom rather than one at a time, and the shapes of R, U and X appear. Three details are worth noticing: - `0..6` is a half-open range: it gives 0, 1, 2, 3, 4 and 5 — six rows — and stops before 6. - The `match` is an **expression**. Each arm produces a piece of text, and the whole `match` hands that text to `let line`. - The last row is the `else` arm. A match over an `int` must have an answer for *every* integer, not only the six the loop will ever ask about, so the final row doubles as the default. ## A rule drawn by repetition The `=` line under the banner is not typed out. A loop prints one character `width` times, and `Print` (not `PrintLine`) keeps them all on one line: ```rux let width = 44; for i in 0..width { Print("="); } PrintLine(); ``` The loop variable `i` is never read — the loop exists only to run its body 44 times. Naming the width once means the rule above and below the title can never disagree, and changing one number resizes both. ## A numbered list without an array The thank-you list uses the same trick as the banner, counted from 1 this time: ```rux for item in 1..=count { let contribution = match item { 1 => "the ideas, and the patience to explain them twice", 2 => "the long discussions, and the short sharp ones", 3 => "the code, the tests, and the unglamorous fixes", 4 => "the critique that was right, and the kind that stung", 5 => "the bug reports written carefully by strangers", 6 => "the documentation nobody is thanked for", 7 => "the funding that bought time to think", 8 => "turning up, reading along, and asking good questions", else => "the posts, the shares, the subscribes, the word of mouth" }; PrintLine(" - {}", contribution); } ``` `count` is 9, and `1..=count` is the inclusive range: it includes `count` itself, so the loop runs for items 1 to 9. As in the banner, the ninth item lives in the `else` arm, which keeps the match complete. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Projects/Thanks){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // A banner drawn as text, and a thank-you to the people who make Rux. // // Everything here comes from the first three parts of the course: printing, a `for` loop over a // range, and `match` used as an expression. There are no arrays yet, so each list is a loop that // counts rows and a `match` that says what belongs on each one. Large letters are only rows of // characters printed one after another. import Io::{ Print, PrintLine }; func Main() -> int { // Each row runs across all three letters. Read the arms from top to bottom rather than one // at a time, and the shapes of R, U and X appear. PrintLine(); for row in 0..6 { let line = match row { 0 => " #### ## ## ## ## ", 1 => " ## ## ## ## ## ## ", 2 => " ## ## ## ## ### ", 3 => " ##### ## ## ### ", 4 => " ## ## ## ## ## ## ", else => " ## ## #### ## ## " }; PrintLine("{}", line); } PrintLine(); // A rule drawn by repeating one character, rather than by typing it out. let width = 44; for i in 0..width { Print("="); } PrintLine(); PrintLine(" Thank you, everyone"); for i in 0..width { Print("="); } PrintLine(); PrintLine(); // Every kind of help that goes into a language, in no particular order, because none of them // is the one that matters least. The `else` arm is the last item, so a match over numbers // still has an answer for every row. let count = 9; PrintLine("Rux exists because of:"); PrintLine(); for item in 1..=count { let contribution = match item { 1 => "the ideas, and the patience to explain them twice", 2 => "the long discussions, and the short sharp ones", 3 => "the code, the tests, and the unglamorous fixes", 4 => "the critique that was right, and the kind that stung", 5 => "the bug reports written carefully by strangers", 6 => "the documentation nobody is thanked for", 7 => "the funding that bought time to think", 8 => "turning up, reading along, and asking good questions", else => "the posts, the shares, the subscribes, the word of mouth" }; PrintLine(" - {}", contribution); } PrintLine(); PrintLine("A language is a community that happens to have a compiler."); PrintLine("Thank you for being part of this one."); PrintLine(); PrintLine(" -- Ivan Muzyka, creator of Rux"); PrintLine(); return 0; } ``` ## Run it ```sh cd Examples/Projects/Thanks rux run ``` ```text #### ## ## ## ## ## ## ## ## ## ## ## ## ## ## ### ##### ## ## ### ## ## ## ## ## ## ## ## #### ## ## ============================================ Thank you, everyone ============================================ Rux exists because of: - the ideas, and the patience to explain them twice - the long discussions, and the short sharp ones - the code, the tests, and the unglamorous fixes - the critique that was right, and the kind that stung - the bug reports written carefully by strangers - the documentation nobody is thanked for - the funding that bought time to think - turning up, reading along, and asking good questions - the posts, the shares, the subscribes, the word of mouth A language is a community that happens to have a compiler. Thank you for being part of this one. -- Ivan Muzyka, creator of Rux ``` ## Common mistakes ::mistake **A match over numbers with no `else` arm.**:br Changing the banner's `else` arm to `5 =>` looks harmless, since the loop never asks for anything else. The compiler disagrees: ```text error: match on 'int' is not exhaustive; its arms do not cover every value ``` The compiler adds the hint `add an 'else' arm`. It checks the `match` on its own, not the loop around it. See [Exhaustive](https://rux-lang.dev/docs/learn/exhaustive). :: ::mistake **`..` where you meant `..=`.**:br Writing `for item in 1..count` compiles and runs, but `1..count` stops before 9, so the last line of the list — the one in the `else` arm — silently disappears. When a range counts things from 1, it almost always wants `..=`. :: ## Try it yourself 1. Make the rule out of `-` instead of `=`, and make it 30 characters wide. How many lines did you have to change? 2. Add a tenth contribution to the list. Remember that the `else` arm has to stay last, and that `count` has to grow too. 3. Number the list instead of using dashes, so it prints `1. the ideas…`, `2. the long discussions…` and so on. 4. Add a fourth letter to the banner — an `!` is the easiest. Every row's text has to grow by the same number of columns, or the letters will lean. ## Learn more - [For](https://rux-lang.dev/docs/learn/for), [Range](https://rux-lang.dev/docs/learn/range) and [Match expression](https://rux-lang.dev/docs/learn/match-expression) — the three tools this project is built from - [Match](https://rux-lang.dev/docs/lang/patterns/match) and [For](https://rux-lang.dev/docs/lang/statements/loops#for) in the Rux Reference - Next project: [FizzBuzz](https://rux-lang.dev/docs/learn/fizz-buzz), the other checkpoint for Control flow # FizzBuzz ::note **You'll need**: Parts 1–3 — this project is a checkpoint for Control flow, and leans on [Arithmetic](https://rux-lang.dev/docs/learn/arithmetic), [Else if](https://rux-lang.dev/docs/learn/else-if) and [For](https://rux-lang.dev/docs/learn/for). :: FizzBuzz is a counting game: go from 1 to 100, but say "Fizz" instead of every multiple of 3, "Buzz" instead of every multiple of 5, and "FizzBuzz" instead of every multiple of both. It began as a children's game for practising division and became the most famous little test in programming — not because it is hard, but because it is so easy to get *almost* right. The program needs only Parts 1–3. It also keeps a tally of each kind of answer, which turns out to be a handy way of checking that the logic is right. ## How it is put together Everything happens inside one `for` loop. Each pass asks a chain of questions about `n`, prints one answer, counts it, and then decides what goes after it — a space or a line break: ```mermaid flowchart LR n(["`n` from 1 to 100"]) --> q15{"`n % 15 == 0?`"} q15 -- "yes" --> fb["`FizzBuzz`"] q15 -- "no" --> q3{"`n % 3 == 0?`"} q3 -- "yes" --> f["`Fizz`"] q3 -- "no" --> q5{"`n % 5 == 0?`"} q5 -- "yes" --> b["`Buzz`"] q5 -- "no" --> num["the number"] ``` | Piece | Lessons it uses | | ------------------------ | ------------------------------------------------------------------------------------------------------------------------ | | `n % 3 == 0` | [Arithmetic](https://rux-lang.dev/docs/learn/arithmetic) (`%`), [Comparison](https://rux-lang.dev/docs/learn/comparison) | | The chain of questions | [Else if](https://rux-lang.dev/docs/learn/else-if) | | Walking 1 to 100 | [For](https://rux-lang.dev/docs/learn/for), [Range](https://rux-lang.dev/docs/learn/range) | | The tallies | [Mutable](https://rux-lang.dev/docs/learn/mutable), [Assignment](https://rux-lang.dev/docs/learn/assignment) (`+=`) | | Ten answers to each line | [If](https://rux-lang.dev/docs/learn/if), [Console](https://rux-lang.dev/docs/learn/console) (`Print` and `PrintLine`) | ## "Divides exactly" is a remainder of zero `%` gives the remainder of a division. When a number divides by 3 exactly, nothing is left over, so `n % 3 == 0` reads as "n is a multiple of 3". A number that is a multiple of both 3 and 5 is a multiple of 15, so one test covers "both": ```rux if n % 15 == 0 { Print("FizzBuzz"); fizzBuzzes += 1; } else if n % 3 == 0 { Print("Fizz"); fizzes += 1; } else if n % 5 == 0 { Print("Buzz"); buzzes += 1; } else { Print("{}", n); } ``` ## The order of the questions is the whole trick An `else if` chain runs the **first** branch whose condition holds and skips the rest. Fifteen is a multiple of 3, so a chain that asks about 3 first answers "Fizz" for 15 and never gets as far as "FizzBuzz". The most specific question has to come first; the general ones follow. That is also why the tallies are worth printing. In a correct run there are 6 FizzBuzzes. If you move the `% 3` test to the top of the chain, the program still compiles and still prints a hundred answers, but the tally reports `Fizz 33 times` and `FizzBuzz 0 times` — every FizzBuzz has been swallowed by Fizz. ## Ten to a line After each answer the loop decides what comes next. Every tenth number ends the line; every other one is followed by a space: ```rux if n % 10 == 0 { PrintLine(); } else { Print(" "); } ``` `Print` writes without ending the line, so the answers build up across it until `PrintLine()` with no arguments ends it. The same `%` test that finds the multiples of 3 here finds every tenth `n`. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Projects/FizzBuzz){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // FizzBuzz: count from 1 to 100, but say "Fizz" instead of every multiple of 3, "Buzz" instead // of every multiple of 5, and "FizzBuzz" instead of every multiple of both. // // It began as a children's game for practising division, and became the most famous little test // in programming because it is so easy to get almost right. The trap is the order of the // questions. Fifteen is a multiple of 3, so a program that asks about 3 first says "Fizz" and // never gets as far as "FizzBuzz". The multiple of both has to be checked before either one. // // Everything here comes from the first three parts: `%` gives the remainder of a division, so // `n % 3 == 0` means "n divides by 3 exactly"; an `if` / `else if` chain picks the first question // that answers yes; and a `for` loop walks the numbers. import Io::{ Print, PrintLine }; func Main() -> int { var fizzes = 0; var buzzes = 0; var fizzBuzzes = 0; for n in 1..=100 { // A multiple of both 3 and 5 is a multiple of 15, so one test covers it. if n % 15 == 0 { Print("FizzBuzz"); fizzBuzzes += 1; } else if n % 3 == 0 { Print("Fizz"); fizzes += 1; } else if n % 5 == 0 { Print("Buzz"); buzzes += 1; } else { Print("{}", n); } // Ten to a line keeps the output short: a space between entries, and a line break after // every tenth one. if n % 10 == 0 { PrintLine(); } else { Print(" "); } } PrintLine(); PrintLine("Fizz {} times", fizzes); PrintLine("Buzz {} times", buzzes); PrintLine("FizzBuzz {} times", fizzBuzzes); PrintLine("numbers {} times", 100 - fizzes - buzzes - fizzBuzzes); return 0; } ``` ## Run it ```sh cd Examples/Projects/FizzBuzz rux run ``` ```text 1 2 Fizz 4 Buzz Fizz 7 8 Fizz Buzz 11 Fizz 13 14 FizzBuzz 16 17 Fizz 19 Buzz Fizz 22 23 Fizz Buzz 26 Fizz 28 29 FizzBuzz 31 32 Fizz 34 Buzz Fizz 37 38 Fizz Buzz 41 Fizz 43 44 FizzBuzz 46 47 Fizz 49 Buzz Fizz 52 53 Fizz Buzz 56 Fizz 58 59 FizzBuzz 61 62 Fizz 64 Buzz Fizz 67 68 Fizz Buzz 71 Fizz 73 74 FizzBuzz 76 77 Fizz 79 Buzz Fizz 82 83 Fizz Buzz 86 Fizz 88 89 FizzBuzz 91 92 Fizz 94 Buzz Fizz 97 98 Fizz Buzz Fizz 27 times Buzz 14 times FizzBuzz 6 times numbers 53 times ``` ## Common mistakes ::mistake **Asking the general question first.**:br`if n % 3 == 0` before `if n % 15 == 0` is still valid code, so the compiler cannot help — 15, 30, 45 and the rest come out as `Fizz`. The tally gives it away: Fizz 33 times, FizzBuzz 0 times. Always order a chain from the most specific case to the least. :: ::mistake **`=` where you meant `==`.**:br`if n % 15 = 0` is an assignment, not a comparison, and is refused: ```text error: operator '=' requires an assignable target, but its left operand has type 'int' ``` A condition compares with `==`. :: ::mistake **A tally declared with `let`.**:br The counters change on every pass, so they need `var`. With `let fizzes = 0;` the line `fizzes += 1;` fails with: ```text error: cannot modify immutable variable 'fizzes' ``` :: ## Try it yourself 1. Add a fourth rule: say "Bazz" for multiples of 7. Where in the chain does each new test have to go, and what should a multiple of 3, 5 and 7 print? 2. Count to 30 instead of 100. The last line of the tally computes the plain numbers as `100 - fizzes - buzzes - fizzBuzzes` — what else has to change so the report stays right? 3. Print five answers to a line instead of ten. 4. Rewrite the chain so it never mentions 15: test 3 and 5 on their own, and use `&&` for the case where both hold. Check that the tallies come out the same. ## Learn more - [Else if](https://rux-lang.dev/docs/learn/else-if) — why the first condition that holds wins - [Arithmetic](https://rux-lang.dev/docs/learn/arithmetic) — `%` and integer division - [If](https://rux-lang.dev/docs/lang/statements/if) and [Arithmetic operators](https://rux-lang.dev/docs/lang/expressions/arithmetic) in the Rux Reference - Next project: [Temperature](https://rux-lang.dev/docs/learn/temperature), the checkpoint for Functions # Temperature ::note **You'll need**: Parts 1–4 — this project is the checkpoint for Functions, and leans on [Function](https://rux-lang.dev/docs/learn/function), [Recursion](https://rux-lang.dev/docs/learn/recursion) and [Default argument](https://rux-lang.dev/docs/learn/default-argument). :: This project prints two conversion tables — Celsius to Fahrenheit and back — with the numbers lined up in columns and a word for how each temperature feels. Then it answers a small puzzle: at which temperature do the two scales show the same number? It is the checkpoint for [Part 4: Functions](https://rux-lang.dev/docs/learn/functions), and the interesting thing about it is not the arithmetic but the **shape**. Every job has its own small function with a name that says what it does, so `Main` reads like a description of the tables rather than a page of formulas. ## How it is put together `Main` only calls other functions. Here is who calls whom: ```mermaid flowchart LR main(["`Main`"]) --> c2f["`CelsiusToFahrenheit`"] main --> f2c["`FahrenheitToCelsius`"] main --> round["`Round`"] main --> right["`PrintRight`"] main --> feel["`PrintFeeling`"] right --> width["`Width`"] round -. "calls itself<br/>for a negative value" .-> round width -. "calls itself<br/>once per digit" .-> width ``` | Function | Its one job | Lessons it uses | | -------------------------------------------- | ----------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------- | | `CelsiusToFahrenheit`, `FahrenheitToCelsius` | One formula each | [Function](https://rux-lang.dev/docs/learn/function), [Float](https://rux-lang.dev/docs/learn/float) | | `Round` | A `float64` to the nearest whole `int` | [Recursion](https://rux-lang.dev/docs/learn/recursion), [Convert](https://rux-lang.dev/docs/learn/convert) | | `Width` | How many characters a number takes when printed | [Recursion](https://rux-lang.dev/docs/learn/recursion), [Arithmetic](https://rux-lang.dev/docs/learn/arithmetic) | | `PrintRight` | A number right-aligned in a column | [Default argument](https://rux-lang.dev/docs/learn/default-argument), [Return](https://rux-lang.dev/docs/learn/return) | | `PrintFeeling` | A temperature in words | [Else if](https://rux-lang.dev/docs/learn/else-if) | | `Main` | The two tables and the puzzle | [While](https://rux-lang.dev/docs/learn/while), [For](https://rux-lang.dev/docs/learn/for) | ## One formula per function The conversions are one line each. Every literal in them is written with a decimal point, because the parameters are `float64`: ```rux func CelsiusToFahrenheit(celsius: float64) -> float64 { return celsius * 9.0 / 5.0 + 32.0; } ``` The loops in `Main` count in whole degrees, so each call converts its `int` argument on the way in: `CelsiusToFahrenheit(celsius as float64)`. Rux never turns an `int` into a `float64` by itself. ## Rounding, and a recursive trick for negatives `as int` alone only drops the fraction: 37.8 would become 37, not 38. Adding 0.5 first fixes that for positive values. For a negative value, `Round` rounds its positive twin and negates the result — a function calling itself once: ```rux func Round(value: float64) -> int { if value < 0.0 { return -Round(-value); } return (value + 0.5) as int; } ``` Without the negative case, −17.8 + 0.5 is −17.3, which `as int` truncates towards zero to −17 — the wrong way. The first row of the Fahrenheit table, 0 F, is exactly that value: it prints −18 only because of the recursive branch. ## Columns from counting digits To right-align a number in a column of six, you need to know how wide it will print. `Width` counts digits recursively — one for this digit, plus however many the number divided by ten has — and adds one for a minus sign: ```rux func Width(value: int) -> int { if value < 0 { return 1 + Width(-value); } if value < 10 { return 1; } return 1 + Width(value / 10); } ``` `PrintRight` then prints the missing spaces before the number. Its `width` parameter has a default, so every call in `Main` can leave it out: ```rux func PrintRight(value: int, width: int = 6) { for i in Width(value)..width { Print(" "); } Print("{}", value); } ``` If the number is already as wide as the column, `Width(value)..width` is an empty range and the loop simply does not run. ## Asking the function, not knowing the answer The last loop finds where the scales agree by trying every whole degree from −100 to 100 and asking the conversion function: ```rux for degrees in -100..=100 { if CelsiusToFahrenheit(degrees as float64) == degrees as float64 { PrintLine("{} C is also {} F", degrees, degrees); } } ``` Comparing floats with `==` is usually a warning sign (see [Float](https://rux-lang.dev/docs/learn/float)), but here both sides are whole numbers that a `float64` holds exactly, so the test is safe. The answer is −40. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Projects/Temperature){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // Temperature: two conversion tables between Celsius and Fahrenheit, built from small functions. // // Each function does one job and has a name that says what. The conversions are one formula // each; `Round` turns a converted value into whole degrees; `Width` and `PrintRight` line the // numbers up in columns; `PrintFeeling` puts a temperature into words. `Main` only calls them, so // it reads like a description of the tables rather than a page of arithmetic. // // The two scales meet at exactly one temperature, and the end of the program finds it by asking // the conversion function, not by knowing the answer. import Io::{ Print, PrintLine }; func CelsiusToFahrenheit(celsius: float64) -> float64 { return celsius * 9.0 / 5.0 + 32.0; } func FahrenheitToCelsius(fahrenheit: float64) -> float64 { return (fahrenheit - 32.0) * 5.0 / 9.0; } // Rounds to the nearest whole degree. `as int` on its own would only drop the fraction, turning // 37.8 into 37 rather than 38. A negative value is rounded as its positive twin, then negated, so // -17.8 becomes -18 and not -17. func Round(value: float64) -> int { if value < 0.0 { return -Round(-value); } return (value + 0.5) as int; } // How many characters a whole number takes when printed: its digits, plus one for a minus sign. func Width(value: int) -> int { if value < 0 { return 1 + Width(-value); } if value < 10 { return 1; } return 1 + Width(value / 10); } // Prints a number right-aligned in a column, by printing spaces first to fill the gap. func PrintRight(value: int, width: int = 6) { for i in Width(value)..width { Print(" "); } Print("{}", value); } func PrintFeeling(celsius: int) { if celsius <= 0 { PrintLine(" frozen"); } else if celsius < 10 { PrintLine(" cold"); } else if celsius < 20 { PrintLine(" cool"); } else if celsius < 30 { PrintLine(" warm"); } else if celsius < 45 { PrintLine(" hot"); } else if celsius < 100 { PrintLine(" too hot to touch"); } else { PrintLine(" boiling"); } } func Main() -> int { // Every multiple of 5 Celsius is a whole number of Fahrenheit, so this table is exact. PrintLine(" C F"); var celsius = -40; while celsius <= 100 { PrintRight(celsius); PrintRight(Round(CelsiusToFahrenheit(celsius as float64))); PrintFeeling(celsius); celsius += 10; } PrintLine(); // The other way round the results have fractions, so they are rounded to whole degrees. PrintLine(" F C"); var fahrenheit = 0; while fahrenheit <= 220 { let converted = Round(FahrenheitToCelsius(fahrenheit as float64)); PrintRight(fahrenheit); PrintRight(converted); PrintFeeling(converted); fahrenheit += 20; } PrintLine(); // Where do the scales agree? Try every whole degree and ask. for degrees in -100..=100 { if CelsiusToFahrenheit(degrees as float64) == degrees as float64 { PrintLine("{} C is also {} F", degrees, degrees); } } return 0; } ``` ## Run it ```sh cd Examples/Projects/Temperature rux run ``` ```text C F -40 -40 frozen -30 -22 frozen -20 -4 frozen -10 14 frozen 0 32 frozen 10 50 cool 20 68 warm 30 86 hot 40 104 hot 50 122 too hot to touch 60 140 too hot to touch 70 158 too hot to touch 80 176 too hot to touch 90 194 too hot to touch 100 212 boiling F C 0 -18 frozen 20 -7 frozen 40 4 cold 60 16 cool 80 27 warm 100 38 hot 120 49 too hot to touch 140 60 too hot to touch 160 71 too hot to touch 180 82 too hot to touch 200 93 too hot to touch 220 104 boiling -40 C is also -40 F ``` ## Common mistakes ::mistake **Passing an `int` where a `float64` is expected.**:br`CelsiusToFahrenheit(celsius)` with an `int` argument is refused: ```text error: argument 1 to 'CelsiusToFahrenheit' has type 'int', but parameter 'celsius' requires 'float64' ``` Convert at the call with `as float64`. :: ::mistake **Writing `9` instead of `9.0` in a float formula.**:br`celsius * 9 / 5 + 32` looks like the same formula, but in a `float64` function it fails with: ```text error: operator '*' cannot combine left operand 'float64' with right operand 'int' ``` The same goes for `/` and `+`. Write the literals as `9.0`, `5.0` and `32.0`. :: ::mistake **Rounding with `as int` alone.**:br`as int` truncates towards zero. With `return value as int;` in `Round` the program still runs, but 100 F comes out as 37 C instead of 38, and 60 F as 15 instead of 16. :: ## Try it yourself 1. Add a Kelvin column to the first table. Write `CelsiusToKelvin` as its own function rather than doing the sum inside `Main`. 2. Call `PrintRight` with a width of 8 for one column, so the default and an explicit argument are used side by side. 3. Change `PrintFeeling` so it returns the word instead of printing it. What does its return type become, and what changes at the call sites? 4. The puzzle loop only tries whole degrees. Change it to step through every half degree from −100 to 100 and check that −40 is still the only answer. ## Learn more - [Function](https://rux-lang.dev/docs/learn/function), [Recursion](https://rux-lang.dev/docs/learn/recursion) and [Default argument](https://rux-lang.dev/docs/learn/default-argument) - [Convert](https://rux-lang.dev/docs/learn/convert) — what `as int` does to a fraction - [Functions](https://rux-lang.dev/docs/lang/functions/declaration) in the Rux Reference - Next project: [Prime](https://rux-lang.dev/docs/learn/prime), the checkpoint for Sequences # Prime ::note **You'll need**: Parts 1–5 — this project is the checkpoint for Sequences, and leans on [While](https://rux-lang.dev/docs/learn/while), [For](https://rux-lang.dev/docs/learn/for) and [Array repeat](https://rux-lang.dev/docs/learn/array-repeat). :: A prime is a whole number above 1 that only 1 and itself divide. This project finds every prime below 100 with the **sieve of Eratosthenes**, an algorithm more than two thousand years old and still the way to do it. The idea fits in one sentence: write down every number, then repeatedly take the smallest one not yet crossed out and cross out all its multiples. Whatever survives is prime. The sieve never divides anything — it only steps along and marks — which is why it beats testing each number for divisors. It is the checkpoint for [Part 5: Sequences](https://rux-lang.dev/docs/learn/sequences), because the crossing-out needs an array. ## How it is put together The program is one `Main` with three steps, all working on a single array of flags: ```mermaid flowchart LR make["One flag per number<br/>`[false; Limit]`"] --> mark["Mark 0 and 1<br/>as not prime"] mark --> sieve["For each surviving `n`,<br/>cross out `n·n`, `n·n + n`, …"] sieve --> print["Print every index<br/>still `false`"] ``` | Piece | Lessons it uses | | ---------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- | | `const Limit = 100` | [Const](https://rux-lang.dev/docs/learn/const) | | `[false; Limit]` | [Array repeat](https://rux-lang.dev/docs/learn/array-repeat), [Array](https://rux-lang.dev/docs/learn/array) | | The two nested passes | [While](https://rux-lang.dev/docs/learn/while), [Logical](https://rux-lang.dev/docs/learn/logical) (`!`) | | Printing the survivors | [For](https://rux-lang.dev/docs/learn/for), [Range](https://rux-lang.dev/docs/learn/range), [Console](https://rux-lang.dev/docs/learn/console) | ## One flag per number The array's **index** is the number and its **element** says whether that number has been crossed out. An array repeat makes a hundred `false` flags in one expression: ```rux const Limit = 100; ``` ```rux var crossedOut = [false; Limit]; crossedOut[0] = true; crossedOut[1] = true; ``` The length of an inline array is part of its type, so it must be known while compiling. That is why the limit is a `const` and not a `let`: a constant can size the array *and* bound the loops, and changing the one number changes both. The array is `var` because the sieve writes to it. "Below 100" means the candidates are 0 to 99 — exactly the indices of a 100-element array, and exactly what the half-open range `0..Limit` walks. ## Crossing out multiples For each number that is still standing, an inner loop steps through its multiples and marks them: ```rux var n = 2; while n * n < Limit { if !crossedOut[n] { var multiple = n * n; while multiple < Limit { crossedOut[multiple] = true; multiple += n; } } n += 1; } ``` Two shortcuts make this fast, and both rest on the same observation. A multiple `k * n` with `k` smaller than `n` also has the factor `k`, so it was already crossed out during an earlier pass. That means: - each pass can **start** at `n * n` rather than at `2 * n`, and - the outer loop can **stop** once `n * n` reaches the limit — such an `n` has no multiples left to visit. For a limit of 100 the outer loop only runs for `n` from 2 to 9, and only 2, 3, 5 and 7 survive to do any crossing out. ## Reading off the answer Whatever is still `false` is prime. One `for` over the indices prints them and counts them: ```rux for i in 0..Limit { if !crossedOut[i] { Print(" {}", i); found += 1; } } ``` ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Projects/Prime){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // Finding every prime below a limit with the sieve of Eratosthenes, an algorithm more than two // thousand years old and still the way to do it. // // The idea: write down every number, then repeatedly take the smallest one not yet crossed out // and cross out all its multiples. Whatever survives is prime. It is faster than testing each // number for divisors, because it never divides at all; it only steps along and marks. // // "Below" means the limit itself is not a candidate: with a limit of 100 the numbers examined are // 0 to 99. That matches the array, whose indices run from 0 to one less than its length, and the // half-open range `0..Limit` that walks it. import Io::{ Print, PrintLine }; // The limit is named once, here. A constant is known at compile time, so it can size the array // as well as bound the loops, and changing it changes both. const Limit = 100; func Main() -> int { // One flag per number, indexed by the number itself, none crossed out yet. var crossedOut = [false; Limit]; // 0 and 1 are not prime, and no pass below would cross them out. crossedOut[0] = true; crossedOut[1] = true; // Cross out the multiples of each surviving number. Each pass starts at n * n: a smaller // multiple k * n, with k below n, also has the factor k, so the pass for k (or for a prime // factor of k) has already crossed it out. For the same reason the passes can stop once // n * n reaches the limit, because such an n has no multiples left to visit. var n = 2; while n * n < Limit { if !crossedOut[n] { var multiple = n * n; while multiple < Limit { crossedOut[multiple] = true; multiple += n; } } n += 1; } // Everything still standing is prime. var found = 0; Print("primes below {}:", Limit); for i in 0..Limit { if !crossedOut[i] { Print(" {}", i); found += 1; } } PrintLine(); PrintLine("{} of them", found); return 0; } ``` ## Run it ```sh cd Examples/Projects/Prime rux run ``` ```text primes below 100: 2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97 25 of them ``` ## Common mistakes ::mistake **Sizing the array with a run-time value.**:br`let size = 100;` followed by `[false; size]` is refused: ```text error: array repeat count must be a non-negative compile-time integer ``` An inline array's length is fixed when the program is compiled, so it comes from a literal or a `const`. :: ::mistake **Declaring the flags with `let`.**:br`let crossedOut = [false; Limit];` makes the array immutable, and every write to it fails with: ```text error: cannot modify immutable variable 'crossedOut' ``` :: ::mistake **Indexing one past the end.**:br The last valid index is `Limit - 1`. Writing `crossedOut[Limit] = true;` still compiles, but the run stops with the line it happened on and this message: ```text Panic: index out of range ``` Keep the loops' conditions as `< Limit`, never `<= Limit`. :: ## Try it yourself 1. Raise the limit to 1000. Only one line changes, and the program should report 168 primes. 2. Print the primes ten to a line, the way [FizzBuzz](https://rux-lang.dev/docs/learn/fizz-buzz) lays out its answers. 3. Count how many times `crossedOut[multiple] = true;` runs. Then change the inner loop to start at `2 * n` instead of `n * n` and count again — the answer stays the same, but the work does not. 4. Twin primes are pairs that differ by 2, such as 11 and 13. After the sieve, walk the array once more and print every twin pair below the limit. ## Learn more - [Array repeat](https://rux-lang.dev/docs/learn/array-repeat) and [Array](https://rux-lang.dev/docs/learn/array) — inline arrays and their fixed length - [Const](https://rux-lang.dev/docs/learn/const) — values the compiler knows - [Arrays](https://rux-lang.dev/docs/lang/arrays/overview) in the Rux Reference - Next project: [Calculator](https://rux-lang.dev/docs/learn/calculator), the checkpoint for Errors # Calculator ::note **You'll need**: Parts 1–9 — this project is the checkpoint for Errors, and leans on [Fail](https://rux-lang.dev/docs/learn/fail), [Propagate](https://rux-lang.dev/docs/learn/propagate), [Catch fallback](https://rux-lang.dev/docs/learn/catch-fallback) and [Error variant](https://rux-lang.dev/docs/learn/error-variant). :: A pocket calculator shows "E" when something goes wrong and leaves you guessing. This one works on 32-bit integers and says exactly **why** it cannot give an answer: you divided by zero, pressed a key that is not an operator, or asked for a result too large for an `int32`. It is the checkpoint for [Part 9: Errors](https://rux-lang.dev/docs/learn/errors), and it uses each of the main tools from that part in the place where it fits best: `fail` to raise an error, `?` to pass one on, `match` to take one apart, and `catch` to recover and carry on. ## How it is put together Every way a sum can go wrong is a case of one error variant, and each case carries the detail that explains it: ```rux variant CalcError { DivisionByZero, UnknownOperator(char), Overflow(int64) } ``` Five small functions share the work, plus `PrintTape`, which only echoes a tape. Arrows show who calls whom, and what travels back: ```mermaid flowchart LR main(["`Main`"]) --> apply["`Apply`<br/>one sum"] main --> run["`Run`<br/>a whole tape"] run -- "each step, with `?`" --> apply apply -- "the answer, with `?`" --> narrow["`Narrow`<br/>`int64` → `int32`"] main --> show["`Show`<br/>`.Success` or `.Failure`"] show --> explain["`Explain`<br/>one line per case"] ``` | Function | What it does with an error | Lessons it uses | | --------- | ---------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `Narrow` | Raises `Overflow` when the answer does not fit | [Fail](https://rux-lang.dev/docs/learn/fail), [Convert](https://rux-lang.dev/docs/learn/convert) | | `Apply` | Raises the other two, passes `Narrow`'s on | [Fail](https://rux-lang.dev/docs/learn/fail), [Match expression](https://rux-lang.dev/docs/learn/match-expression), [Propagate](https://rux-lang.dev/docs/learn/propagate) | | `Run` | Passes the first failure of a tape on | [Propagate](https://rux-lang.dev/docs/learn/propagate), [Tuple](https://rux-lang.dev/docs/learn/tuple), [Destructure](https://rux-lang.dev/docs/learn/destructure) | | `Show` | Opens the outcome | [Outcome](https://rux-lang.dev/docs/learn/outcome) | | `Explain` | Turns each case into a sentence | [Error variant](https://rux-lang.dev/docs/learn/error-variant), [Variant match](https://rux-lang.dev/docs/learn/variant-match) | | `Main` | Skips bad steps on the forgiving tape | [Catch fallback](https://rux-lang.dev/docs/learn/catch-fallback) | ## Overflow is checked in a wider type Adding or multiplying two `int32`s can overflow `int32`, but no sum, difference or product of two `int32`s can overflow `int64`. So `Apply` widens both operands, does the arithmetic there, and `Narrow` checks the answer on its way back down: ```rux func Narrow(wide: int64) -> int32 ! CalcError { if wide > 2147483647 || wide < -2147483648 { fail CalcError::Overflow(wide); } return wide as int32; } ``` That catches the case everyone expects, `2147483647 + 1`, and one people usually miss: `-2147483648 / -1`. The answer, 2147483648, is one more than an `int32` can hold, because the negative range reaches one further than the positive one. ## A match arm that fails Inside `Apply`, a `match` expression picks the operation. Its last arm does not produce a value at all — it leaves the function through the failure channel: ```rux let wide = match op { '+' => a + b, '-' => a - b, '*' => a * b, '/' => a / b, '%' => a % b, else => fail CalcError::UnknownOperator(op) }; return Narrow(wide)?; ``` Division by zero is tested before the `match`, so `/` and `%` are never reached with a zero divisor. And `return Narrow(wide)?;` passes an overflow straight to `Apply`'s caller: `?` keeps the success and hands any failure on unchanged. ## A tape stops at the first bad key A tape is a run of key presses, each applied to the answer so far — like a real pocket calculator, strictly left to right, with no precedence. `Run` walks it, and one `?` is all it takes to make the first failure end the whole run: ```rux for step in tape { let (op, operand) = step; total = Apply(total, op, operand)?; } ``` Each step is a tuple `(char, int32)`, and `let (op, operand) = step;` unpacks it. The bad tape fails at its second key, `/ 0`, so the `x` key after it is never even looked at. ## Forgiving instead of failing The end of `Main` runs the same bad tape a second time, but with `catch` instead of `?`. A step that fails leaves `total` as it was, and the tape carries on: ```rux total = Apply(total, op, operand) catch { else => total }; ``` `/ 0` and `x 2` are skipped, so the tape computes `(0 + 10) * 7 - 6`, which is 64. Which behaviour is right — stop at the first error or skip it — is a design decision, and the two loops show that it is decided by a single token. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Projects/Calculator){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // Calculator: a pocket calculator that works on 32-bit integers and says exactly why when it // cannot give an answer. // // A real calculator shows "E" and leaves you guessing. This one has an error variant with one case // for each way a sum can go wrong, carrying whatever detail explains it: dividing by zero, a key // that is not an operator, and an answer too large for an `int32`. // // The arithmetic happens in `int64`, where no two `int32` values can overflow, and the answer is // then checked on its way back down. That catches the cases people expect, such as 2147483647 + 1, // and one they usually do not: -2147483648 / -1, whose answer is one more than an `int32` holds. // // The program uses each of the main tools from the Errors part. `Apply` raises one with // `fail`. `Run` passes one on with `?`, so a tape of key presses stops at the first bad step. // `Show` and `Explain` take one apart with `match`. And the forgiving calculator at the end uses // `catch` to skip a bad step and carry on. import Io::{ Print, PrintLine }; variant CalcError { DivisionByZero, UnknownOperator(char), Overflow(int64) } // Brings a wide answer back to `int32`, or fails if it does not fit. func Narrow(wide: int64) -> int32 ! CalcError { if wide > 2147483647 || wide < -2147483648 { fail CalcError::Overflow(wide); } return wide as int32; } func Apply(left: int32, op: char, right: int32) -> int32 ! CalcError { if (op == '/' || op == '%') && right == 0 { fail CalcError::DivisionByZero; } let a = left as int64; let b = right as int64; // An arm may fail instead of producing a value: an unknown key ends the function right there. let wide = match op { '+' => a + b, '-' => a - b, '*' => a * b, '/' => a / b, '%' => a % b, else => fail CalcError::UnknownOperator(op) }; return Narrow(wide)?; } // Presses the keys of a tape one after another, starting from `start`. The first step that fails // fails the whole run, and `?` is all it takes to say so. func Run(start: int32, tape: (char, int32)[..]) -> int32 ! CalcError { var total = start; for step in tape { let (op, operand) = step; total = Apply(total, op, operand)?; } return total; } func Explain(error: CalcError) { match error { .DivisionByZero => PrintLine("error: division by zero"), .UnknownOperator(op) => PrintLine("error: '{}' is not an operator", op), .Overflow(wide) => PrintLine("error: {} does not fit in an int32", wide) } } func Show(outcome: int32 ! CalcError) { match outcome { .Success(answer) => PrintLine("{}", answer), .Failure(error) => Explain(error) } } func PrintTape(start: int32, tape: (char, int32)[..]) { Print("{}", start); for step in tape { let (op, operand) = step; Print(" {} {}", op, operand); } Print(" = "); } func Main() -> int { let sums: (int32, char, int32)[9] = [ (12, '+', 30), (7, '*', 6), (17, '%', 5), (7, '/', 0), (7, '%', 0), (2, '^', 8), (2147483647, '+', 1), (-2147483648, '/', -1), (65536, '*', 65536) ]; for sum in sums { let (left, op, right) = sum; Print("{} {} {} = ", left, op, right); Show(Apply(left, op, right)); } PrintLine(); // A tape is a run of key presses, each applied to the answer so far. Like a pocket calculator, // it works strictly left to right, with no precedence: 1 + 2 * 3 is 9 on a tape, not 7. let good: (char, int32)[4] = [('+', 10), ('*', 7), ('-', 6), ('/', 8)]; let bad: (char, int32)[5] = [('+', 10), ('/', 0), ('*', 7), ('x', 2), ('-', 6)]; PrintTape(0, good); Show(Run(0, good)); PrintTape(0, bad); Show(Run(0, bad)); // A forgiving calculator ignores a key it cannot use. `catch { else => total }` keeps the // answer it already had, whatever went wrong, and the tape carries on past the bad steps. var total: int32 = 0; for step in bad { let (op, operand) = step; total = Apply(total, op, operand) catch { else => total }; } PrintLine("skipping the bad keys instead: {}", total); return 0; } ``` ## Run it ```sh cd Examples/Projects/Calculator rux run ``` ```text 12 + 30 = 42 7 * 6 = 42 17 % 5 = 2 7 / 0 = error: division by zero 7 % 0 = error: division by zero 2 ^ 8 = error: '^' is not an operator 2147483647 + 1 = error: 2147483648 does not fit in an int32 -2147483648 / -1 = error: 2147483648 does not fit in an int32 65536 * 65536 = error: 4294967296 does not fit in an int32 0 + 10 * 7 - 6 / 8 = 8 0 + 10 / 0 * 7 x 2 - 6 = error: division by zero skipping the bad keys instead: 64 ``` ## Common mistakes ::mistake **Calling a fallible function and ignoring the result.**:br A line such as `Apply(1, '+', 2);` on its own is refused: ```text error: fallible result of type 'int32 ! CalcError' is discarded ``` A failure must be handled, passed on or discarded on purpose — see [Discard](https://rux-lang.dev/docs/learn/discard). :: ::mistake **Forgetting the `?` in `Run`.**:br Without it, `total = Apply(total, op, operand);` tries to store the whole outcome in an `int32`: ```text error: cannot assign 'int32 ! CalcError' to 'int32' ``` The `?` is what unwraps the success. :: ::mistake **A match that misses a case.**:br Delete the `.DivisionByZero` arm from `Explain` and the compiler names what is missing: ```text error: match on 'CalcError' is not exhaustive; missing CalcError::DivisionByZero ``` Adding a case to `CalcError` later makes every such `match` point at itself, which is exactly what you want. :: ::mistake **A comma after the last arm.**:br The arms of a `match` are separated by commas, and the last one has none. Leaving one there fails with: ```text error: trailing comma is not allowed in match blocks ``` :: ## Try it yourself 1. Add a `^` key for powers, with `2 ^ 8` giving 256. Compute it with a loop in `int64` and let `Narrow` catch a power that is too large. What should a negative exponent do — and does it need a new case in `CalcError`? 2. Add a case `NegativeRoot` and an `r` key that takes an integer square root, failing for a negative operand. The compiler will show you every `match` that needs a new arm. 3. Make the forgiving calculator report what it skipped. Replace the `catch` with a `match` on the outcome: store the answer on `.Success`, and call `Explain` on `.Failure` while `total` stays as it was. 4. Change `Run` so that it returns the number of the step that failed along with the error. Hint: a new error type that carries a `uint` and a `CalcError`, and [Error mapping](https://rux-lang.dev/docs/learn/error-mapping) to build it. ## Learn more - [Error variant](https://rux-lang.dev/docs/learn/error-variant), [Fail](https://rux-lang.dev/docs/learn/fail), [Propagate](https://rux-lang.dev/docs/learn/propagate) and [Catch fallback](https://rux-lang.dev/docs/learn/catch-fallback) - [Error handling](https://rux-lang.dev/docs/lang/errors/overview) in the Rux Reference - Next projects: [Circle](https://rux-lang.dev/docs/learn/circle) and [Quadratic](https://rux-lang.dev/docs/learn/quadratic), which apply the same ideas to input a person types # Circle ::note **You'll need**: Parts 1–14 — this project is the checkpoint for Text, and leans on [Input](https://rux-lang.dev/docs/learn/input), [Parse](https://rux-lang.dev/docs/learn/parse), [String view](https://rux-lang.dev/docs/learn/string-view), [Error variant](https://rux-lang.dev/docs/learn/error-variant) and [Destructor](https://rux-lang.dev/docs/learn/destructor) — plus [Float special](https://rux-lang.dev/docs/learn/float-special) and [Math](https://rux-lang.dev/docs/learn/math) from Part 16. :: This program asks for the radius of a circle and prints its circumference and area. The arithmetic is two lines. Everything else is about the input: a person can type anything, or nothing, and a good program tells them which kind of unusable answer they gave. It is a checkpoint for [Part 14: Text](https://rux-lang.dev/docs/learn/text) — reading a line, trimming it and parsing a number — and it borrows `IsFinite` and `Pi` from [Float special](https://rux-lang.dev/docs/learn/float-special) and [Math](https://rux-lang.dev/docs/learn/math) in Part 16. ## How it is put together Every way the input can be unusable is a case of one error variant: ```rux variant RadiusError { Ended, Unreadable, NotANumber, Negative(float64), NotFinite } ``` `ReadRadius` reads, parses and checks, failing with the first case that applies. `Main` asks once and opens the outcome with one exhaustive `match` — a radius on `.Success`, a sentence for each case on `.Failure`: ```mermaid flowchart LR read["`ReadLine`"] -- "end of input" --> ended["`Ended`"] read -- "other read error" --> unreadable["`Unreadable`"] read -- "a line" --> parse["`ParseFloat64`<br/>of the trimmed line"] parse -- "too large" --> nf["`NotFinite`"] parse -- "malformed" --> nan["`NotANumber`"] parse -- "a `float64`" --> finite{"`IsFinite`?"} finite -- "no: `Inf` or `NaN`" --> nf finite -- "yes" --> sign{"below zero?"} sign -- "yes" --> neg["`Negative`"] sign -- "no" --> ok(["the radius"]) ``` | Piece | Lessons it uses | | --------------------------------- | ------------------------------------------------------------------------------------------------------------------------ | | `ReadLine` into a `StringBuilder` | [Input](https://rux-lang.dev/docs/learn/input), [String builder](https://rux-lang.dev/docs/learn/string-builder) | | `.View().Trim()` | [String view](https://rux-lang.dev/docs/learn/string-view) | | `ParseFloat64` and its `catch` | [Parse](https://rux-lang.dev/docs/learn/parse), [Catch](https://rux-lang.dev/docs/learn/catch) | | The match guard on `error.kind` | [Guard](https://rux-lang.dev/docs/learn/guard), [Outcome](https://rux-lang.dev/docs/learn/outcome) | | `RadiusError` and its `match` | [Error variant](https://rux-lang.dev/docs/learn/error-variant), [Exhaustive](https://rux-lang.dev/docs/learn/exhaustive) | | `IsFinite`, `Pi` | [Float special](https://rux-lang.dev/docs/learn/float-special), [Math](https://rux-lang.dev/docs/learn/math) | | The builder's memory | [Allocator](https://rux-lang.dev/docs/learn/allocator), [Destructor](https://rux-lang.dev/docs/learn/destructor) | ## Reading a line, and the end of the input `ReadLine` appends one line to a builder and returns a fallible. Reaching the end of the input is not a crash but an `IoError` whose kind is `EndOfStream`, and a match guard tells it apart from every other read failure: ```rux match ReadLine(builder) { .Success(_) => {}, .Failure(error) if error.kind == IoErrorKind::EndOfStream => fail RadiusError::Ended, .Failure(_) => fail RadiusError::Unreadable } ``` The arms are tried in order, so the guarded arm must come before the general `.Failure(_)`. The input ends when you press Ctrl+Z and Enter on Windows or Ctrl+D elsewhere, or when piped input runs out. ## Parsing, and why a number still needs checking The line is trimmed, so `" 2.5 "` is read as 2.5, and then parsed. `catch` translates the parser's errors into this program's own cases: ```rux let radius = ParseFloat64(builder.View().Trim()) catch { .Overflow(_) => fail RadiusError::NotFinite, else => fail RadiusError::NotANumber }; if !IsFinite(radius) { fail RadiusError::NotFinite; } if radius < 0.0 { fail RadiusError::Negative(radius); } ``` A successful parse is not yet a radius. The parser reads `Inf` and `NaN`, because that is how such values print, so `IsFinite` has to rule them out separately. A number such as `1e400` is too large for a `float64`; the parser reports it as an `Overflow`, and the program counts it as "not finite" too, since it is a number — just not one a `float64` can hold. The order of the checks matters for NaN: every comparison with NaN is false, so `radius < 0.0` alone would let it through. ## Negative zero `-0` parses to −0.0, and it passes `radius < 0.0` because −0.0 equals 0.0. Left alone, it would print as `Radius: -0.0` and `Circumference: -0.0000`. Adding zero turns it into a plain 0: ```rux return radius + 0.0; ``` ## A finite radius with an infinite area The last surprise is in `Main`. A radius can be finite and its area still overflow: `1e200` squared is far past the largest `float64`, so the area is infinity. The program checks the result before printing it: ```rux let circumference = 2.0 * Pi * radius; let area = Pi * radius * radius; PrintLine(); if !IsFinite(area) { PrintLine("A radius of {} is too large: the area is past float64", radius); return 1; } ``` Every refusal exits with status 1, so a script that runs the program can tell success from failure without reading the text. ## No cleanup code The builder takes memory from the allocator, yet `Main` has three `return`s and none of them frees anything. The builder's **destructor** runs when `Main` returns, whichever `return` it leaves by, and gives the memory back. That is [Destructor](https://rux-lang.dev/docs/learn/destructor) doing the work a cleanup call would otherwise have to repeat on every path. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Projects/Circle){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // Reading a radius the user types and working out the circle it describes. The arithmetic is two // lines; the rest of the program is about every way the input can be unusable, and telling the // user which one happened: // // the input ended end of input before any line arrived (Ctrl+Z, or an empty pipe) // the input failed a read error, or a line that is not valid UTF-8 // not a number the line does not spell a number at all // not a radius a number, but negative, infinite or NaN // // Each is a case of one error variant, so `Main` handles them in one exhaustive `match`. The // parser reads "Inf" and "NaN" because that is how such values print, which is why a parsed // number still has to be checked before it is trusted. import Allocator::{ Allocator, SystemAllocator }; import Core::IsFinite; import Format::ParseFloat64; import Io::{ IoErrorKind, Print, PrintLine, ReadLine }; import Math::Pi; import Text::StringBuilder; variant RadiusError { Ended, Unreadable, NotANumber, Negative(float64), NotFinite } func ReadRadius(builder: &var StringBuilder) -> float64 ! RadiusError { match ReadLine(builder) { .Success(_) => {}, .Failure(error) if error.kind == IoErrorKind::EndOfStream => fail RadiusError::Ended, .Failure(_) => fail RadiusError::Unreadable } // Trimming lets " 2.5 " through. A number too large for a float64 is reported as an // `Overflow`: it is a number, just not a finite one, so it joins Inf and NaN. let radius = ParseFloat64(builder.View().Trim()) catch { .Overflow(_) => fail RadiusError::NotFinite, else => fail RadiusError::NotANumber }; if !IsFinite(radius) { fail RadiusError::NotFinite; } if radius < 0.0 { fail RadiusError::Negative(radius); } // `-0` passes the test above, since -0.0 == 0.0. Adding zero makes it a plain 0. return radius + 0.0; } func Main() -> int { var system = SystemAllocator(); let allocator: Allocator = system; // The builder owns memory from the allocator. Its destructor gives that memory back when // `Main` returns, whichever `return` it leaves by, so no path needs a cleanup call. var builder = StringBuilder(allocator); // `Print` rather than `PrintLine`, so an answer typed at the console stays on the same line. Print("Circle radius: "); match ReadRadius(builder) { .Success(radius) => { // A finite radius can still give an infinite area: 1e200 squared is past float64. let circumference = 2.0 * Pi * radius; let area = Pi * radius * radius; PrintLine(); if !IsFinite(area) { PrintLine("A radius of {} is too large: the area is past float64", radius); return 1; } PrintLine("Radius: {}", radius); PrintLine("Circumference: {:.4}", circumference); PrintLine("Area: {:.4}", area); return 0; }, .Failure(error) => { // Piped input leaves the cursor after the prompt, so the report starts a new line. PrintLine(); match error { .Ended => PrintLine("The input ended before a radius was entered"), .Unreadable => PrintLine("The input could not be read"), .NotANumber => PrintLine("That is not a number"), .Negative(radius) => PrintLine("A radius cannot be negative, and {} is", radius), .NotFinite => PrintLine("A radius must be a finite number") } return 1; } } } ``` Besides `Io`, its `Rux.toml` lists `Allocator`, `Core`, `Format`, `Math` and `Text` under `[Dependencies]`. ## Run it ```sh cd Examples/Projects/Circle rux run ``` ```text Circle radius: 2.5 Radius: 2.5 Circumference: 15.7080 Area: 19.6350 ``` Piped input works too. The typed value is not echoed then, so each report follows the prompt on a line of its own: ```sh "-3" | rux run "two" | rux run $null | rux run ``` ```text Circle radius: A radius cannot be negative, and -3.0 is Circle radius: That is not a number Circle radius: The input ended before a radius was entered ``` `Inf`, `NaN` and numbers too large for a `float64` are refused as not finite. Every refusal exits with status 1. The program waits for you to type. Run it, type a radius after the prompt and press Enter. To try the refusals, type `-3`, `two`, `Inf` or `1e200`, or end the input straight away with Ctrl+Z and Enter on Windows (Ctrl+D elsewhere). The piped examples above are written for PowerShell; in a POSIX shell, `echo -3 | rux run` does the same. ## Common mistakes ::mistake **Calling `ReadRadius` without looking at the result.**:br A bare `ReadRadius(builder);` is refused: ```text error: fallible result of type 'float64 ! RadiusError' is discarded ``` The whole program is about what that result says, so it has to be matched. :: ::mistake **Leaving a case out of the final match.**:br Remove the `.Unreadable` arm from `Main` and the build stops with: ```text error: match on 'RadiusError' is not exhaustive; missing RadiusError::Unreadable ``` This is the reason to put every failure in one variant: adding a sixth case later makes the compiler point at every `match` that must learn about it. :: ::mistake **Trusting a parsed number.**:br Take the `IsFinite` check out of `ReadRadius` and type `Inf`: the program no longer refuses it as a radius, but reaches the area check and reports: ```text A radius of Inf is too large ``` Take the sign check out and `-3` gives a negative circumference. Parsing tells you the text is a number, not that it is a sensible one. :: ## Try it yourself 1. Also print the diameter, and the radius of a circle with twice the area. ([Math](https://rux-lang.dev/docs/learn/math) has `Sqrt`.) 2. Refuse a radius of exactly zero with a case of its own, `Zero`, and a message to match. Let the compiler show you where the new case must be handled. 3. Keep asking until a valid radius arrives: put the `Print` and the call in a loop, and leave it only on success or on `Ended`. Remember that the builder is reused, so it must be cleared before each read — [Quadratic](https://rux-lang.dev/docs/learn/quadratic) shows how. 4. Ask for a second radius and print the area of the ring between the two circles. ## Learn more - [Input](https://rux-lang.dev/docs/learn/input), [Parse](https://rux-lang.dev/docs/learn/parse) and [String view](https://rux-lang.dev/docs/learn/string-view) - [Float special](https://rux-lang.dev/docs/learn/float-special) — infinity, NaN and negative zero - [ReadLine](https://rux-lang.dev/docs/api/io/read-line) and the [Math](https://rux-lang.dev/docs/api/math) package in the API reference - Next project: [Quadratic](https://rux-lang.dev/docs/learn/quadratic), the same input handling for three numbers # Quadratic ::note **You'll need**: Parts 1–14 — this project is the checkpoint for Text, and leans on [Input](https://rux-lang.dev/docs/learn/input), [Parse](https://rux-lang.dev/docs/learn/parse), [String view](https://rux-lang.dev/docs/learn/string-view) and [Error variant](https://rux-lang.dev/docs/learn/error-variant) — plus [Float special](https://rux-lang.dev/docs/learn/float-special) and [Math](https://rux-lang.dev/docs/learn/math) from Part 16. :: This program reads three numbers, a, b and c, and solves the equation a x² + b x + c = 0. It is the classic calculation whose **shape** depends on its input: depending on the numbers there are two answers, one, a pair of complex ones, or — when `a` is zero and the equation is not really quadratic at all — one answer, none, or infinitely many. Like [Circle](https://rux-lang.dev/docs/learn/circle), it is a checkpoint for [Part 14: Text](https://rux-lang.dev/docs/learn/text), and it reads its input with the same care. What it adds is a decision tree with six leaves, and a lesson in floating-point arithmetic that the textbook formula gets wrong. ## How it is put together The program splits cleanly into reading and solving: | Function | Its job | Lessons it uses | | ----------------- | -------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `ReadCoefficient` | Prompt, read one line, parse it, check it is finite | [Input](https://rux-lang.dev/docs/learn/input), [Parse](https://rux-lang.dev/docs/learn/parse), [String view](https://rux-lang.dev/docs/learn/string-view), [Fail](https://rux-lang.dev/docs/learn/fail) | | `Explain` | One sentence for each `EntryError` | [Error variant](https://rux-lang.dev/docs/learn/error-variant) | | `SolveLinear` | The three cases where `a` is zero | [Else if](https://rux-lang.dev/docs/learn/else-if) | | `SolveQuadratic` | The discriminant and the three quadratic cases | [Math](https://rux-lang.dev/docs/learn/math) (`Sqrt`), [Float special](https://rux-lang.dev/docs/learn/float-special), [Ternary](https://rux-lang.dev/docs/learn/ternary) | | `Main` | Reads a, b and c, stopping at the first bad one, then picks a solver | [Catch](https://rux-lang.dev/docs/learn/catch), [Destructor](https://rux-lang.dev/docs/learn/destructor) | Once the three numbers are in, the cases fall out like this: ```mermaid flowchart LR start(["a, b, c"]) --> qa{"a = 0?"} qa -- "no" --> d{"discriminant<br/>b² − 4ac"} d -- "positive" --> two["two real roots"] d -- "zero" --> one["one repeated root"] d -- "negative" --> cx["a complex pair"] qa -- "yes" --> qb{"b = 0?"} qb -- "no" --> lin["linear: x = −c / b"] qb -- "yes" --> qc{"c = 0?"} qc -- "no" --> none["no solution"] qc -- "yes" --> all["every x"] ``` ## One reader, three times `ReadCoefficient` prints its own prompt and reuses one builder for every line, so it clears the builder first. Otherwise the second line would be appended to the first: ```rux func ReadCoefficient(name: char8[..], builder: &var StringBuilder) -> float64 ! EntryError { Print("{} = ", name); builder.Clear(); ``` The rest is [Circle](https://rux-lang.dev/docs/learn/circle)'s reader: end of input, read failure, not a number, not finite. In `Main` each call handles its failure on the spot with a `catch` arm that explains and leaves: ```rux let a = ReadCoefficient("a", builder) catch { error => { Explain(error); return 1; } }; let b = ReadCoefficient("b", builder) catch { error => { Explain(error); return 1; } }; let c = ReadCoefficient("c", builder) catch { error => { Explain(error); return 1; } }; ``` The arm `error =>` binds whichever case it was, so a single `Explain` covers them all. ## The degenerate cases When `a` is zero the quadratic formula would divide by zero, so those inputs never reach it. `SolveLinear` handles them with a three-way chain: ```rux if b != 0.0 { PrintLine("linear, not quadratic: x = {}", -c / b + 0.0); } else if c != 0.0 { PrintLine("inconsistent: {} = 0 is never true, so there is no solution", c); } else { PrintLine("an identity: 0 = 0 holds for every x"); } ``` The `+ 0.0` is the negative-zero fix from Circle: with c = 0, `-c / b` is −0.0, and adding zero makes it print as `0.0`. ## Two real roots without losing one The textbook formula is (−b ± √disc) / 2a. When b is large and 4ac is small, √disc is almost exactly |b|, and one of the two roots comes from subtracting two nearly equal numbers. Most of their digits cancel, and the rounding error that is left becomes most of the answer. The program avoids the subtraction. It computes the larger root by **adding** two numbers of the same sign — which never cancels — and gets the other from Vieta's rule, x₁ · x₂ = c / a: ```rux let root = Sqrt(discriminant); let q = b >= 0.0 ? -(b + root) / 2.0 : (root - b) / 2.0; let first = q / a; let second = c / q; ``` The difference is real. For a = 1, b = 1e8, c = 1 the program prints the small root as `-1.0e-08`, which is right to every digit shown. The textbook formula, written the obvious way, gives `-7.450580596923828e-09` — wrong by a quarter. ## Complex roots A negative discriminant has no real square root, but the roots still exist as a complex pair: a real part plus or minus an imaginary part. The program prints them as text, dividing by |2a| so that the imaginary part is always positive and the `+` and `-` it prints are the signs it means: ```rux let real = -b / (2.0 * a) + 0.0; let twiceA = a < 0.0 ? -2.0 * a : 2.0 * a; let imaginary = Sqrt(-discriminant) / twiceA; ``` Before any of this, `SolveQuadratic` checks that the discriminant itself is finite: b = 1e200 is a perfectly finite coefficient, but b² is not. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Projects/Quadratic){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // Solving a x^2 + b x + c = 0, the classic calculation whose *shape* depends on its input. // // With `a` not zero it is a quadratic, and the discriminant b^2 - 4ac decides the answer: two // real roots when it is positive, one repeated root when it is zero, and a complex pair when it // is negative. With `a` zero it is not a quadratic at all, and the formula would divide by zero: // // a = 0, b != 0 linear, one root x = -c / b // a = 0, b = 0, c != 0 inconsistent, no x makes c equal 0 // a = 0, b = 0, c = 0 an identity, every x is a solution // // Reading comes first, and every way it can go wrong is a case of one error variant: the input // may end early, fail to read, not spell a number, or spell one that is not finite. The parser // accepts "Inf" and "NaN", because that is how such values print, so finiteness is checked // separately. import Allocator::{ Allocator, SystemAllocator }; import Core::IsFinite; import Format::ParseFloat64; import Io::{ IoErrorKind, Print, PrintLine, ReadLine }; import Math::Sqrt; import Text::StringBuilder; variant EntryError { Ended, Unreadable, NotANumber, NotFinite } // Reads one coefficient. The builder is reused for every line, so it is cleared first, and the // view is trimmed so that " 2 " reads as 2. func ReadCoefficient(name: char8[..], builder: &var StringBuilder) -> float64 ! EntryError { Print("{} = ", name); builder.Clear(); match ReadLine(builder) { .Success(_) => {}, .Failure(error) if error.kind == IoErrorKind::EndOfStream => fail EntryError::Ended, .Failure(_) => fail EntryError::Unreadable } // A number past the largest float64 is an `Overflow`, not a malformed one: it is a number, // just not a finite float64, so it joins Inf and NaN. let value = ParseFloat64(builder.View().Trim()) catch { .Overflow(_) => fail EntryError::NotFinite, else => fail EntryError::NotANumber }; if !IsFinite(value) { fail EntryError::NotFinite; } return value; } // Each report starts on a fresh line, since piped input leaves the cursor after the prompt. func Explain(error: EntryError) { PrintLine(); match error { .Ended => PrintLine("the input ended before all three coefficients were given"), .Unreadable => PrintLine("the input could not be read"), .NotANumber => PrintLine("that is not a number"), .NotFinite => PrintLine( "a coefficient must be finite: Inf, NaN and numbers past float64 are refused") } } func SolveLinear(b: float64, c: float64) { if b != 0.0 { // Adding zero turns -0 into 0, so c = 0 prints "x = 0.0" rather than "x = -0.0". PrintLine("linear, not quadratic: x = {}", -c / b + 0.0); } else if c != 0.0 { PrintLine("inconsistent: {} = 0 is never true, so there is no solution", c); } else { PrintLine("an identity: 0 = 0 holds for every x"); } } func SolveQuadratic(a: float64, b: float64, c: float64) { // Finite coefficients can still overflow: b = 1e200 makes b^2 infinite. let discriminant = b * b - 4.0 * a * c; if !IsFinite(discriminant) { PrintLine("the coefficients are too large to solve in float64"); return; } if discriminant > 0.0 { // The textbook formula subtracts two nearly equal numbers when 4ac is small, and loses // the smaller root to rounding. Adding numbers of the same sign never cancels, so find // the larger root that way, then the other from x1 * x2 = c / a. let root = Sqrt(discriminant); let q = b >= 0.0 ? -(b + root) / 2.0 : (root - b) / 2.0; let first = q / a; let second = c / q; let low = first < second ? first : second; let high = first < second ? second : first; PrintLine("two real roots: x1 = {}, x2 = {}", low, high); } else if discriminant == 0.0 { PrintLine("one repeated root: x = {}", -b / (2.0 * a) + 0.0); } else { // No real root, but the complex pair is real part +/- imaginary part. Dividing by |2a| // keeps the imaginary part positive, so the signs printed are the signs meant. let real = -b / (2.0 * a) + 0.0; let twiceA = a < 0.0 ? -2.0 * a : 2.0 * a; let imaginary = Sqrt(-discriminant) / twiceA; PrintLine("complex roots: x = {} + {}i and x = {} - {}i", real, imaginary, real, imaginary); } } func Main() -> int { var system = SystemAllocator(); let allocator: Allocator = system; // The builder's destructor returns its memory on every path out of `Main`. var builder = StringBuilder(allocator); PrintLine("Solving a x^2 + b x + c = 0"); let a = ReadCoefficient("a", builder) catch { error => { Explain(error); return 1; } }; let b = ReadCoefficient("b", builder) catch { error => { Explain(error); return 1; } }; let c = ReadCoefficient("c", builder) catch { error => { Explain(error); return 1; } }; PrintLine(); if a == 0.0 { SolveLinear(b, c); } else { SolveQuadratic(a, b, c); } return 0; } ``` Besides `Io`, its `Rux.toml` lists `Allocator`, `Core`, `Format`, `Math` and `Text` under `[Dependencies]`. ## Run it ```sh cd Examples/Projects/Quadratic rux run ``` ```text Solving a x^2 + b x + c = 0 a = 1 b = -3 c = 2 two real roots: x1 = 1.0, x2 = 2.0 ``` Piped input works too. The typed values are not echoed then, so the prompts run together: ```sh "1", "2", "5" | rux run "0", "0", "3" | rux run "1", "Inf" | rux run $null | rux run ``` ```text Solving a x^2 + b x + c = 0 a = b = c = complex roots: x = -1.0 + 2.0i and x = -1.0 - 2.0i Solving a x^2 + b x + c = 0 a = b = c = inconsistent: 3.0 = 0 is never true, so there is no solution Solving a x^2 + b x + c = 0 a = b = a coefficient must be finite: Inf, NaN and numbers past float64 are refused Solving a x^2 + b x + c = 0 a = the input ended before all three coefficients were given ``` Unusable input, including input that ends early, exits with status 1. The program waits for three answers. Run it and type a number after each prompt, pressing Enter each time. Try `1`, `2`, `1` for a repeated root, `0`, `2`, `0` for a linear equation, or `1`, `1e8`, `1` to see the careful formula at work. The piped examples above are written for PowerShell; in a POSIX shell, `printf '1\n2\n5\n' | rux run` does the same. ## Common mistakes ::mistake **Not clearing a reused builder.**:br`ReadLine` appends to the builder, without the line break. Leave out `builder.Clear()` and the answers `1`, `2`, `1` are read as 1, 12 and 121 — each line glued onto the ones before it — so instead of the repeated root −1 the program reports a complex pair, −6 ± 9.2195…i. Nothing fails; the answer is just wrong. :: ::mistake **Dividing by `a` before checking it.**:br With a = 0 the quadratic formula divides by zero. On floats that does not stop the program — it produces infinity or NaN, and the output is nonsense rather than an error. Decide the shape of the problem first, then calculate. :: ::mistake **Using the textbook formula for both roots.**:br It compiles and passes every small example, which is what makes it dangerous. The cancellation only shows up when b² is much larger than 4ac, as with b = 1e8 above. :: ## Try it yourself 1. Print the discriminant before the roots, so you can see which branch was taken and why. 2. Change the textbook-formula experiment into a permanent feature: print both the careful roots and the textbook ones, and the difference between them. 3. For two real roots, also print the vertex of the parabola: x = −b / 2a, and y found by putting that x back into the equation. 4. Let the user solve several equations in one run: after printing a result, ask for the next a, b and c, and stop cleanly when the input ends. ## Learn more - [Float special](https://rux-lang.dev/docs/learn/float-special) — infinity, NaN and negative zero - [Math](https://rux-lang.dev/docs/learn/math) — `Sqrt` and its domain - [Catch](https://rux-lang.dev/docs/learn/catch) — handling a failure in place with one arm per case - Previous project: [Circle](https://rux-lang.dev/docs/learn/circle), which reads one number the same way - Next project: [Word count](https://rux-lang.dev/docs/learn/word-count), a checkpoint for Collections # Word count ::note **You'll need**: Parts 1–17 — this project is a checkpoint for Collections, and leans on [String builder](https://rux-lang.dev/docs/learn/string-builder), [Hash map](https://rux-lang.dev/docs/learn/hash-map) and [Tree map](https://rux-lang.dev/docs/learn/tree-map). :: How often does each word appear in "How much wood would a woodchuck chuck"? This program counts every word of the tongue twister, prints the counts in alphabetical order with a little bar chart, and names the favourite word. Counting is what a hash map is for, and this project is a checkpoint for [Part 17: Collections](https://rux-lang.dev/docs/learn/collections). It also shows two habits that make text programs cheap: normalising the text once, up front, and using **views** into it as keys instead of copying every word into a new string. ## How it is put together The program is a pipeline of four steps, each feeding the next: ```mermaid flowchart LR lines["Five lines<br/>of the twister"] --> lower["One lower-case copy<br/>in a `StringBuilder`"] lower --> count["`HashMap`<br/>word → count"] count --> sorted["`TreeMap`<br/>same entries, sorted"] sorted --> report["Bars and<br/>the favourite"] ``` | Step | Lessons it uses | | -------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Lower-case copy | [String builder](https://rux-lang.dev/docs/learn/string-builder), [Encoding](https://rux-lang.dev/docs/learn/encoding) (`c8'a'`), [Propagate](https://rux-lang.dev/docs/learn/propagate) | | Splitting into words | [Slice](https://rux-lang.dev/docs/learn/slice), [Continue](https://rux-lang.dev/docs/learn/continue), [Range](https://rux-lang.dev/docs/learn/range) | | Counting | [Hash map](https://rux-lang.dev/docs/learn/hash-map), [Coalesce](https://rux-lang.dev/docs/learn/coalesce) (`?? 0`) | | Sorting | [Tree map](https://rux-lang.dev/docs/learn/tree-map) | | The report | [Format](https://rux-lang.dev/docs/learn/format) (`{:10}`), [For](https://rux-lang.dev/docs/learn/for) | | Failures | [Error sum](https://rux-lang.dev/docs/learn/error-sum), [Fallible main](https://rux-lang.dev/docs/learn/fallible-main) | ## Normalise once, up front "How" and "how" should be one word. Rather than compare words case-insensitively everywhere, the program makes **one** lower-case copy of the whole text, with a space where each line ended: ```rux func AppendLowercase(builder: &var StringBuilder, text: char8[..]) -> ! TextError { for c in text { if c >= c8'A' && c <= c8'Z' { builder.AppendAscii(c - c8'A' + c8'a')?; } else { builder.AppendAscii(c)?; } } } ``` `c - c8'A' + c8'a'` moves a capital letter to its small twin: the letters A to Z and a to z each sit in a row in ASCII, so the distance from `A` is the same as the distance from `a`. Appending can fail — the builder may need more memory — so each call ends in `?`, and the function's `! TextError` passes the failure on. ## Words are views, not copies The text is walked once. `start` marks where the current word began; any byte that is not a letter ends it, and the slice between the two is the word: ```rux for i in 0..=text.length { let inWord = i < text.length && IsLetter(text[i]); if inWord { continue; } if i > start { let word = text[start..i]; counts.Insert(word, (counts.Get(word) ?? 0) + 1)?; words += 1; } start = i + 1; } ``` Three details make this loop correct: - The range is `0..=text.length`, one step **past** the last byte. At that step `inWord` is false, so a word that runs to the very end of the text is still counted. The `i < text.length &&` test comes first, and `&&` short-circuits, so `text[i]` is never read out of range. - `i > start` skips empty words, which appear wherever two separators sit side by side, such as `", "`. - `text[start..i]` is a view into the lower-case copy: making it costs nothing. That is also why nothing may be appended to the builder after this point — the keys all point into it. ## Counting with a hash map The counting line reads like a sentence: look the word up, add one, store it back. `Get` returns an `int32?` — `none` for a word not seen before — and `?? 0` turns that absence into a count of zero: ```rux counts.Insert(word, (counts.Get(word) ?? 0) + 1)?; ``` The map is built with three things: an allocator, a function that hashes a slice, and one that compares two slices. A slice's `==` would compare the *views*, not the text they show, so the map is told how to compare the contents: ```rux var counts = HashMap<char8[..], int32>(allocator, HashSlice, EqualsSlice); ``` ## Sorting by copying into a tree map A hash map keeps no order — print it straight out and the words come in whatever order the hashing scattered them. A tree map always walks its keys in order, so copying the finished counts into one sorts them for free: ```rux var sorted = TreeMap<char8[..], int32>(allocator, CompareSlice); for entry in counts { sorted.Insert(entry.key, entry.value)?; } ``` The report then walks `sorted`. `{:10}` pads each word to ten columns so the counts line up, and a strict `>` when looking for the favourite means a tie goes to the word earlier in the alphabet. ## Two kinds of failure `Main` is declared `-> ! (CollectionError | TextError)`: the maps can fail with a `CollectionError` and the builder with a `TextError`. With a sum of both as `Main`'s failure, every `?` in the program passes its error straight up, and a failure ends the program with exit status 1. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Projects/WordCount){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // WordCount: how often does each word appear in a tongue twister? // // Counting is what a hash map is for. Each word is a key and its count the value: look the word // up, add one, store it back. A word not seen before is simply absent, and `?? 0` turns that // absence into a count of zero to add to. // // A hash map keeps no order, though, so printing it straight out would list the words however the // hashing scattered them. Copying the finished counts into a `TreeMap` sorts them by word for // free, because a tree map walks its keys in order. // // Two details make the words come out right. "How" and "how" should count as one word, so the // text is first copied in lower case. And the map's keys are slices of that copy, not new strings: // each word is a view of the bytes it occupies, which costs nothing to make. import Allocator::{ Allocator, SystemAllocator }; import Collections::{ CollectionError, CompareSlice, EqualsSlice, HashMap, HashSlice, TreeMap }; import Io::{ Print, PrintLine }; import Text::{ StringBuilder, TextError }; func IsLetter(c: char8) -> bool { return c >= c8'a' && c <= c8'z'; } // Adds the text to the builder with every capital letter A to Z made small, and the rest as it is. func AppendLowercase(builder: &var StringBuilder, text: char8[..]) -> ! TextError { for c in text { if c >= c8'A' && c <= c8'Z' { builder.AppendAscii(c - c8'A' + c8'a')?; } else { builder.AppendAscii(c)?; } } } func Main() -> ! (CollectionError | TextError) { var system = SystemAllocator(); let allocator: Allocator = system; let twister = [ "How much wood would a woodchuck chuck", "if a woodchuck could chuck wood?", "He would chuck, he would, as much as he could,", "and chuck as much wood as a woodchuck would", "if a woodchuck could chuck wood." ]; // One lower-case copy of the whole text, with a space where each line ended. Every key in the // maps below is a view into it, so nothing is appended to it after this loop. var lower = StringBuilder(allocator); for line in twister { AppendLowercase(lower, line)?; lower.AppendAscii(c8' ')?; } let text = lower.Bytes(); // Walk the text once. `start` marks where the current word began; a byte that is not a // letter ends the word, and the slice between them is the key. var counts = HashMap<char8[..], int32>(allocator, HashSlice, EqualsSlice); var words = 0; var start: uint = 0; for i in 0..=text.length { let inWord = i < text.length && IsLetter(text[i]); if inWord { continue; } if i > start { let word = text[start..i]; counts.Insert(word, (counts.Get(word) ?? 0) + 1)?; words += 1; } start = i + 1; } PrintLine("{} words, {} different", words, counts.Length()); PrintLine(); // Same entries, now in alphabetical order. var sorted = TreeMap<char8[..], int32>(allocator, CompareSlice); for entry in counts { sorted.Insert(entry.key, entry.value)?; } var top: char8[..] = ""; var topCount = 0; for entry in sorted { Print("{:10} {:2} ", entry.key, entry.value); for i in 0..entry.value { Print("*"); } PrintLine(); // Strictly greater, so a tie goes to the word earlier in the alphabet. if entry.value > topCount { top = entry.key; topCount = entry.value; } } PrintLine(); PrintLine("the favourite word is \"{}\", {} times", top, topCount); } ``` Besides `Io`, its `Rux.toml` lists `Allocator`, `Collections` and `Text` under `[Dependencies]`. ## Run it ```sh cd Examples/Projects/WordCount rux run ``` ```text 38 words, 12 different a 4 **** and 1 * as 4 **** chuck 5 ***** could 3 *** he 3 *** how 1 * if 2 ** much 3 *** wood 4 **** woodchuck 4 **** would 4 **** the favourite word is "chuck", 5 times ``` ## Common mistakes ::mistake **Using a lookup as if it were a count.**:br`counts.Get(word) + 1` is refused, because `Get` may find nothing: ```text error: operator '+' cannot combine left operand 'int32?' with right operand 'int' ``` Decide what absence means first — here `?? 0`. :: ::mistake **Dropping the `?` from an insertion.**:br`Insert` can fail when the map needs memory, so a bare `counts.Insert(…);` fails with: ```text error: fallible result of type '! CollectionError' is discarded ``` :: ::mistake **Normalising only half the program.**:br`IsLetter` accepts only `a` to `z`. Skip the lower-casing and the capitals become separators: "How" splits into a lost `H` and a word `ow`, "He" into `e`, and the report says 13 different words instead of 12. Normalise once, and then the rest of the program can assume it. :: ## Try it yourself 1. Print the words sorted by count, highest first, instead of alphabetically. One way: copy the entries into a [Vector](https://rux-lang.dev/docs/learn/vector) of structs and order it with `SortBy` from [Sort](https://rux-lang.dev/docs/learn/sort), in the next part. 2. Count letters as well as words. No map is needed: an array of 26 counters, `[0; 26]`, indexed by `c - c8'a'`, does the job. 3. Ignore the short words "a", "as", "he" and "if" by keeping them in a [Hash set](https://rux-lang.dev/docs/learn/hash-set) and skipping any word it contains. 4. Report the longest word as well as the most frequent one. When two are equally long, which one does your loop keep? ## Learn more - [Hash map](https://rux-lang.dev/docs/learn/hash-map) and [Tree map](https://rux-lang.dev/docs/learn/tree-map) — when order matters and when it does not - [String builder](https://rux-lang.dev/docs/learn/string-builder) and [Slice](https://rux-lang.dev/docs/learn/slice) - [Format](https://rux-lang.dev/docs/learn/format) — widths and alignment in placeholders - Next project: [Inventory](https://rux-lang.dev/docs/learn/inventory), the other checkpoint for Collections # Inventory ::note **You'll need**: Parts 1–17 — this project is a checkpoint for Collections, and leans on [Absence to error](https://rux-lang.dev/docs/learn/absence-to-error), [Error sum](https://rux-lang.dev/docs/learn/error-sum), [Typed pattern](https://rux-lang.dev/docs/learn/typed-pattern) and [Vector](https://rux-lang.dev/docs/learn/vector). :: This program keeps the stock list of a small shop — apples, bread, candles, milk — and applies a day of orders to it. Some orders are fine. Others ask for more than is on the shelf, for an item the shop has never stocked, or for a negative amount, and those are refused with a reason. It is a checkpoint for [Part 17: Collections](https://rux-lang.dev/docs/learn/collections), but most of what it practises comes from earlier: structs, variants with data, and above all fallible functions. Its rule is that **a refused order changes nothing**, so the stock is never left half-updated. ## How it is put together The data is three types. A `StockItem` is one line of the list, an `Order` is one thing that can happen to it, and a `StockError` is one reason an order can be refused, carrying the details that explain it: ```rux variant StockError { UnknownItem(char8[..]), BadAmount(int32), NotEnough { name: char8[..]; have: int32; wanted: int32; }, StillInStock { name: char8[..]; count: int32; } } ``` The functions are layered. `Main` hands each order to `Apply`, which dispatches to one function per kind of order; all of them look items up through `Find`: ```mermaid flowchart LR main(["`Main`<br/>for each order"]) --> apply["`Apply`<br/>`match order`"] apply --> sell["`Sell`"] apply --> deliver["`Deliver`"] apply --> retire["`Retire`"] sell --> find["`Find`<br/>`uint?`"] deliver --> find retire --> find deliver -- "new item" --> push["`Vector.Push`<br/>may fail: `CollectionError`"] ``` | Piece | Lessons it uses | | ------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `StockItem`, `Order`, `StockError` | [Struct](https://rux-lang.dev/docs/learn/struct), [Variant](https://rux-lang.dev/docs/learn/variant), [Error variant](https://rux-lang.dev/docs/learn/error-variant) | | The stock as `Vector<StockItem>` | [Vector](https://rux-lang.dev/docs/learn/vector), [Mutable reference](https://rux-lang.dev/docs/learn/mutable-reference) | | `Find` returning `uint?` | [Optional](https://rux-lang.dev/docs/learn/optional), [Presence](https://rux-lang.dev/docs/learn/presence) | | `?? fail` in `Sell` and `Retire` | [Absence to error](https://rux-lang.dev/docs/learn/absence-to-error) | | `Apply` failing with two error types | [Error sum](https://rux-lang.dev/docs/learn/error-sum), [Propagate](https://rux-lang.dev/docs/learn/propagate) | | Taking orders and errors apart | [Struct pattern](https://rux-lang.dev/docs/learn/struct-pattern), [Typed pattern](https://rux-lang.dev/docs/learn/typed-pattern) | ## Finding an item, or not `Find` answers with the item's position in the vector, or `none`. Names are compared with `EqualsSlice`, because `==` on two slices is refused — it would ask whether they are the same view, not whether they hold the same text: ```rux func Find(stock: &Vector<StockItem>, name: char8[..]) -> uint? { let items = stock.AsSlice(); for i in 0..items.length { if EqualsSlice(items[i].name, name) { return i; } } return none; } ``` In `Sell`, an absent position is a refusal. `?? fail` turns the `none` into a failure on the spot, so the line after it can use `index` as a plain `uint`: ```rux let index = Find(stock, name) ?? fail StockError::UnknownItem(name); ``` ## Check everything, then change `Sell` makes every check before it touches the stock. Only when all of them pass does the count change, which is what makes a refused order harmless: ```rux func Sell(stock: &var Vector<StockItem>, name: char8[..], amount: int32) -> ! StockError { if amount <= 0 { fail StockError::BadAmount(amount); } // An absent position becomes a failure on the spot. let index = Find(stock, name) ?? fail StockError::UnknownItem(name); var items = stock.AsMutableSlice(); if items[index].count < amount { fail StockError::NotEnough { name: name, have: items[index].count, wanted: amount }; } items[index].count -= amount; } ``` `AsMutableSlice` gives a writable view of the vector's elements, so `items[index].count -= amount` changes the stock in place. `Sell` returns `! StockError` with no success value: reaching the end of the body is the success. ## Two kinds of failure, kept apart A delivery of something new adds an item, and adding to a vector can run out of memory. That is a `CollectionError` — a different kind of failure altogether, and nobody's fault. So `Deliver` and `Apply` fail with the **sum** of the two error types, and every `?` passes either kind through unchanged: ```rux func Apply(stock: &var Vector<StockItem>, order: Order) -> ! (StockError | CollectionError) { ``` `Main` opens the outcome with typed patterns. A `StockError` is explained and counted; a `CollectionError` ends the day, because no order can be blamed for it: ```rux match Apply(stock, order) { .Success(()) => PrintLine(" done"), .Failure(error: StockError) => { Explain(error); refused += 1; }, // Running out of memory is no fault of the order, so it ends the day. .Failure(error: CollectionError) => fail error } ``` `Main` itself is declared `-> ! CollectionError`, so `fail error` ends the program with exit status 1. ## Retiring a sold-out item `Retire` refuses to drop an item that is still on the shelf. Once it has sold out, `RemoveAt` takes it out of the vector. In the run above, retiring milk is refused with 6 still in stock, candles (at 0) are removed, and later honey — delivered as a new item — appears at the end of the closing list. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Projects/Inventory){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // Inventory: the stock list of a small shop, kept as structs in a `Vector`, and a day of orders // applied to it, some of which cannot be carried out. // // Every change to the stock is a fallible function, and each way it can be refused is a case of // `StockError` carrying the details: which item is unknown, how many were wanted and how many // were there. A refused order changes nothing, so the stock is never left half-updated. // // A delivery of something new adds an item to the vector, and adding can run out of memory. That // is a `CollectionError`, a different kind of failure altogether, so `Apply` fails with the sum // `StockError | CollectionError` and both kinds pass through its `?` unchanged. import Allocator::{ Allocator, SystemAllocator }; import Collections::{ CollectionError, EqualsSlice, Vector }; import Io::PrintLine; struct StockItem { name: char8[..]; count: int32; } variant StockError { UnknownItem(char8[..]), BadAmount(int32), NotEnough { name: char8[..]; have: int32; wanted: int32; }, StillInStock { name: char8[..]; count: int32; } } variant Order { Sell { name: char8[..]; amount: int32; }, Deliver { name: char8[..]; amount: int32; }, Retire(char8[..]) } // Where the item sits in the vector, or `none` if the shop has never stocked it. Names are // compared with `EqualsSlice`: `==` on two slices is refused, because it would ask whether they // are the same view rather than whether they hold the same text. func Find(stock: &Vector<StockItem>, name: char8[..]) -> uint? { let items = stock.AsSlice(); for i in 0..items.length { if EqualsSlice(items[i].name, name) { return i; } } return none; } func Sell(stock: &var Vector<StockItem>, name: char8[..], amount: int32) -> ! StockError { if amount <= 0 { fail StockError::BadAmount(amount); } // An absent position becomes a failure on the spot. let index = Find(stock, name) ?? fail StockError::UnknownItem(name); var items = stock.AsMutableSlice(); if items[index].count < amount { fail StockError::NotEnough { name: name, have: items[index].count, wanted: amount }; } items[index].count -= amount; } func Deliver(stock: &var Vector<StockItem>, name: char8[..], amount: int32) -> ! (StockError | CollectionError) { if amount <= 0 { fail StockError::BadAmount(amount); } match Find(stock, name) { index? => { var items = stock.AsMutableSlice(); items[index].count += amount; }, none => stock.Push(StockItem { name: name, count: amount })? } } // An item leaves the list only once it has sold out. func Retire(stock: &var Vector<StockItem>, name: char8[..]) -> ! StockError { let index = Find(stock, name) ?? fail StockError::UnknownItem(name); let count = stock.AsSlice()[index].count; if count > 0 { fail StockError::StillInStock { name: name, count: count }; } // `RemoveAt` hands back the item it took out, as an optional; it is not needed here. stock.RemoveAt(index); } func Apply(stock: &var Vector<StockItem>, order: Order) -> ! (StockError | CollectionError) { match order { .Sell { name, amount } => { PrintLine("sell {} {}", amount, name); Sell(stock, name, amount)?; }, .Deliver { name, amount } => { PrintLine("deliver {} {}", amount, name); Deliver(stock, name, amount)?; }, .Retire(name) => { PrintLine("retire {}", name); Retire(stock, name)?; } } } func Explain(error: StockError) { match error { .UnknownItem(name) => PrintLine(" refused: no such item as {}", name), .BadAmount(amount) => PrintLine(" refused: {} is not an amount", amount), .NotEnough { name, have, wanted } => PrintLine(" refused: wanted {} {}, only {} left", wanted, name, have), .StillInStock { name, count } => PrintLine(" refused: {} {} still on the shelf", count, name) } } func PrintStock(stock: &Vector<StockItem>) { for item in stock { PrintLine(" {:10} {:3}", item.name, item.count); } } func Main() -> ! CollectionError { var system = SystemAllocator(); let allocator: Allocator = system; var stock = Vector<StockItem>(allocator); stock.Push(StockItem { name: "apples", count: 12 })?; stock.Push(StockItem { name: "bread", count: 3 })?; stock.Push(StockItem { name: "candles", count: 0 })?; stock.Push(StockItem { name: "milk", count: 6 })?; PrintLine("opening stock"); PrintStock(stock); let orders = [ Order::Sell { name: "apples", amount: 5 }, Order::Sell { name: "bread", amount: 4 }, Order::Sell { name: "honey", amount: 1 }, Order::Deliver { name: "bread", amount: 10 }, Order::Sell { name: "bread", amount: 4 }, Order::Deliver { name: "honey", amount: 2 }, Order::Sell { name: "milk", amount: -2 }, Order::Retire("milk"), Order::Retire("candles"), Order::Sell { name: "milk", amount: 6 } ]; var refused = 0; for order in orders { match Apply(stock, order) { .Success(()) => PrintLine(" done"), .Failure(error: StockError) => { Explain(error); refused += 1; }, // Running out of memory is no fault of the order, so it ends the day. .Failure(error: CollectionError) => fail error } } PrintLine("closing stock, after {} refused orders", refused); PrintStock(stock); } ``` Besides `Io`, its `Rux.toml` lists `Allocator` and `Collections` under `[Dependencies]`. ## Run it ```sh cd Examples/Projects/Inventory rux run ``` ```text opening stock apples 12 bread 3 candles 0 milk 6 sell 5 apples done sell 4 bread refused: wanted 4 bread, only 3 left sell 1 honey refused: no such item as honey deliver 10 bread done sell 4 bread done deliver 2 honey done sell -2 milk refused: -2 is not an amount retire milk refused: 6 milk still on the shelf retire candles done sell 6 milk done closing stock, after 4 refused orders apples 7 bread 9 milk 0 honey 2 ``` ## Common mistakes ::mistake **Comparing names with `==`.**:br`items[i].name == name` is refused: ```text error: operator '==' is not defined for slice type 'char8[..]' ``` A note adds that comparing the views would compare addresses rather than elements. Use `EqualsSlice` from Collections. :: ::mistake **Letting a `CollectionError` into a function that fails with `StockError` only.**:br Declare `Deliver` as `-> ! StockError` and its `stock.Push(…)?` stops compiling: ```text error: '?' propagates error type 'CollectionError', but the enclosing function fails with 'StockError' ``` `?` never converts one error into another; the function has to admit both. :: ::mistake **Handling only the errors you expected.**:br Remove the `.Failure(error: CollectionError)` arm from `Main` and the match is incomplete: ```text error: match on '! (CollectionError | StockError)' is not exhaustive; missing .Failure(_: CollectionError) ``` Every member of the sum needs an answer, even if the answer is "give up". :: ## Try it yourself 1. Add an order `Return { name; amount; }` for goods a customer brings back. It should behave like a delivery, but refuse an item the shop has never stocked. 2. Give each item a price in cents and print the value of the closing stock. Which functions have to change, and which do not? 3. Add a `LowStock` warning: after each successful sale, print a note if fewer than three are left. Is that a new case of `StockError`, or something else? 4. Apply all of a customer's orders together or none of them: take a small array of orders, check them all first, and only then change the stock. ## Learn more - [Vector](https://rux-lang.dev/docs/learn/vector) — `Push`, `AsSlice` and `AsMutableSlice` - [Absence to error](https://rux-lang.dev/docs/learn/absence-to-error) and [Error sum](https://rux-lang.dev/docs/learn/error-sum) - [Typed pattern](https://rux-lang.dev/docs/learn/typed-pattern) — matching a sum by the type it holds - Next project: [Statistics](https://rux-lang.dev/docs/learn/statistics), the checkpoint for Algorithms # Statistics ::note **You'll need**: Parts 1–18 — this project is the checkpoint for Algorithms, and leans on [Writable slice](https://rux-lang.dev/docs/learn/writable-slice), [Sort](https://rux-lang.dev/docs/learn/sort), [Min and max](https://rux-lang.dev/docs/learn/min-max), [Fold](https://rux-lang.dev/docs/learn/fold) and [Math](https://rux-lang.dev/docs/learn/math). :: Given a handful of numbers, where is the middle, and how spread out are they around it? This program summarises a slice of measurements: how many there are, the smallest and largest, the mean, two kinds of variance and the median. Then it does the same for awkward inputs — repeated values, a single value and no values at all — because a summary that only works on nice data is not finished. It is the checkpoint for [Part 18: Algorithms](https://rux-lang.dev/docs/learn/algorithms), and most of the work is done by that part's functions: `MinIndex`, `MaxIndex`, `Sum` and `Sort`. ## How it is put together One function, `Summarize`, does all the work, and `Main` calls it four times with different data. Inside, the order of the steps matters: ```mermaid flowchart LR s(["`Summarize`"]) --> ext["count, smallest, largest<br/>(fine for zero values)"] ext --> empty{"`count == 0?`"} empty -- "yes" --> stop(["stop: nothing to divide"]) empty -- "no" --> mean["mean<br/>first pass"] mean --> var["variance<br/>second pass"] var --> sort["`Sort`, then median<br/>(changes the slice)"] ``` | Statistic | How it is found | Lessons it uses | | ------------------- | --------------------------------------- | -------------------------------------------------------------------------------------------------------------- | | Smallest, largest | `MinIndex`, `MaxIndex` → `uint?` | [Min and max](https://rux-lang.dev/docs/learn/min-max), [Presence](https://rux-lang.dev/docs/learn/presence) | | Mean | `Sum(values, 0.0) / n` | [Fold](https://rux-lang.dev/docs/learn/fold), [Convert](https://rux-lang.dev/docs/learn/convert) | | Variance, deviation | A loop of squared distances, `Sqrt` | [For](https://rux-lang.dev/docs/learn/for), [Math](https://rux-lang.dev/docs/learn/math) | | Median | `Sort`, then the middle element(s) | [Sort](https://rux-lang.dev/docs/learn/sort), [Writable slice](https://rux-lang.dev/docs/learn/writable-slice) | | Four data sets | Views of arrays, including an empty one | [Slice](https://rux-lang.dev/docs/learn/slice), [Array](https://rux-lang.dev/docs/learn/array) | ## Extremes that cope with nothing `MinIndex` and `MaxIndex` do not return a value — they return the **position** of one, as an optional. An empty slice has no smallest element, and `none` says so without any special case: ```rux match MinIndex(values) { at? => PrintLine(" smallest {}", values[at]), none => PrintLine(" smallest none") } ``` Everything after this point divides by the count, so the function stops early when there is nothing to divide: ```rux if count == 0 { PrintLine(" mean, variance and median need at least one value"); PrintLine(); return; } ``` ## Mean and variance: two passes The **variance** is the average squared distance from the mean, so the mean has to be known before any distance can be measured — hence two passes over the data. The distances are squared so that values above and below the mean both count, instead of cancelling each other out: ```rux let n = count as float64; let mean = Sum(values, 0.0) / n; var squares = 0.0; for value in values { let distance = value - mean; squares += distance * distance; } ``` `Sum` is the fold of `+` from the [Fold](https://rux-lang.dev/docs/learn/fold) lesson, already written. Its second argument is the starting value, `0.0`, which also fixes the result's type as `float64`. ## Population or sample? There are two conventions for "average squared distance", and a summary should say which it uses: | Name | Divide by | Use it when | | ------------------- | --------- | ---------------------------------------- | | Population variance | n | the data is everything there is | | Sample variance | n − 1 | the data is a sample of something larger | Dividing by n − 1 corrects for the sample's mean having been computed from the sample itself. With one value there is nothing to correct with — n − 1 is zero — so the program reports the sample variance as undefined rather than printing a number. The **standard deviation** is the square root of either variance, which brings the answer back into the units of the data. ## The median sorts the data The median is the middle value once the data is in order, or the average of the two middle values when the count is even: ```rux Sort(values); let middle = count / 2; if count % 2 == 1 { PrintLine(" median {} (the middle value)", values[middle]); } else { let low = values[middle - 1]; let high = values[middle]; PrintLine(" median {} (between {} and {})", (low + high) / 2.0, low, high); } ``` `Sort` works in place, so `Summarize` takes a **writable** slice, `var float64[..]`, and the caller's array is left sorted afterwards. That is why the median comes last: the `values` line at the top of each summary still shows the data in its original order. ## Four kinds of input `Main` keeps each data set in a `var` array and passes a view of it. The last call passes `readings[..0]`, an empty view of an array that already exists — the simplest way to make "no values" without a new type: ```rux var single: float64[1] = [42.0]; Summarize("a single value", single[..]); // An empty view of an array, so there is nothing to summarise. Summarize("no values", readings[..0]); ``` ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Projects/Statistics){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // Summarising a set of numbers: where the middle is, and how spread out the numbers are around it. // // The mean is the total divided by the count. The variance is the average squared distance from // the mean, and the standard deviation is its square root, which brings the answer back to the // units of the data. There are two conventions for that average, and a summary should say which // one it uses: // // population variance divide by n the data is everything there is // sample variance divide by n - 1 the data is a sample of something larger // // Dividing by n - 1 corrects for the sample's mean being computed from the sample itself. With one // value there is nothing to correct with, so the sample variance is undefined rather than zero. // // The median is the middle value once the data is sorted, or the average of the two middle values // when the count is even. `Sort` works in place, so `Summarize` takes a writable slice and leaves // the caller's data in order. import Algorithms::{ MaxIndex, MinIndex, Sort, Sum }; import Io::{ Print, PrintLine }; import Math::Sqrt; func Summarize(label: char8[..], values: var float64[..]) { PrintLine("{}", label); Print(" values "); for value in values { Print(" {}", value); } PrintLine(); let count = values.length; PrintLine(" count {}", count); // The extremes answer with an optional index, so an empty slice is handled right here. match MinIndex(values) { at? => PrintLine(" smallest {}", values[at]), none => PrintLine(" smallest none") } match MaxIndex(values) { at? => PrintLine(" largest {}", values[at]), none => PrintLine(" largest none") } // Everything else divides by the count, and there is no mean of nothing. if count == 0 { PrintLine(" mean, variance and median need at least one value"); PrintLine(); return; } // Two passes: the mean has to be known before the distances from it can be measured. The // distances are squared so that values above and below both count, instead of cancelling. // `Sum` is the fold of `+` from the Fold lesson, already written. let n = count as float64; let mean = Sum(values, 0.0) / n; var squares = 0.0; for value in values { let distance = value - mean; squares += distance * distance; } PrintLine(" mean {:.4}", mean); let population = squares / n; PrintLine(" population variance {:.4}, deviation {:.4}", population, Sqrt(population)); if count > 1 { let sample = squares / (n - 1.0); PrintLine(" sample variance {:.4}, deviation {:.4}", sample, Sqrt(sample)); } else { PrintLine(" sample variance undefined for one value"); } // The median needs the values in order, so it comes last. Sort(values); let middle = count / 2; if count % 2 == 1 { PrintLine(" median {} (the middle value)", values[middle]); } else { let low = values[middle - 1]; let high = values[middle]; PrintLine(" median {} (between {} and {})", (low + high) / 2.0, low, high); } PrintLine(); } func Main() -> int { // An odd count: one value sits exactly in the middle. var readings: float64[9] = [12.5, 9.0, 15.25, 11.0, 8.75, 14.0, 10.5, 13.25, 11.75]; Summarize("nine readings", readings[..]); // An even count with repeated values. Duplicates are ordinary data: each one counts. var scores: float64[6] = [4.0, 7.0, 4.0, 1.0, 7.0, 7.0]; Summarize("six scores with repeats", scores[..]); // One value: no spread at all, and no sample variance. var single: float64[1] = [42.0]; Summarize("a single value", single[..]); // An empty view of an array, so there is nothing to summarise. Summarize("no values", readings[..0]); return 0; } ``` Besides `Io`, its `Rux.toml` lists `Algorithms` and `Math` under `[Dependencies]`. ## Run it ```sh cd Examples/Projects/Statistics rux run ``` ```text nine readings values 12.5 9.0 15.25 11.0 8.75 14.0 10.5 13.25 11.75 count 9 smallest 8.75 largest 15.25 mean 11.7778 population variance 4.3117, deviation 2.0765 sample variance 4.8507, deviation 2.2024 median 11.75 (the middle value) six scores with repeats values 4.0 7.0 4.0 1.0 7.0 7.0 count 6 smallest 1.0 largest 7.0 mean 5.0000 population variance 5.0000, deviation 2.2361 sample variance 6.0000, deviation 2.4495 median 5.5 (between 4.0 and 7.0) a single value values 42.0 count 1 smallest 42.0 largest 42.0 mean 42.0000 population variance 0.0000, deviation 0.0000 sample variance undefined for one value median 42.0 (the middle value) no values values count 0 smallest none largest none mean, variance and median need at least one value ``` ## Common mistakes ::mistake **Passing data that cannot be sorted.**:br`Summarize` sorts, so its parameter is `var float64[..]`. An array declared with `let` gives only a read-only view, and the call fails: ```text error: argument 2 to 'Summarize' has type 'float64[..]', but parameter 'values' requires 'var float64[..]' ``` Dropping the `var` from the parameter just moves the problem to `Sort`, which needs a `var T[..]` too. :: ::mistake **Taking the median before sorting.**:br Without `Sort(values);` the program still runs, but the "median" is whatever sits in the middle of the unsorted data: 8.75 for the nine readings instead of 11.75. :: ::mistake **Forgetting the empty case.**:br Remove the `count == 0` check and the empty summary prints a mean of `NaN` — zero divided by zero — and then stops with: ```text Panic: index out of range ``` `middle - 1` on a count of 0 is not −1 but a huge unsigned number. :: ## Try it yourself 1. Add the **range** (largest minus smallest) to the summary. Where must it go so that it still works for an empty slice? 2. Add the **mode**, the most frequent value. Because the slice is sorted by then, equal values sit side by side, so one pass that counts runs is enough. 3. Print the values again after the median, to see that the caller's array really has been sorted. 4. Summarise a copy instead: make `Summarize` take a read-only `float64[..]` and sort a copy of the data in a local array, so the caller's data keeps its order. What limits the size of that local array? ## Learn more - [Min and max](https://rux-lang.dev/docs/learn/min-max), [Fold](https://rux-lang.dev/docs/learn/fold) and [Sort](https://rux-lang.dev/docs/learn/sort) - [Writable slice](https://rux-lang.dev/docs/learn/writable-slice) — why sorting needs `var T[..]` - [Sqrt](https://rux-lang.dev/docs/api/math/powers#sqrt) in the API reference - Next projects: [Guess](https://rux-lang.dev/docs/learn/guess), [Age](https://rux-lang.dev/docs/learn/age), [Password](https://rux-lang.dev/docs/learn/password) and [Launch](https://rux-lang.dev/docs/learn/launch), the checkpoints for Utilities # Guess ::note **You'll need**: Parts 1–20 — this project is a checkpoint for Utilities, and leans on [Entropy](https://rux-lang.dev/docs/learn/entropy), [Input](https://rux-lang.dev/docs/learn/input) and [Parse](https://rux-lang.dev/docs/learn/parse). :: The program thinks of a number from 1 to 100, and you have seven guesses to find it. After each wrong guess it says "higher" or "lower". It is the first project in the course that you **play** rather than just run. Seven guesses are exactly enough if you play well: halve what is left every time, and seven halvings take a hundred candidates down to one. That is also why the program is strict about what counts as a guess — text that is not a number, or a number outside 1 to 100, is answered and asked again without using a guess up. It is a checkpoint for [Part 20: Utilities](https://rux-lang.dev/docs/learn/utilities), which supplies the random number; the input handling comes from [Part 14: Text](https://rux-lang.dev/docs/learn/text). ## How it is put together All of it lives in `Main`: pick a secret, then loop until the guesses run out. Every line the player types takes one of these paths: ```mermaid flowchart LR read["`ReadLine`"] -- "end of input" --> leave(["reveal the number<br/>and stop"]) read -- "read error" --> fail(["stop, status 1"]) read -- "a line" --> parse{"a number?"} parse -- "no" --> again["try again,<br/>no guess used"] parse -- "yes" --> range{"1 to 100?"} range -- "no" --> again range -- "yes" --> used["count the guess"] used --> hit{"the secret?"} hit -- "yes" --> win(["found it"]) hit -- "no" --> hint["higher or lower"] ``` | Piece | Lessons it uses | | -------------------------------- | ---------------------------------------------------------------------------------------------------------------------- | | A generator seeded from entropy | [Entropy](https://rux-lang.dev/docs/learn/entropy), [Random](https://rux-lang.dev/docs/learn/random) | | A secret from 1 to 100 | [Distribution](https://rux-lang.dev/docs/learn/distribution) (`UniformInRange`) | | Reading a line, the end of input | [Input](https://rux-lang.dev/docs/learn/input), [Guard](https://rux-lang.dev/docs/learn/guard) | | Turning the line into a number | [Parse](https://rux-lang.dev/docs/learn/parse), [String view](https://rux-lang.dev/docs/learn/string-view) | | Skipping a bad guess | [Catch fallback](https://rux-lang.dev/docs/learn/catch-fallback), [Continue](https://rux-lang.dev/docs/learn/continue) | | The hint | [Ternary](https://rux-lang.dev/docs/learn/ternary) | ## A different number every game A seeded generator such as `Pcg64Dxsm` gives the same numbers for the same seed — useful for tests, useless for a game. So the generator is seeded from the operating system's entropy instead. Asking for entropy can fail, and then there is no fair number to pick, so the program says so and stops: ```rux var generator = PcgFromEntropy() catch { else => { PrintLine("There is no entropy to pick a number with, so there is no game."); return 1; } }; let secret = UniformInRange<Pcg64Dxsm>(generator, 1, 100) as int32; ``` `UniformInRange` returns a `uint64` from 1 to 100 inclusive, every value equally likely. The guesses will be parsed as `int32`, so the secret is converted once here, and every comparison after it is between two `int32`s. ## Four ways the game can end Each pass of the loop prints a prompt, clears the builder and reads a line. The match on the read is where two of the endings live: ```rux match ReadLine(builder) { .Success(_) => {}, .Failure(error) if error.kind == IoErrorKind::EndOfStream => { PrintLine(); PrintLine("Leaving already? It was {}.", secret); return 0; }, .Failure(_) => { PrintLine("The input could not be read."); return 1; } } ``` Ending the input is a polite way to give up, so it reveals the number and exits with status 0. A read error is a real fault, so it exits with status 1. The other two endings — found it, and out of guesses — are ordinary `return 0`s further down. ## A guess that does not count The guess is parsed from the trimmed line. If parsing fails, the `catch` arm prints a message and uses `continue` to start the next pass of the loop — the `catch` is inside the loop, so it can leave the pass, not just the expression: ```rux let guess = ParseInt32(builder.View().Trim()) catch { else => { PrintLine("That is not a number. It does not count; try again."); continue; } }; if guess < 1 || guess > 100 { PrintLine("That is outside 1 to 100. It does not count; try again."); continue; } used += 1; ``` `used` only grows after both checks, so the prompt keeps saying `guess 1:` until a real guess arrives. ## The hint The last line of the loop picks between two words with the conditional operator: ```rux PrintLine("{}", guess < secret ? "higher" : "lower"); ``` ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Projects/Guess){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // A guessing game: the program picks a number from 1 to 100, and you have seven guesses to find // it, with a "higher" or "lower" after each one. // // Seven is enough if you halve what is left every time, because seven halvings take a hundred // candidates down to one. So a guess only counts when it is a real one: text that is not a // number, or a number outside 1 to 100, is answered and asked again without using a guess up. // // The game ends in one of four ways, and each is handled on purpose: the number is found, the // guesses run out, the input ends (Ctrl+Z and Enter on Windows, Ctrl+D elsewhere, or the end of // piped input), or the input cannot be read at all. // // The number comes from a generator seeded from the system's entropy, so every game is // different. Asking for entropy can fail, and then there is no fair number to pick, so the // program says so and stops. import Allocator::{ Allocator, SystemAllocator }; import Format::ParseInt32; import Io::{ IoErrorKind, Print, PrintLine, ReadLine }; import Random::{ Pcg64Dxsm, PcgFromEntropy, UniformInRange }; import Text::StringBuilder; const Guesses = 7; func Main() -> int { var generator = PcgFromEntropy() catch { else => { PrintLine("There is no entropy to pick a number with, so there is no game."); return 1; } }; let secret = UniformInRange<Pcg64Dxsm>(generator, 1, 100) as int32; PrintLine("I am thinking of a number from 1 to 100. You have {} guesses.", Guesses); var system = SystemAllocator(); let allocator: Allocator = system; var builder = StringBuilder(allocator); var used = 0; while used < Guesses { Print("guess {}: ", used + 1); builder.Clear(); match ReadLine(builder) { .Success(_) => {}, .Failure(error) if error.kind == IoErrorKind::EndOfStream => { PrintLine(); PrintLine("Leaving already? It was {}.", secret); return 0; }, .Failure(_) => { PrintLine("The input could not be read."); return 1; } } // Spaces around the number are forgiven; anything else that is not a number is not. let guess = ParseInt32(builder.View().Trim()) catch { else => { PrintLine("That is not a number. It does not count; try again."); continue; } }; if guess < 1 || guess > 100 { PrintLine("That is outside 1 to 100. It does not count; try again."); continue; } used += 1; if guess == secret { PrintLine("Yes, {}! Found in {} of {} guesses.", secret, used, Guesses); return 0; } PrintLine("{}", guess < secret ? "higher" : "lower"); } PrintLine("Out of guesses. It was {}.", secret); return 0; } ``` Besides `Io`, its `Rux.toml` lists `Allocator`, `Format`, `Random` and `Text` under `[Dependencies]`. ## Run it ```sh cd Examples/Projects/Guess rux run ``` ```text I am thinking of a number from 1 to 100. You have 7 guesses. guess 1: fifty That is not a number. It does not count; try again. guess 1: 50 higher guess 2: 75 higher guess 3: 88 lower guess 4: 81 higher guess 5: 84 Yes, 84! Found in 5 of 7 guesses. ``` Ending the input (Ctrl+Z and Enter on Windows, Ctrl+D elsewhere) leaves the game and reveals the number. Piped input works too, though the guesses cannot react to the hints: ```sh 1..7 | rux run ``` ```text I am thinking of a number from 1 to 100. You have 7 guesses. guess 1: higher guess 2: higher guess 3: higher guess 4: higher guess 5: higher guess 6: higher guess 7: higher Out of guesses. It was 78. ``` The game waits for you. Run it and type a guess after each prompt, pressing Enter each time. To leave early, end the input — Ctrl+Z and Enter on Windows, Ctrl+D elsewhere — and the program tells you the number. The piped example above is written for PowerShell (`1..7` is the numbers 1 to 7); in a POSIX shell, `seq 1 7 | rux run` does the same. Because the secret is different on every run, your output will differ from the sample. ## Common mistakes ::mistake **Comparing the guess with an unconverted secret.**:br`UniformInRange` returns a `uint64`. Leave out the `as int32` and every comparison with the `int32` guess is refused: ```text error: operator '==' cannot compare left operand 'int32' with right operand 'uint64' ``` The same goes for `<`. Convert once, where the value is made. :: ::mistake **Counting a guess before checking it.**:br If `used += 1;` moves above the range check, typing `500` wastes a guess. The program still works — it is just unfair, which in a game is a bug. :: ::mistake **Treating the end of input as an error.**:br Without the guarded `EndOfStream` arm, a player who presses Ctrl+Z (or Ctrl+D) to quit gets "The input could not be read" and exit status 1. The end of the input is expected, so it has its own arm, and it comes before the general `.Failure(_)`. :: ## Try it yourself 1. Let the player choose the upper limit — 10, 100 or 1000 — and work out the number of guesses from it: the smallest `n` with 2ⁿ at least the limit. 2. Keep a list of the guesses so far and refuse a repeated one without counting it. 3. After the game, ask "Play again? (y/n)" and start a new round on `y`, with a new secret. 4. Swap the roles: you think of a number and the program guesses it by halving the range, reading "higher", "lower" or "yes" after each try. ## Learn more - [Entropy](https://rux-lang.dev/docs/learn/entropy) and [Distribution](https://rux-lang.dev/docs/learn/distribution) — where the secret comes from - [Input](https://rux-lang.dev/docs/learn/input) and [Parse](https://rux-lang.dev/docs/learn/parse) — reading and checking a line - [Continue](https://rux-lang.dev/docs/learn/continue) — skipping the rest of a pass - Next project: [Age](https://rux-lang.dev/docs/learn/age) # Age ::note **You'll need**: Parts 1–20 — this project is a checkpoint for Utilities, and leans on [Date](https://rux-lang.dev/docs/learn/date), [Fail](https://rux-lang.dev/docs/learn/fail) and [Absence to error](https://rux-lang.dev/docs/learn/absence-to-error). :: How old is someone, in completed years, months and days? It sounds like a subtraction and is not, because months have different lengths. What is one month after 31 January? When does someone born on 29 February have a birthday in a year without one? This program answers with the rule people actually use, and runs it on eleven pairs of dates chosen to hit every awkward case. It is a checkpoint for [Part 20: Utilities](https://rux-lang.dev/docs/learn/utilities): the Time package does the calendar arithmetic, and the program's job is to ask it the right questions. ## How it is put together | Piece | Its job | Lessons it uses | | ---------- | ---------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- | | `Age` | Years, months and days, as a struct | [Struct](https://rux-lang.dev/docs/learn/struct) | | `AgeError` | `BornLater` or `OutOfRange` — no details needed, so a plain enum | [Enum](https://rux-lang.dev/docs/learn/enum), [Fail](https://rux-lang.dev/docs/learn/fail) | | `AgeOn` | The calculation | [Date](https://rux-lang.dev/docs/learn/date), [Absence to error](https://rux-lang.dev/docs/learn/absence-to-error) | | `Show` | Parses two texts, calls `AgeOn`, prints one row | [Date](https://rux-lang.dev/docs/learn/date), [Catch](https://rux-lang.dev/docs/learn/catch), [Format](https://rux-lang.dev/docs/learn/format) | | `Main` | Eleven rows of test cases | [Function](https://rux-lang.dev/docs/learn/function) | The dates are all written out in the source, so the output is the same on every run. A real program would ask the clock for today — one of the exercises below. ## The rule Count whole years, then whole months, then the days left over. A month is complete when its day comes round again — and when that day does not exist, the month is complete on its **last** day instead: | Born | One month later | Why | | ----------- | --------------- | ------------------------------------- | | 15 March | 15 April | The day exists | | 31 January | 28 February | February has no 31st, so its last day | | 29 February | 28 February | In a year that is not a leap year | `PlusMonths` from the Time package follows exactly that rule — it clamps to the end of the month — so the program never counts the days in a month by hand. ## Counting months, then correcting by one `AgeOn` first refuses a birth after the date asked about. Then it counts the calendar months between the two dates: ```rux var months = ((on.year - birth.year) as int64) * 12 + (on.month as int64) - (birth.month as int64); var reached = birth.PlusMonths(months) ?? fail AgeError::OutOfRange; if on.DaysSince(reached) < 0 { months -= 1; reached = birth.PlusMonths(months) ?? fail AgeError::OutOfRange; } ``` That count is either right or one too many — too many when the day of the month has not come round yet. Born on 15 March 1990 and asked about 4 October 2026, the count says 439 months, but 15 October 2026 is still in the future, so it drops to 438 — 36 years and 6 months. `reached` is then the last date, on or before `on`, that is a whole number of months after the birth. `PlusMonths` returns `Date?`: a date far enough out leaves the range the calendar supports. `?? fail` turns that absence into the `OutOfRange` error on the spot. The answer is then a division and a remainder, and the days left over are a plain `DaysSince`: ```rux return Age { years: months / 12, months: months % 12, days: on.DaysSince(reached) }; ``` ## Step from the birth, not from last month Notice that both calls are `birth.PlusMonths(months)` — always counted from the birth date. Stepping one month at a time would let the clamping drift: | From 31 January 2026 | Result | | --------------------------- | ----------- | | `PlusMonths(1)` | 28 February | | …then `PlusMonths(1)` again | 28 March | | `PlusMonths(2)` directly | 31 March | Once a step has clamped to the 28th, every later step keeps the 28th. Counting from the birth each time keeps the original day of the month. ## Parsing, and dates that do not exist `Show` parses both texts with `ParseDate`, which returns `Date ! TimeParseError`. A text that is not a real date — such as 29 February 2023 — fails, and the `catch` prints a row saying so and leaves `Show` early: ```rux let birth = ParseDate(birthText) catch { else => { PrintLine("{} {} {} is not a date", birthText, onText, birthText); return; } }; ``` The outcome of `AgeOn` is matched with nested patterns, one arm per case of the enum: ```rux match AgeOn(birth, on) { .Success(age) => PrintLine("{} {} {:5} {:7} {:5}", birth, on, age.years, age.months, age.days), .Failure(AgeError::BornLater) => PrintLine("{} {} refused, born after that date", birth, on), .Failure(AgeError::OutOfRange) => PrintLine("{} {} outside the calendar", birth, on) } ``` `{:5}` and `{:7}` pad the numbers to the widths of the header's columns. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Projects/Age){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // Working out how old someone is, in completed years, months and days. It sounds like // subtraction and is not, because months have different lengths. // // The rule is the one people use: count whole years, then whole months, then the days left over. // A month is complete when its day comes round again. When that day does not exist, the month // is complete on its last day instead: one month after 31 January is 28 February, and someone // born on 29 February has their birthday on 28 February in a year that is not a leap year. // // `PlusMonths` from the Time package follows exactly that rule, clamping to the end of the // month, so the program never counts days in a month by hand. It finds the last date, on or // before the second one, that is a whole number of months after the birth, and the days left // over are a plain `DaysSince`. // // Every date is written out, so the output is the same on every run. A real program would ask // the clock for today. import Io::PrintLine; import Time::{ Date, ParseDate }; struct Age { years: int64; months: int64; days: int64; } enum AgeError { BornLater, OutOfRange } // The age on `on` of someone born on `birth`, or why there is none. func AgeOn(birth: Date, on: Date) -> Age ! AgeError { if on.DaysSince(birth) < 0 { fail AgeError::BornLater; } // Counting the calendar months between the two gives the right answer, or one too many // when the day of the month has not come round yet. Stepping from `birth` rather than // from the previous month keeps the clamping from drifting: 31 January plus two months // is 31 March, not 28 March. var months = ((on.year - birth.year) as int64) * 12 + (on.month as int64) - (birth.month as int64); var reached = birth.PlusMonths(months) ?? fail AgeError::OutOfRange; if on.DaysSince(reached) < 0 { months -= 1; reached = birth.PlusMonths(months) ?? fail AgeError::OutOfRange; } return Age { years: months / 12, months: months % 12, days: on.DaysSince(reached) }; } func Show(birthText: char8[..], onText: char8[..]) { let birth = ParseDate(birthText) catch { else => { PrintLine("{} {} {} is not a date", birthText, onText, birthText); return; } }; let on = ParseDate(onText) catch { else => { PrintLine("{} {} {} is not a date", birthText, onText, onText); return; } }; match AgeOn(birth, on) { .Success(age) => PrintLine("{} {} {:5} {:7} {:5}", birth, on, age.years, age.months, age.days), .Failure(AgeError::BornLater) => PrintLine("{} {} refused, born after that date", birth, on), .Failure(AgeError::OutOfRange) => PrintLine("{} {} outside the calendar", birth, on) } } func Main() -> int { PrintLine("born on years months days"); // A birthday already past this year, one still to come, and the day itself. Show("1990-03-15", "2026-10-04"); Show("1990-12-25", "2026-10-04"); Show("2000-10-04", "2026-10-04"); // The end of a month. 31 January reaches a whole month on 28 February, and the next on // 31 March, so 30 March is one month and 30 days. Show("2026-01-31", "2026-02-28"); Show("2026-01-31", "2026-03-30"); Show("2026-01-31", "2026-03-31"); // A leap-day birthday falls on 28 February in an ordinary year, and on the 29th in a // leap year, which makes 28 February 2028 the day before it. Show("2004-02-29", "2025-02-28"); Show("2004-02-29", "2028-02-28"); Show("2004-02-29", "2028-02-29"); // Dates the other way round, and a date that does not exist. Show("2026-10-04", "1990-03-15"); Show("2023-02-29", "2026-10-04"); return 0; } ``` Besides `Io`, its `Rux.toml` lists `Time` under `[Dependencies]`. ## Run it ```sh cd Examples/Projects/Age rux run ``` ```text born on years months days 1990-03-15 2026-10-04 36 6 19 1990-12-25 2026-10-04 35 9 9 2000-10-04 2026-10-04 26 0 0 2026-01-31 2026-02-28 0 1 0 2026-01-31 2026-03-30 0 1 30 2026-01-31 2026-03-31 0 2 0 2004-02-29 2025-02-28 21 0 0 2004-02-29 2028-02-28 23 11 30 2004-02-29 2028-02-29 24 0 0 2026-10-04 1990-03-15 refused, born after that date 2023-02-29 2026-10-04 2023-02-29 is not a date ``` ## Common mistakes ::mistake **Using a `Date?` as a `Date`.**:br`PlusMonths` may have no answer, so `var reached = birth.PlusMonths(months);` makes `reached` a `Date?`, and the next line fails: ```text error: argument 1 to 'DaysSince' has type 'Date?', but parameter 'earlier' requires 'Date' ``` Decide what absence means — here `?? fail AgeError::OutOfRange`. :: ::mistake **Skipping the correction step.**:br Without the `if on.DaysSince(reached) < 0` block the program still compiles, but every birthday not yet reached this year comes out with negative days: 15 March 1990 on 4 October 2026 gives 36 years, 7 months and −11 days. :: ## Try it yourself 1. Use today's date instead of a fixed one. `DateTime::FromTimestamp(Timestamp::Now(), UtcOffset::Utc()).date` from the Time package is today in UTC — see [Date and time](https://rux-lang.dev/docs/learn/date-time). 2. Also print the age in total days, with one `DaysSince`. 3. Print how many days remain until the next birthday. (Careful with 29 February.) 4. Read the birth date from the input instead of from the source, using [Input](https://rux-lang.dev/docs/learn/input), and keep asking until `ParseDate` accepts it. ## Learn more - [Date](https://rux-lang.dev/docs/learn/date) — `ParseDate`, `PlusDays` and friends - [Absence to error](https://rux-lang.dev/docs/learn/absence-to-error) — `?? fail` - [Enum](https://rux-lang.dev/docs/learn/enum) — why `AgeError` needs no data - Next project: [Password](https://rux-lang.dev/docs/learn/password) # Password ::note **You'll need**: Parts 1–20 — this project is a checkpoint for Utilities, and leans on [Entropy](https://rux-lang.dev/docs/learn/entropy), [Propagate](https://rux-lang.dev/docs/learn/propagate) and [Loop](https://rux-lang.dev/docs/learn/loop). :: This program makes a 16-character password. It is short, but two decisions in it carry real weight, and getting either one wrong produces a password that *looks* random and is not: - **Where the randomness comes from.** Every character is drawn straight from the operating system's entropy, never from a seeded generator. - **How a random byte becomes a character.** A byte has 256 values and the alphabet has 57 characters. Turning one into the other fairly takes a technique called **rejection sampling**. It is a checkpoint for [Part 20: Utilities](https://rux-lang.dev/docs/learn/utilities). The result has about 93 bits of strength, and it is different on every run. ## How it is put together | Piece | Its job | Lessons it uses | | ----------- | ------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `Alphabet` | 57 characters that cannot be misread | [Const](https://rux-lang.dev/docs/learn/const), [String literal](https://rux-lang.dev/docs/learn/string-literal) | | `DrawIndex` | One fair index into the alphabet, or an `EntropyError` | [Entropy](https://rux-lang.dev/docs/learn/entropy), [Loop](https://rux-lang.dev/docs/learn/loop), [Propagate](https://rux-lang.dev/docs/learn/propagate), [Pointer](https://rux-lang.dev/docs/learn/pointer) | | `Reason` | An `EntropyError` in words | [Match expression](https://rux-lang.dev/docs/learn/match-expression), [Enum](https://rux-lang.dev/docs/learn/enum) | | `Main` | Sixteen draws into an array, then one line of output | [Array](https://rux-lang.dev/docs/learn/array), [Catch](https://rux-lang.dev/docs/learn/catch), [Writable slice](https://rux-lang.dev/docs/learn/writable-slice) | ## An alphabet for people The alphabet leaves out the characters that look like each other in many fonts — `l`, `I`, `O`, `0` and `1`: ```rux const Alphabet = "abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789"; ``` A character that can be misread costs more in mistyped passwords than it adds in strength. Each character drawn from 57 adds log₂ 57 ≈ 5.83 bits, so sixteen of them give about 93 bits — far beyond guessing. ## Why not a seeded generator? A generator such as `Pcg64Dxsm` from [Random](https://rux-lang.dev/docs/learn/random) is **predictable by design**: the same seed always replays the same numbers. A password made from one is only as secret as its seed, and anyone who learns or guesses the seed can make the same password. So every character here comes from the Entropy package directly, and every request is checked: if the system has no randomness to give, the program stops rather than invent some. ## Rejection sampling Taking `byte % 57` is the obvious way to turn a byte into an index, and it is biased. 256 is four whole 57s (228) plus 28 left over, so the first 28 characters of the alphabet would get five chances in 256 while the rest get only four: | Byte values | `byte % 57` gives | Effect | | ----------- | ------------------------- | -------------------------------------- | | 0 to 227 | every index 4 times | Fair | | 228 to 255 | indices 0 to 27 once more | Biased towards the first 28 characters | The fix is to throw away a byte from that uneven top and draw again: ```rux func DrawIndex() -> uint ! EntropyError { let count = Alphabet.length; // The largest multiple of `count` that fits in a byte's 256 values: 228 for 57 characters. // Bytes below it split evenly among the characters; bytes from it upwards are rejected. let limit = 256 - 256 % count; loop { var drawn: byte = 0; Fill(@drawn as *var opaque, 1)?; if (drawn as uint) < limit { return (drawn as uint) % count; } } } ``` `loop` has no condition: it repeats until the `return` inside it fires. A byte is rejected with probability 28 / 256, about one time in nine, so the loop almost always ends on the first or second try. `Fill` writes random bytes into any memory you point it at. It takes an untyped pointer and a length, so `@drawn` — the address of the one-byte variable — is converted to `*var opaque`. The `?` passes an `EntropyError` straight to the caller. ## Nothing printed until it is complete `Main` builds the whole password in an array before printing any of it. A failure halfway therefore leaves nothing on the screen that could be mistaken for a shorter password: ```rux var password: char8[16]; for i in 0..password.length { let index = DrawIndex() catch { error => { PrintLine("no password: {}", Reason(error)); return 1; } }; password[i] = Alphabet[index]; } ``` `PrintLine` prints text views, not fixed-size arrays, so the last line passes `password[..]`, a view of the whole array. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Projects/Password){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // A password generator: sixteen characters, each drawn straight from the operating system's // entropy, from an alphabet chosen so nobody misreads the result. // // Two decisions carry the whole program. // // Where the randomness comes from. A seeded generator such as `Pcg64Dxsm` is predictable by // design, so a password made from one is only as secret as its seed. Here every character comes // from the Entropy package directly, and every request is checked: if the system has no // randomness to give, the program stops rather than invent some. // // How a random byte becomes a character. A byte has 256 values and the alphabet has 57 // characters, and 57 does not divide 256. Taking `byte % 57` would make the first 28 characters // (256 - 4 * 57 of them) a little more likely than the rest. So a byte from the uneven top of the // range is thrown away and another is drawn: rejection sampling. Every character is then exactly // as likely as every other. // // The result has 16 * log2(57), about 93 bits of strength. The output differs on every run. import Entropy::{ EntropyError, Fill }; import Io::PrintLine; // Lowercase, uppercase and digits, without the look-alikes l, I, O, 0 and 1. A character that // can be misread costs more in mistyped passwords than it adds in strength. const Alphabet = "abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789"; // An index into the alphabet, every one equally likely, or why no entropy was available. func DrawIndex() -> uint ! EntropyError { let count = Alphabet.length; // The largest multiple of `count` that fits in a byte's 256 values: 228 for 57 characters. // Bytes below it split evenly among the characters; bytes from it upwards are rejected. let limit = 256 - 256 % count; loop { var drawn: byte = 0; Fill(@drawn as *var opaque, 1)?; if (drawn as uint) < limit { return (drawn as uint) % count; } } } func Reason(error: EntropyError) -> char8[..] { return match error { EntropyError::Unsupported => "this system has no entropy source", EntropyError::Interrupted => "the request was interrupted", EntropyError::Failed => "the system refused", EntropyError::TooLarge => "too many bytes in one request" }; } func Main() -> int { PrintLine("alphabet {} ({} characters)", Alphabet, Alphabet.length); // The password is built in full before any of it is printed, so a failure halfway leaves // nothing on the screen that could be mistaken for a shorter password. var password: char8[16]; for i in 0..password.length { let index = DrawIndex() catch { error => { PrintLine("no password: {}", Reason(error)); return 1; } }; password[i] = Alphabet[index]; } // `PrintLine` prints text views, not fixed-size arrays, so `password[..]` views the whole // array. The view is writable, because the array is `var`, and it prints just the same. PrintLine("password {}", password[..]); return 0; } ``` Besides `Io`, its `Rux.toml` lists `Entropy` under `[Dependencies]`. ## Run it ```sh cd Examples/Projects/Password rux run ``` ```text alphabet abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789 (57 characters) password 3negVXPww5u2Nzh4 ``` This is a sample: the password is different on every run. ## Common mistakes ::mistake **Printing the array itself.**:br`PrintLine("password {}", password);` is refused: ```text error: no matching overload for 'PrintLine' with argument types (char8[..], char8[16]) ``` A fixed-size array is not text to `PrintLine`; a view of it, `password[..]`, is. :: ::mistake **Ignoring a failed request for entropy.**:br`Fill` returns `! EntropyError`. Drop the `?` and the call is refused: ```text error: fallible result of type '! EntropyError' is discarded ``` Here that is a safety feature: a password generator that carried on after its randomness failed would print something that only looks like a password. :: ::mistake **`byte % count` without rejection.**:br It compiles, it runs, and the passwords look random. The bias is small — 5 chances in 256 instead of 4 for some characters — which is exactly why it goes unnoticed. Tests cannot see it in one password; only the arithmetic shows it. :: ## Try it yourself 1. Let the length be a constant, `const Length = 20;`, and print the strength in bits next to the password. ([Math](https://rux-lang.dev/docs/learn/math) has `Log2`.) 2. Add a few symbols such as `-`, `_` and `!` to the alphabet. `DrawIndex` needs no change at all — why not? 3. Print five passwords, one per line, as a menu to choose from. 4. Demand at least one digit: after drawing, check the password and draw it again if it has none. Does that change the strength? ## Learn more - [Entropy](https://rux-lang.dev/docs/learn/entropy) — `Fill` and `EntropyError` - [Random](https://rux-lang.dev/docs/learn/random) — why a seeded generator is the wrong tool here - [Loop](https://rux-lang.dev/docs/learn/loop) — repeating until a `return` or `break` - Next project: [Launch](https://rux-lang.dev/docs/learn/launch) # Launch ::note **You'll need**: Parts 1–20 — this project is a checkpoint for Utilities, and leans on [Input](https://rux-lang.dev/docs/learn/input), [Parse](https://rux-lang.dev/docs/learn/parse) and [Stopwatch](https://rux-lang.dev/docs/learn/stopwatch). :: Mission control: the program runs a pre-flight checklist, asks how long a countdown you want, counts down with a pause between the numbers, and launches a rocket up the terminal. It is the most playful project in the course, and also a careful one — the answer to its one question is handled in every way it can arrive. Every part of it has appeared before. The checklist is an array of text, the countdown is a loop with a pause from the Time package, and the question is the line reading from [Input](https://rux-lang.dev/docs/learn/input), checked the way [Parse](https://rux-lang.dev/docs/learn/parse) checks a number. It is a checkpoint for [Part 20: Utilities](https://rux-lang.dev/docs/learn/utilities). ## How it is put together `Main` runs four stages in order, and only the question can end the program early: ```mermaid flowchart LR check["Checklist<br/>array + `Pause`"] --> ask["Ask: count down from?<br/>1 to 10, Enter for 10"] ask -- "end of input" --> scrub(["Mission scrubbed<br/>status 0"]) ask -- "read error" --> radio(["Radio down<br/>status 1"]) ask -- "a valid answer" --> count["`T minus …`<br/>`while count > 0`"] count --> lift["Ignition and<br/>rocket frames"] ``` | Piece | Lessons it uses | | --------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ | | Checklist and rocket frames | [Array](https://rux-lang.dev/docs/learn/array), [For](https://rux-lang.dev/docs/learn/for), [Character](https://rux-lang.dev/docs/learn/character) (`\u{…}`) | | `Pause` | [Duration](https://rux-lang.dev/docs/learn/duration), [Discard](https://rux-lang.dev/docs/learn/discard) | | The question | [Input](https://rux-lang.dev/docs/learn/input), [String view](https://rux-lang.dev/docs/learn/string-view), [Guard](https://rux-lang.dev/docs/learn/guard) | | Checking the answer | [Parse](https://rux-lang.dev/docs/learn/parse), [Catch fallback](https://rux-lang.dev/docs/learn/catch-fallback) | | The countdown | [While](https://rux-lang.dev/docs/learn/while), [Assignment](https://rux-lang.dev/docs/learn/assignment) | ## A pause that may be skipped `SleepFor` returns a fallible: the operating system may refuse to sleep. A countdown that skips a pause is only quicker, never wrong, so `Pause` discards a failure — on purpose, and visibly: ```rux func Pause(milliseconds: int64) { SleepFor(Duration::FromMilliseconds(milliseconds)) catch { else => {} }; } ``` `catch { else => {} }` is the standard way to say "I have considered this failure and it does not matter". Writing the call without it is an error, as Common mistakes shows. ## A question with a guaranteed answer The question is asked in a loop that runs until `count` holds a usable number. `count` starts at 0, which is not a valid answer, so the loop runs at least once: ```rux let answer = builder.View().Trim(); if answer.IsEmpty() { count = 10; } else { // Text that is not a number becomes 0, which the range check refuses as well. let asked = ParseInt32(answer) catch { else => 0 }; if asked >= 1 && asked <= 10 { count = asked; } else { PrintLine("Mission rules allow 1 to 10. Say again?"); } } ``` Three kinds of answer are handled with very little code: | Typed | What happens | | ------------- | ------------------------------------------------------------------ | | Nothing | The default, 10 | | 1 to 10 | That number | | Anything else | Asked again — text parses to the fallback 0, which is out of range | Folding "not a number" into "out of range" with `catch { else => 0 }` is a neat trick here, because 0 is never a valid answer. Whatever happens, the countdown is bounded: it can never be asked to count from a million. Before all that, the same guarded match as in [Guess](https://rux-lang.dev/docs/learn/guess) decides what the end of the input means. Here nobody gave the go, so the mission is scrubbed — a normal outcome with status 0. A read error is a broken radio, and exits with status 1. ## Countdown and liftoff The countdown is a plain `while` that pauses between numbers: ```rux while count > 0 { PrintLine(" T minus {}...", count); Pause(400); count -= 1; } ``` The rocket climbs because each frame is printed on a new line with a little less indentation than the one before, and the pauses between them let you watch it go. The emoji are written as `\u{1F680}` escapes in the source, so the file itself stays plain ASCII and every editor shows it the same way. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Projects/Launch){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // Mission control: run the checklist, ask how long a countdown you want, count down, and launch. // // Every part of this has appeared before. The checklist is an array of text, the countdown is a // loop with a pause from the Time package between steps, and the question is the line reading // from the Input lesson, with the number checked the way the Parse lesson checks it. // // What makes it a whole program is that the input is handled in every way it can arrive. A // number from 1 to 10 sets the countdown and an empty line takes the default of 10, so the // countdown is always bounded. Anything else is asked again. And if the input ends before an // answer arrives (Ctrl+Z and Enter on Windows, Ctrl+D elsewhere, or the end of piped input), // nobody gave the go, so the mission is scrubbed. import Allocator::{ Allocator, SystemAllocator }; import Format::ParseInt32; import Io::{ IoErrorKind, Print, PrintLine, ReadLine }; import Text::StringBuilder; import Time::{ Duration, SleepFor }; // A pause that does not happen only makes the countdown quicker, so a failed sleep is ignored // on purpose rather than by accident. func Pause(milliseconds: int64) { SleepFor(Duration::FromMilliseconds(milliseconds)) catch { else => {} }; } func Main() -> int { PrintLine("\u{1F680} RUX MISSION CONTROL \u{1F680}"); PrintLine("========================"); let checklist = [ "fuel ............. loaded", "crew ............. strapped in", "weather .......... clear skies", "snacks ........... dangerously low", "borrow checker ... satisfied" ]; for item in checklist { PrintLine(" {} \u{2705}", item); Pause(150); } PrintLine(); var system = SystemAllocator(); let allocator: Allocator = system; var builder = StringBuilder(allocator); var count = 0; while count == 0 { Print("Count down from? (1 to 10, Enter for 10) "); builder.Clear(); match ReadLine(builder) { .Success(_) => {}, .Failure(error) if error.kind == IoErrorKind::EndOfStream => { PrintLine(); PrintLine("No go from the flight director. Mission scrubbed. \u{1F6D1}"); return 0; }, .Failure(_) => { PrintLine("The radio is down: the input could not be read."); return 1; } } let answer = builder.View().Trim(); if answer.IsEmpty() { count = 10; } else { // Text that is not a number becomes 0, which the range check refuses as well. let asked = ParseInt32(answer) catch { else => 0 }; if asked >= 1 && asked <= 10 { count = asked; } else { PrintLine("Mission rules allow 1 to 10. Say again?"); } } } PrintLine(); while count > 0 { PrintLine(" T minus {}...", count); Pause(400); count -= 1; } PrintLine(" \u{1F525} IGNITION \u{1F525}"); Pause(500); // Each frame is one line, so the rocket climbs up the terminal as it prints. let frames = [ " \u{1F680}", " \u{1F680}", " \u{1F680}", " \u{1F680}", " \u{1F680}", " \u{1F680}", " \u{1F680}", " \u{1F680}" ]; for frame in frames { PrintLine(frame); Pause(120); } PrintLine(); PrintLine(" \u{2B50} \u{1F30D} \u{2B50}"); PrintLine(" Liftoff! The crew waves from the window. \u{1F44B}"); return 0; } ``` Besides `Io`, its `Rux.toml` lists `Allocator`, `Format`, `Text` and `Time` under `[Dependencies]`. ## Run it ```sh cd Examples/Projects/Launch rux run ``` ```text 🚀 RUX MISSION CONTROL 🚀 ======================== fuel ............. loaded ✅ crew ............. strapped in ✅ weather .......... clear skies ✅ snacks ........... dangerously low ✅ borrow checker ... satisfied ✅ Count down from? (1 to 10, Enter for 10) 20 Mission rules allow 1 to 10. Say again? Count down from? (1 to 10, Enter for 10) 3 T minus 3... T minus 2... T minus 1... 🔥 IGNITION 🔥 🚀 🚀 🚀 🚀 🚀 🚀 🚀 🚀 ⭐ 🌍 ⭐ Liftoff! The crew waves from the window. 👋 ``` The answer can be piped in. With no input at all, nobody gave the go, and after the checklist the run ends with: ```sh "3" | rux run $null | rux run ``` ```text Count down from? (1 to 10, Enter for 10) No go from the flight director. Mission scrubbed. 🛑 ``` The program waits for an answer after the checklist. Run it, type a number from 1 to 10 (or just press Enter for 10) and watch the countdown. End the input instead — Ctrl+Z and Enter on Windows, Ctrl+D elsewhere — to scrub the mission. The piped examples above are written for PowerShell; in a POSIX shell, `echo 3 | rux run` and `rux run < /dev/null` do the same. Whether the emoji show up depends on your terminal and its font. ## Common mistakes ::mistake **Calling `SleepFor` and ignoring the result.**:br`SleepFor(Duration::FromMilliseconds(milliseconds));` on its own is refused: ```text error: fallible result of type '! TimeError' is discarded ``` Even a failure you do not care about has to be discarded on purpose, with `catch { else => {} }`. :: ::mistake **A countdown nobody bounded.**:br Accept any number that parses and someone will type `1000000`. At 0.4 seconds a step, the program would still be counting four and a half days later. Checking the range on input keeps every later part of the program simple. :: ## Try it yourself 1. Add a "hold" option: if the answer is `h`, print "Holding." and ask again. 2. Let the checklist fail: make one item `"weather .......... storm"` and scrub the launch if any item does not end with a known good word. (Hint: [String view](https://rux-lang.dev/docs/learn/string-view) can test how text ends.) 3. Time the whole countdown with a [Stopwatch](https://rux-lang.dev/docs/learn/stopwatch) and print how long it really took, pauses and all. 4. Make the rocket climb diagonally: change both the indentation and the number of empty lines between frames. ## Learn more - [Duration](https://rux-lang.dev/docs/learn/duration) and [Stopwatch](https://rux-lang.dev/docs/learn/stopwatch) — the Time package - [Discard](https://rux-lang.dev/docs/learn/discard) — ignoring a failure on purpose - [Input](https://rux-lang.dev/docs/learn/input) and [Parse](https://rux-lang.dev/docs/learn/parse) - Next project: [Notes](https://rux-lang.dev/docs/learn/notes), the checkpoint for Data formats # Notes ::note **You'll need**: Parts 1–21 — this project is the checkpoint for Data formats, and leans on [File](https://rux-lang.dev/docs/learn/file), [Atomic file](https://rux-lang.dev/docs/learn/atomic-file), [JSON](https://rux-lang.dev/docs/learn/json) and [Writing JSON](https://rux-lang.dev/docs/learn/json-write). :: A to-do list is only useful if it is still there tomorrow. This program keeps one as JSON in a file: it saves a list, loads it back as if it were a new session, adds a note, saves again, and then deals with the two things that go wrong with real files — one that someone damaged by hand, and one that is not there at all. It is the checkpoint for [Part 21: Data formats](https://rux-lang.dev/docs/learn/data-formats), and it brings together files from [Part 19](https://rux-lang.dev/docs/learn/files), JSON from Part 21, and the error handling of [Part 9](https://rux-lang.dev/docs/learn/errors) at full strength: five different error types meet in one program. ## How it is put together Each note is a small JSON object, `{"title": "...", "done": false}`, and the list is a JSON array of them. Saving turns the tree of `JsonValue`s into text and writes it; loading reads the text and parses it back into a tree: ```mermaid flowchart LR tree["`JsonValue` tree<br/>in memory"] -- "`Encode`<br/>`WriteValue`, pretty" --> text["JSON text<br/>`String`"] text -- "`Save`<br/>`WriteAtomically`" --> file[("`Bin/notes.json`")] file -- "`Load`<br/>`Open`, `Size`, `ReadExact`" --> bytes["bytes"] bytes -- "`Parse`" --> tree ``` | Function | Its job | Can fail with | Lessons it uses | | ------------ | -------------------------------------------- | ---------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- | | `Note` | Builds one note object | `TextError` | [Writing JSON](https://rux-lang.dev/docs/learn/json-write), [Move](https://rux-lang.dev/docs/learn/move) | | `Encode` | Turns the tree into indented text | `FormatError` | [Writing JSON](https://rux-lang.dev/docs/learn/json-write), [String builder](https://rux-lang.dev/docs/learn/string-builder) | | `Save` | Replaces the file in one step | `IoError` | [Atomic file](https://rux-lang.dev/docs/learn/atomic-file) | | `Load` | Reads the whole file and parses it | `IoError`, `CollectionError`, `JsonParseError` | [File](https://rux-lang.dev/docs/learn/file), [Dynamic array](https://rux-lang.dev/docs/learn/dynamic-array), [JSON](https://rux-lang.dev/docs/learn/json) | | `PrintNotes` | Prints the list, tolerating missing members | nothing | [JSON](https://rux-lang.dev/docs/learn/json), [Out parameter](https://rux-lang.dev/docs/learn/out-parameter) | | `Main` | Two sessions, a damaged file, a missing file | all five | [Error sum](https://rux-lang.dev/docs/learn/error-sum), [Typed pattern](https://rux-lang.dev/docs/learn/typed-pattern) | ## Building a note A note is an object with two members. Building it can fail — copying text into a new `String` needs memory — so every step ends in `?`: ```rux func Note(allocator: Allocator, title: char8[..], done: bool) -> JsonValue ! TextError { var note = JsonValue::Object(allocator); note.Insert(String::FromBytes(allocator, "title")?, JsonValue::Text(allocator, title)?); note.Insert(String::FromBytes(allocator, "done")?, JsonValue::Boolean(allocator, done)); return <-note; } ``` A `JsonValue` owns the memory of everything inside it, so it cannot be copied — only moved. `return <-note;` hands it to the caller. ## Saving whole or not at all `Save` is one call, and the call is the point: ```rux func Save(allocator: Allocator, path: Path, text: char8[..]) -> ! IoError { WriteAtomically(allocator, path, text)?; } ``` `WriteAtomically` writes the new text beside the old file and swaps it in only once it is complete. If the program crashes halfway through a save, the old list is still there, whole. Writing over the file directly would risk leaving half a list behind — the one outcome a notes file must never have. ## Loading, step by step `Load` asks the file how big it is, reads exactly that many bytes into an array of that size, and parses them: ```rux func Load(allocator: Allocator, path: Path) -> JsonValue ! (IoError | CollectionError | JsonParseError) { var file = File::Open(allocator, path, OpenOptions::Reading())?; let size = file.Size()?; var bytes = Array::Filled<char8>(allocator, size as uint, c8' ')?; ReadExact(file, bytes.AsMutableSlice())?; file.Close()?; return Parse(allocator, bytes.AsSlice())?; } ``` Each line can fail in its own way: opening and reading with an `IoError`, allocating the array with a `CollectionError`, parsing with a `JsonParseError`. The return type lists all three as a sum, and every `?` passes its error through unchanged. ## Reading what may not be there A file read from disk may have been edited by hand, so `PrintNotes` does not assume a note has both members. `Find` returns a pointer that is `null` when the member is missing: ```rux let title = (*note).Find(StringView::FromValidated("title")); let flag = (*note).Find(StringView::FromValidated("done")); var done = false; if flag != null { (*flag).AsBoolean(@done); } ``` `AsBoolean` writes its answer through an out-parameter, and leaves `done` alone if the member is not a boolean. A note with no title prints as `(untitled)`. ## Expected failures, and the rest `Main` is declared to fail with all five error types, so `?` can pass anything up — and a failure then ends the program with status 1. But two failures are **expected**, and those are handled where they happen. A damaged file is a `JsonParseError`, which knows the byte where the text stopped making sense: ```rux match Load(allocator, path) { .Success(_) => PrintLine("the damaged file loaded?"), .Failure(error: JsonParseError) => PrintLine("damaged file refused at byte {}: {}", error.Offset(), error), .Failure(error) => fail error } ``` A missing file is an `IoError` of kind `NotFound`, picked out with a typed pattern **and** a guard. In a real program, that arm is where "start a new, empty list" would go: ```rux .Failure(error: IoError) if error.kind == IoErrorKind::NotFound => PrintLine("no notes file any more: starting a new list would begin here"), .Failure(error) => fail error ``` In both matches the last arm, `.Failure(error) => fail error`, passes anything unexpected out of `Main`, which ends the program with status 1. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Projects/Notes){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // Notes: a to-do list that outlives the program, kept as JSON in a file. // // Each note is a small JSON object, `{"title": "...", "done": false}`, and the list is an array // of them. Saving turns the tree of `JsonValue`s into text and writes it to disk; loading reads // the text back and parses it into a tree again. Between the two, the program could stop and // start a hundred times, which is the whole point of a file. // // A file is also where things go wrong. It may be missing, or it may hold something that is not // JSON, perhaps because someone edited it by hand. Every step that touches the disk or parses // text is fallible, and the program handles the two failures it expects — a damaged file and a // missing one — while `?` hands anything stranger to `Main`, which then ends with status 1. // // The file lives in this package's `Bin/` folder, and the program deletes it at the end. import Allocator::{ Allocator, SystemAllocator }; import Collections::{ Array, CollectionError }; import FileSystem::{ DeleteFile, File, OpenOptions, WriteAtomically }; import Io::{ IoError, IoErrorKind, PrintLine, ReadExact }; import Json::{ JsonParseError, JsonStyle, JsonValue, Parse, WriteValue }; import Path::{ OsString, Path }; import Text::{ FormatError, String, StringBuilder, StringView, TextError, TextWriter }; func Note(allocator: Allocator, title: char8[..], done: bool) -> JsonValue ! TextError { var note = JsonValue::Object(allocator); note.Insert(String::FromBytes(allocator, "title")?, JsonValue::Text(allocator, title)?); note.Insert(String::FromBytes(allocator, "done")?, JsonValue::Boolean(allocator, done)); return <-note; } // Turns the notes into indented JSON text, ready to be written or shown. func Encode(allocator: Allocator, notes: &JsonValue) -> String ! FormatError { var builder = StringBuilder(allocator); let sink: &var TextWriter = builder; WriteValue(sink, notes, JsonStyle::Pretty())?; return builder.IntoString(); } // Writing atomically means the old file is replaced only once the new one is complete, so a // crash halfway through a save can never leave half a list behind. func Save(allocator: Allocator, path: Path, text: char8[..]) -> ! IoError { WriteAtomically(allocator, path, text)?; } // Asks the file how big it is, reads exactly that many bytes, and parses them. func Load(allocator: Allocator, path: Path) -> JsonValue ! (IoError | CollectionError | JsonParseError) { var file = File::Open(allocator, path, OpenOptions::Reading())?; let size = file.Size()?; var bytes = Array::Filled<char8>(allocator, size as uint, c8' ')?; ReadExact(file, bytes.AsMutableSlice())?; file.Close()?; return Parse(allocator, bytes.AsSlice())?; } // A note read from a file might lack a member, so each one is checked before it is read. func PrintNotes(notes: &JsonValue) { for i in 0..notes.Length() { let note = notes.At(i); let title = (*note).Find(StringView::FromValidated("title")); let flag = (*note).Find(StringView::FromValidated("done")); var done = false; if flag != null { (*flag).AsBoolean(@done); } let mark = done ? "x" : " "; if title != null { PrintLine(" [{}] {}", mark, (*title).AsText()); } else { PrintLine(" [{}] (untitled)", mark); } } } func Main() -> ! (IoError | TextError | FormatError | CollectionError | JsonParseError) { var system = SystemAllocator(); let allocator: Allocator = system; var holder = OsString::FromText(allocator, "Bin/notes.json")?; let path = Path::FromView(holder.View()); // The first session: start a list and save it. var notes = JsonValue::Array(allocator); notes.Push(Note(allocator, "buy milk", true)?); notes.Push(Note(allocator, "water the plants", false)?); let first = Encode(allocator, notes)?; Save(allocator, path, first.View().Bytes())?; PrintLine("saved {} notes to {}", notes.Length(), path); // The next session knows nothing but the file: load it, add a note, save it again. var loaded = Load(allocator, path)?; loaded.Push(Note(allocator, "write a Rux program", false)?); let second = Encode(allocator, loaded)?; Save(allocator, path, second.View().Bytes())?; PrintLine("added a note; the file now reads:"); PrintLine("{}", second); // And one more time, to read the list as a person would. let final = Load(allocator, path)?; PrintLine("{} notes:", final.Length()); PrintNotes(final); // Someone edits the file by hand and cuts it short. Loading now fails as a parse error, which // says where the text stopped making sense. Save(allocator, path, "[{\"title\": \"half a note\"")?; match Load(allocator, path) { .Success(_) => PrintLine("the damaged file loaded?"), .Failure(error: JsonParseError) => PrintLine("damaged file refused at byte {}: {}", error.Offset(), error), .Failure(error) => fail error } // Clean up, then show that a missing file is told apart from every other I/O failure. DeleteFile(allocator, path)?; match Load(allocator, path) { .Success(_) => PrintLine("the deleted file loaded?"), .Failure(error: IoError) if error.kind == IoErrorKind::NotFound => PrintLine("no notes file any more: starting a new list would begin here"), .Failure(error) => fail error } } ``` Besides `Io`, its `Rux.toml` lists `Allocator`, `Collections`, `FileSystem`, `Json`, `Path` and `Text` under `[Dependencies]`. ## Run it ```sh cd Examples/Projects/Notes rux run ``` ```text saved 2 notes to Bin/notes.json added a note; the file now reads: [ { "title": "buy milk", "done": true }, { "title": "water the plants", "done": false }, { "title": "write a Rux program", "done": false } ] 3 notes: [x] buy milk [ ] water the plants [ ] write a Rux program damaged file refused at byte 24: document ended in the middle of a value no notes file any more: starting a new list would begin here ``` The file is written to the package's `Bin/` folder, next to the build output, and the program deletes it before it ends, so a second run starts from nothing again. ## Common mistakes ::mistake **Returning a `JsonValue` without moving it.**:br`return note;` is refused: ```text error: move-only value 'note' requires an explicit '<-' in return ``` It comes with the note that `JsonValue` prohibits copying. Write `return <-note;` — see [Move](https://rux-lang.dev/docs/learn/move). :: ::mistake **Handling only the failure you were thinking of.**:br Drop the last arm from the damaged-file match and the compiler lists what is left: ```text error: match on 'JsonValue ! (CollectionError | IoError | JsonParseError)' is not exhaustive; missing .Failure(_: CollectionError), .Failure(_: IoError) ``` One catch-all arm that passes the rest on is enough. :: ::mistake **A `?` the function's type does not allow.**:br If `Load` is declared `-> JsonValue ! (IoError | JsonParseError)`, the array allocation stops compiling: ```text error: '?' propagates error type 'CollectionError', but the enclosing function fails with 'IoError | JsonParseError' ``` The sum must name every error its `?`s can carry. :: ## Try it yourself 1. Mark a note as done: load the list, find "water the plants", set its `done` member to `true`, and save it again. 2. Turn the missing-file arm into real behaviour: when the file is not there, start with an empty array instead of failing. 3. Make the program a tiny command-line tool: read one line from the input with [Input](https://rux-lang.dev/docs/learn/input), add it as a note, save, and print the list. Remove the `DeleteFile` call so the notes survive between runs. 4. Damage the file differently — a missing comma, a stray `}` — and see what offset and message the parser reports for each. ## Learn more - [JSON](https://rux-lang.dev/docs/learn/json) and [Writing JSON](https://rux-lang.dev/docs/learn/json-write) - [File](https://rux-lang.dev/docs/learn/file) and [Atomic file](https://rux-lang.dev/docs/learn/atomic-file) - [Error sum](https://rux-lang.dev/docs/learn/error-sum) and [Typed pattern](https://rux-lang.dev/docs/learn/typed-pattern) — one function, several kinds of failure - Next project: [Melody](https://rux-lang.dev/docs/learn/melody), the checkpoint for Platform # Melody ::note **You'll need**: Parts 1–24 — this project is the checkpoint for Platform, and leans on [Extern](https://rux-lang.dev/docs/learn/extern), [Target](https://rux-lang.dev/docs/learn/target) and [Compile error](https://rux-lang.dev/docs/learn/compile-error). :: This program plays the opening of Beethoven's *Ode to Joy*, one note at a time, through the console speaker. There is no portable way to make a sound and no standard package that wraps one, so it does what a systems language is for: it calls the operating system directly. The function it calls is `Beep` in Windows' Kernel32 library, which plays a tone of a given frequency for a given number of milliseconds — exactly the shape of a musical note. That makes this the checkpoint for [Part 24: Platform](https://rux-lang.dev/docs/learn/platform), and the last project in the course. It builds and runs **only on Windows**, and it says so clearly everywhere else. ## How it is put together | Piece | Its job | Lessons it uses | | --------------------------- | ----------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `when #target.os` | Declares `Beep` on Windows, stops the build elsewhere | [When](https://rux-lang.dev/docs/learn/when), [Target](https://rux-lang.dev/docs/learn/target), [Compile error](https://rux-lang.dev/docs/learn/compile-error) | | `#Link` and `extern` | Binds `Beep` to Kernel32 | [Extern](https://rux-lang.dev/docs/learn/extern) | | `C4` … `G4` | Note frequencies as named constants | [Const](https://rux-lang.dev/docs/learn/const) | | `Note` and the `tune` array | The music, as data | [Struct](https://rux-lang.dev/docs/learn/struct), [Array](https://rux-lang.dev/docs/learn/array) | | `Main` | Plays each note, stops at the first failure | [For](https://rux-lang.dev/docs/learn/for), [Boolean](https://rux-lang.dev/docs/learn/boolean) | When `Main` calls `Beep`, nothing in Rux sits in between — the call goes straight to the system library: ```mermaid flowchart LR main(["`Main`<br/>`for note in tune`"]) -- "`Beep(frequency, duration)`" --> decl["`extern Beep`<br/>declared in Rux"] decl -- "linked by `#Link`" --> dll["`Kernel32.dll`"] dll --> spk["console speaker"] dll -- "`bool32`: did it play?" --> main ``` ## Windows only, on purpose The declaration of `Beep` sits inside a compile-time `when`, which picks a branch while compiling rather than while running: ```rux when #target.os { .Windows => { #Link("Kernel32.dll") extern { func Beep(frequency: uint32, duration: uint32) -> bool32; } }, else => #Error("Melody plays through the Windows Beep function, so it builds only for Windows") } ``` On Windows the first branch declares `Beep` and says which library holds it. On any other system there is no `Beep` to call. Without the `else` branch the build would still stop there, but with `error: no arm of this 'when' matches .Linux` — accurate, and no help to someone who only wanted to hear a tune. `#Error` stops it with a sentence a person can act on instead. Checking for Linux shows it: ```sh rux check --target linux-x86_64 ``` ```text error: Melody plays through the Windows Beep function, so it builds only for Windows ``` The branches `when` skips are never even type-checked, which is why the Windows-only declaration costs other systems nothing. ## The tune as data Raw frequencies such as 330 and 392 mean nothing on the page, so each note gets a name. Then the tune is an array of `Note` structs that reads almost like a score: ```rux const C4: uint32 = 262; const D4: uint32 = 294; const E4: uint32 = 330; const F4: uint32 = 349; const G4: uint32 = 392; ``` ```rux Note { name: "E", frequency: E4, milliseconds: 400 }, Note { name: "E", frequency: E4, milliseconds: 400 }, Note { name: "F", frequency: F4, milliseconds: 400 }, Note { name: "G", frequency: G4, milliseconds: 400 }, ``` The constants are typed `uint32`, because that is what `Beep` takes and what the `frequency` field holds. An untyped constant would be an `int`, and every note would be refused — see Common mistakes. ## A foreign failure, checked by hand A foreign function does not report failure through a Rux fallible. `Beep` returns a `bool32` that is false when no tone could be played — and the compiler will not insist that you look at it. The program looks anyway, and stops at the first note that fails rather than printing notes nobody heard: ```rux for note in tune { Print("{} ", note.name); if !Beep(note.frequency, note.milliseconds) { PrintLine(); PrintLine("Windows could not play a tone, so the tune stops here."); return 1; } } ``` `Beep` also blocks until the note has finished, so the loop needs no pauses of its own: the durations in the tune *are* the rhythm. The whole tune lasts about six seconds. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Projects/Melody){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // Playing a tune by asking the operating system to sound one note at a time. // // There is no portable way to make a sound, and no standard package wraps one, so this program // calls Windows directly: `Beep(frequency, duration)` in Kernel32 plays a tone of that many // hertz for that many milliseconds, which is exactly the shape of a note. It is the extern // declaration and `#Link` from the Extern lesson, put to work. // // That makes the program Windows-only, and it says so where it matters: on any other system the // `when` below stops the build with an `#Error`, instead of letting it fail to link a function // that does not exist there. // // A foreign function reports failure its own way, not through a Rux fallible. `Beep` returns a // `bool32` that is false when no tone could be played, so every call is checked, and the tune // stops at the first note that fails rather than printing notes nobody heard. import Core::{ #Error, #target }; import Io::{ Print, PrintLine }; when #target.os { .Windows => { #Link("Kernel32.dll") extern { func Beep(frequency: uint32, duration: uint32) -> bool32; } }, else => #Error("Melody plays through the Windows Beep function, so it builds only for Windows") } // Note frequencies in hertz, near the middle of a piano. Naming them keeps the tune readable as // music rather than as numbers. const C4: uint32 = 262; const D4: uint32 = 294; const E4: uint32 = 330; const F4: uint32 = 349; const G4: uint32 = 392; struct Note { name: char8[..]; frequency: uint32; milliseconds: uint32; } func Main() -> int { // The opening of Beethoven's Ode to Joy. let tune: Note[15] = [ Note { name: "E", frequency: E4, milliseconds: 400 }, Note { name: "E", frequency: E4, milliseconds: 400 }, Note { name: "F", frequency: F4, milliseconds: 400 }, Note { name: "G", frequency: G4, milliseconds: 400 }, Note { name: "G", frequency: G4, milliseconds: 400 }, Note { name: "F", frequency: F4, milliseconds: 400 }, Note { name: "E", frequency: E4, milliseconds: 400 }, Note { name: "D", frequency: D4, milliseconds: 400 }, Note { name: "C", frequency: C4, milliseconds: 400 }, Note { name: "C", frequency: C4, milliseconds: 400 }, Note { name: "D", frequency: D4, milliseconds: 400 }, Note { name: "E", frequency: E4, milliseconds: 400 }, Note { name: "E", frequency: E4, milliseconds: 600 }, Note { name: "D", frequency: D4, milliseconds: 200 }, Note { name: "D", frequency: D4, milliseconds: 800 } ]; PrintLine("Ode to Joy, through the console speaker:"); for note in tune { Print("{} ", note.name); if !Beep(note.frequency, note.milliseconds) { PrintLine(); PrintLine("Windows could not play a tone, so the tune stops here."); return 1; } } PrintLine(); return 0; } ``` Besides `Io`, its `Rux.toml` lists `Core` under `[Dependencies]`. ## Run it ```sh cd Examples/Projects/Melody rux run ``` ```text Ode to Joy, through the console speaker: E E F G G F E D C C D E E D D ``` Run it on Windows with the sound turned up. Each note name is printed as it plays. On a machine with no sound device `Beep` may fail, and then the program says so and exits with status 1. On Linux, macOS or FreeBSD the build stops with the `#Error` message shown above. ## Common mistakes ::mistake **Calling a foreign function as if it could not fail.**:br`Beep(C4, 100);` on its own compiles without a word: a `bool32` result is not a fallible, so nothing makes you check it. The safety a Rux fallible gives you ends at the `extern` boundary, and the checking becomes your job. :: ::mistake **A `when` with no answer for other systems.**:br Without the `else => #Error(…)` branch, a build for Linux stops with: ```text error: no arm of this 'when' matches .Linux ``` That is correct but unhelpful. Whenever code is platform-specific, say why in an `#Error` of your own. :: ::mistake **Untyped note constants.**:br With `const E4 = 330;` the constant is an `int`, and every note that uses it fails: ```text error: field 'frequency' in initializer for 'Note' has type 'int', but its declaration requires 'uint32' ``` Give the constants the type the foreign function expects, once, where they are declared. :: ## Try it yourself 1. Add rests: a `Note` with frequency 0 that pauses instead of beeping. `Beep` only plays frequencies from 37 to 32767 hertz, so the loop has to tell rests apart — [Duration](https://rux-lang.dev/docs/learn/duration) and `SleepFor` provide the pause. 2. Add a tempo: a constant that scales every duration, so the whole tune can be played faster or slower by changing one number. 3. Play the next phrase of *Ode to Joy* (E E F G G F E D C C D E D C C). Which constants and array length have to change? 4. Make the program portable in a different way: on systems other than Windows, instead of stopping the build, print the note names with a pause between them so the rhythm still shows. Use `when` to choose the body of a `PlayNote` function. ## Learn more - [Extern](https://rux-lang.dev/docs/learn/extern), [Target](https://rux-lang.dev/docs/learn/target) and [Compile error](https://rux-lang.dev/docs/learn/compile-error) - [Beep](https://rux-lang.dev/docs/api/windows/console#beep) in the API reference - [External functions](https://rux-lang.dev/docs/lang/ffi/overview) and [Conditional compilation](https://rux-lang.dev/docs/lang/comptime/conditional) in the Rux Reference - Back to the [Projects overview](https://rux-lang.dev/docs/learn/projects) for the full list # Grep ::note **You'll need**: Parts 1–26 — this project is the checkpoint for Systems, and leans on [Command line](https://rux-lang.dev/docs/learn/command-line), [Regular expressions](https://rux-lang.dev/docs/learn/regex), [File](https://rux-lang.dev/docs/learn/file) and [Buffered I/O](https://rux-lang.dev/docs/learn/buffered-io). :: `grep` is one of the oldest tools on Unix and still one of the most used: give it a pattern and some files, and it prints every line that matches. This project builds a small one — a real command-line tool, with options, a help text, error messages and an exit status that scripts can rely on: ```sh rux run -- -in "name" Rux.toml ``` It is the checkpoint for [Part 26: Systems](https://rux-lang.dev/docs/learn/systems), and it brings three parts of the course together: reading the command line from Part 26, regular expressions from [Part 14: Text](https://rux-lang.dev/docs/learn/text), and files read line by line from [Part 19: Files](https://rux-lang.dev/docs/learn/files). ## Try it first Before reading on, try writing it yourself. Start with the smallest version that works — `grep <pattern> <file>`, printing matching lines — then add one option at a time: `-n` for line numbers, `-c` for a count, `-i` to ignore case, `-v` to invert the match, and more than one file. Everything you need has appeared in a lesson, and the table below says which. ## How it is put together ```mermaid flowchart LR args["arguments"] -- "ParseProcess" --> parsed["Parsed"] parsed -- "Pattern" --> regex["Regex"] parsed -- "paths" --> files["each file"] files -- "SearchFile<br/>BufferedReader" --> lines["lines"] regex --> lines lines --> out["printed lines<br/>and exit status"] ``` | Function | Its job | Lessons it uses | | ------------ | --------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `Main` | Describes the command and picks real or tour mode | [Command line](https://rux-lang.dev/docs/learn/command-line), [Environment](https://rux-lang.dev/docs/learn/environment) | | `Run` | Turns one parsed command line into a search | [Command line](https://rux-lang.dev/docs/learn/command-line), [Regular expressions](https://rux-lang.dev/docs/learn/regex) | | `Pattern` | The pattern as text, with `(?i)` in front for `-i` | [Path](https://rux-lang.dev/docs/learn/path), [Move](https://rux-lang.dev/docs/learn/move) | | `SearchFile` | Reads one file line by line and prints what matches | [File](https://rux-lang.dev/docs/learn/file), [Buffered I/O](https://rux-lang.dev/docs/learn/buffered-io), [Error sum](https://rux-lang.dev/docs/learn/error-sum) | | `Split` | Cuts a fixed command line into arguments | [Writable slice](https://rux-lang.dev/docs/learn/writable-slice) | ## The command, described The options and arguments are a `CommandSpec`, so the help text and the error messages come from the same place as the parsing. Four flags, a required pattern, and any number of paths: ```rux let positionals: PositionalSpec[2] = [ Required("pattern", "The regular expression to look for"), Remaining("paths", "The files to search") ]; let grep = Command("grep", "Print the lines of files that match a pattern") .WithOptions(options[..]).WithPositionals(positionals[..]); ``` ## Two ways to run A tool that only works with arguments would print nothing useful under a plain `rux run`. So `Main` looks at [`ArgumentCount`](https://rux-lang.dev/docs/learn/environment) first. With real arguments it parses them and returns `Run`'s answer as the program's exit status: ```rux if ArgumentCount() > 1 { let parsed = ParseProcess(@grep) catch { error => { PrintLine("grep: {}", error); WriteUsage(grep, screen) catch { else => {} }; return 2; } }; return Run(allocator, parsed, screen) catch { else => 2 }; } ``` With none, it takes a **tour**: seven fixed command lines over the package's own files, each split at its spaces and checked with `Parse`, as the [Command line](https://rux-lang.dev/docs/learn/command-line) lesson did. Paths such as `Src/Main.rux` are relative, and `rux run` runs the program in the package's folder, so they are found. ## Ignoring case The Regex package takes flags inside the pattern: `(?i)` at the front makes the whole pattern ignore case. So `-i` needs no special searching — `Pattern` just puts the flag in front of the text: ```rux func Pattern(allocator: Allocator, parsed: &Parsed) -> String ! TextError { let typed = (parsed.Positional("pattern") ?? OsStringView()).ToText(allocator)?; if !parsed.Has("ignore-case") { return <-typed; } return Concat(allocator, StringView::FromValidated("(?i)"), typed.View()); } ``` The pattern arrives as native text and the Regex package wants UTF-8, so `ToText` converts it, and fails for an argument that is not text at all. ## Searching a file `SearchFile` opens the file, wraps it in a `BufferedReader` — reading a byte at a time from the system would be slow — and reads one line at a time with `ReadTextLine`. The end of the file arrives as an error, the one that is expected: ```rux ReadTextLine(reader, line, 65536) catch { error if error.IsEnd() => break, error => fail error }; number += 1; if regex.IsMatch(line.View().Bytes())? != show.invert { ``` Comparing the match with `show.invert` is the whole of `-v`: a line is selected when it matches and `-v` is off, or does not match and `-v` is on. The limit of 65536 bytes is a guard against a "line" that is really a whole binary file. ## Exit status Scripts read a tool's exit status, not its output, so it follows the real `grep`: | Status | Means | | ------ | ----------------------------------------------------------------------------- | | 0 | at least one line was selected | | 1 | the search worked, and nothing was selected | | 2 | something went wrong: a bad pattern, a bad option, a file that cannot be read | A file that cannot be read does not stop the search: `Run` reports it, remembers status 2, and goes on to the next file. ## The program The whole lesson is one package in the [Examples repository](https://github.com/rux-lang/Examples/tree/main/Projects/Grep){rel=""nofollow""}. Its comments explain every step. ```rux [Src/Main.rux] // Grep: print the lines of some files that match a regular expression, the way the Unix tool of // the same name does. // // grep [options] <pattern> [paths...] // // `-i` ignores case, `-n` puts the line number in front of each line, `-c` prints only how many // lines matched, `-v` turns the search around to select the lines that do not match, and `--help` // prints the help. The exit status follows the real tool: 0 when a line was selected, 1 when none // was, and 2 when something went wrong — a bad pattern, a file that cannot be read. // // Three packages do the work. `CommandLine` reads the options, `Regex` decides which lines match, // and `FileSystem` opens each file, which a `BufferedReader` then reads line by line. // // Given no arguments at all, as `rux run` gives it, the program searches its own source with a // few fixed command lines instead, so that a first run shows everything it can do. import Allocator::{ Allocator, SystemAllocator }; import CommandLine::{ Command, Flag, OptionSpec, Parse, Parsed, ParseProcess, PositionalSpec, Remaining, Required, WriteUsage }; import FileSystem::{ File, OpenOptions }; import Io::{ BufferedReader, ConsoleWriter, IoError, Print, PrintLine, ReadTextLine }; import Path::{ OsString, OsStringView, Path }; import Process::ArgumentCount; import Regex::{ Regex, RegexError }; import Text::{ Concat, FormatError, String, StringBuilder, StringView, TextError, TextWriter }; // How the selected lines of a file are shown. struct Show { numbers: bool; countOnly: bool; invert: bool; // Whether to put the file's name in front, which only helps when there are several files. names: bool; } // Searches one file and returns how many of its lines were selected. func SearchFile(allocator: Allocator, regex: &Regex, path: OsStringView, show: Show) -> uint ! (IoError | RegexError) { var file = File::Open(allocator, Path::FromView(path), OpenOptions::Reading())?; var reader = BufferedReader::New(allocator, file.Stream(), 0)?; var line = StringBuilder(allocator); var number: uint = 0; var selected: uint = 0; loop { // The end of the file is the one failure that is expected: it ends the loop. ReadTextLine(reader, line, 65536) catch { error if error.IsEnd() => break, error => fail error }; number += 1; if regex.IsMatch(line.View().Bytes())? != show.invert { selected += 1; if !show.countOnly { if show.names { Print("{}:", path); } if show.numbers { Print("{}:", number); } PrintLine("{}", line.View()); } } line.Clear(); } if show.countOnly { if show.names { Print("{}:", path); } PrintLine("{}", selected); } return selected; } // The pattern as typed, with `(?i)` in front when case is to be ignored. func Pattern(allocator: Allocator, parsed: &Parsed) -> String ! TextError { let typed = (parsed.Positional("pattern") ?? OsStringView()).ToText(allocator)?; if !parsed.Has("ignore-case") { return <-typed; } return Concat(allocator, StringView::FromValidated("(?i)"), typed.View()); } // Does what a parsed command line asks, and returns the exit status. func Run(allocator: Allocator, parsed: &Parsed, screen: &var TextWriter) -> int ! FormatError { if parsed.HelpRequested() { parsed.WriteHelp(screen)?; return 0; } let pattern = Pattern(allocator, parsed) catch { else => { PrintLine("grep: the pattern is not valid text"); return 2; } }; // A compiled `Regex` owns memory, so it is moved out of the match, not copied. Without the // arrow, `.Success(compiled) => compiled` is refused: // // error: move-only value 'compiled' requires an explicit '<-' in conditional-arm let regex = match Regex::New(allocator, pattern.Bytes()) { .Success(compiled) => <-compiled, .Failure(error) => { PrintLine("grep: bad pattern '{}' at byte {}", pattern, error.offset); return 2; } }; var files: uint = 0; for _ in parsed.Positionals("paths") { files += 1; } if files == 0 { PrintLine("grep: name at least one file to search"); return 2; } let show = Show { numbers: parsed.Has("line-number"), countOnly: parsed.Has("count"), invert: parsed.Has("invert-match"), names: files > 1 }; // A file that cannot be read is reported and skipped; the others are still searched. var status = 1; for path in parsed.Positionals("paths") { match SearchFile(allocator, regex, path, show) { .Success(selected) => { if selected > 0 && status == 1 { status = 0; } }, .Failure(_) => { PrintLine("grep: {}: cannot be read", path); status = 2; } } } return status; } // Splits native text at its spaces into `words`, as the CommandLine lesson did. func Split(text: OsStringView, words: var OsStringView[..]) -> uint { let units = text.Units(); var count: uint = 0; var start: uint = 0; for at in 0..=units.length { if at == units.length || units[at] as uint32 == 0x20 { if at > start && count < words.length { words[count] = OsStringView::FromUnits(units[start..at]); count += 1; } start = at + 1; } } return count; } func Main() -> int { var system = SystemAllocator(); let allocator: Allocator = system; var failure: IoError? = none; var console = ConsoleWriter(@failure); let screen: &var TextWriter = console; let options: OptionSpec[4] = [ Flag("ignore-case", 'i', "Ignore the difference between upper and lower case"), Flag("line-number", 'n', "Put each line's number in front of it"), Flag("count", 'c', "Print only how many lines were selected"), Flag("invert-match", 'v', "Select the lines that do not match") ]; let positionals: PositionalSpec[2] = [ Required("pattern", "The regular expression to look for"), Remaining("paths", "The files to search") ]; let grep = Command("grep", "Print the lines of files that match a pattern") .WithOptions(options[..]).WithPositionals(positionals[..]); // Real arguments: one search, and its status is the program's. if ArgumentCount() > 1 { let parsed = ParseProcess(@grep) catch { error => { PrintLine("grep: {}", error); WriteUsage(grep, screen) catch { else => {} }; return 2; } }; return Run(allocator, parsed, screen) catch { else => 2 }; } // No arguments: a tour of fixed command lines over this package's own files. let tour: char8[..][7] = [ "-n ^func Src/Main.rux", "-c -i regex Src/Main.rux Rux.toml", "-v -c ^\\s*// Src/Main.rux", "-n (unclosed Src/Main.rux", "-x fn Src/Main.rux", "nothing Src/Missing.rux", "--help" ]; for line in tour { PrintLine("$ grep {}", line); var holder = OsString::FromText(allocator, line) catch { else => return 2 }; var words: OsStringView[8] = [OsStringView(); 8]; let count = Split(holder.View(), words[..]); match Parse(@grep, words[..count]) { .Success(parsed) => { let status = Run(allocator, parsed, screen) catch { else => 2 }; PrintLine("(exit status {})", status); }, .Failure(error) => PrintLine("grep: {}", error) } } return 0; } ``` Besides `Io`, its `Rux.toml` lists `Allocator`, `CommandLine`, `FileSystem`, `Path`, `Process`, `Regex` and `Text` under `[Dependencies]`. ## Run it ```sh cd Examples/Projects/Grep rux run ``` ```text $ grep -n ^func Src/Main.rux 38:func SearchFile(allocator: Allocator, regex: &Regex, path: OsStringView, show: Show) 70:func Pattern(allocator: Allocator, parsed: &Parsed) -> String ! TextError { 77:func Run(allocator: Allocator, parsed: &Parsed, screen: &var TextWriter) -> int ! FormatError { 128:func Split(text: OsStringView, words: var OsStringView[..]) -> uint { 144:func Main() -> int { (exit status 0) $ grep -c -i regex Src/Main.rux Rux.toml Src/Main.rux:9 Rux.toml:1 (exit status 0) $ grep -v -c ^\s*// Src/Main.rux 171 (exit status 0) $ grep -n (unclosed Src/Main.rux grep: bad pattern '(unclosed' at byte 0 (exit status 2) $ grep -x fn Src/Main.rux grep: unknown option '-x' $ grep nothing Src/Missing.rux grep: Src/Missing.rux: cannot be read (exit status 2) $ grep --help Print the lines of files that match a pattern Usage: grep [options] <pattern> [paths...] Arguments: <pattern> The regular expression to look for [paths...] The files to search Options: -i, --ignore-case Ignore the difference between upper and lower case -n, --line-number Put each line's number in front of it -c, --count Print only how many lines were selected -v, --invert-match Select the lines that do not match -h, --help Print this help (exit status 0) ``` Pass arguments after `--` to search for real, for example `rux run -- -in "name" Rux.toml`. The tour searches the program's own source, so the line numbers and counts change whenever `Src/Main.rux` does. ## Common mistakes ::mistake **Returning a move-only value from a `match` arm.**:br A compiled `Regex` owns memory. Writing `.Success(compiled) => compiled` in the `match` that builds it is refused: ```text error: move-only value 'compiled' requires an explicit '<-' in conditional-arm ``` Move it out with `<-compiled`. :: ::mistake **Running from the wrong folder.**:br The tour's paths are relative to the current folder. `rux run` starts the program in the package's folder; run the built executable from anywhere else and every search in the tour reports that `Src/Main.rux` cannot be read. :: ::mistake **Patterns the shell rewrites.**:br`rux run -- ^func Src/*.rux` may have `*` expanded by the shell before `grep` sees it, and a pattern with spaces or `|` must be quoted. Put the pattern in quotes: `rux run -- -n "^func" Src/Main.rux`. :: ## Try it yourself 1. Run `rux run -- -i "(unclosed" Rux.toml`. The message shows the `(?i)` the program added, and a byte offset four too far. Fix both. 2. Add `-w`, which selects only whole-word matches. Hint: `\b` in a pattern matches at a word boundary. 3. With no paths at all, the real `grep` reads its standard input. Make yours do the same, with a `BufferedReader` over `StandardIn::Acquire()`. 4. Accept a directory as a path, and search every file in it with `ReadDirectory`. ## Learn more - [Command line](https://rux-lang.dev/docs/learn/command-line) — the options, the help and the errors - [Regular expressions](https://rux-lang.dev/docs/learn/regex) — the pattern syntax, flags included - [Buffered I/O](https://rux-lang.dev/docs/learn/buffered-io) — why a file is read through a buffer - [Regex API](https://rux-lang.dev/docs/api/regex) and [CommandLine API](https://rux-lang.dev/docs/api/commandline) - [Projects](https://rux-lang.dev/docs/learn/projects) — every checkpoint project in the course # Introduction Rux is a fast, compiled, strongly typed, multi-paradigm programming language. It compiles to native machine code, checks types and ownership at compile time, and keeps the cost of every construct visible in the source. The same language serves command-line tools, libraries and system code. This reference describes the language as rux 0.4.0 implements it: what each construct means, which forms are accepted, and what the compiler reports when a rule is broken. Rux is developed in the open across the [rux-lang repositories](https://github.com/rux-lang){rel=""nofollow""} and released under the [MIT license](https://github.com/rux-lang/Rux/blob/main/LICENSE.md){rel=""nofollow""}. ## Design goals | Goal | What it means in practice | | -------------- | ------------------------------------------------------------------------------------------------------------------- | | Performance | Native code, no garbage collector, no hidden allocation. A value's size and layout follow from its type. | | Safety | Strong static types, explicit conversions, explicit moves, and borrows the compiler checks. | | Clarity | Regular syntax and few implicit rules: a cast is written `as`, a move is written `<-`, a failure is written `fail`. | | Multi-paradigm | Procedural code, methods and interfaces, generics, and pattern matching over sums, optionals and fallibles. | | Tooling | One `rux` binary builds, runs, tests, formats, documents and publishes packages. | ## Hello, World ```rux import Io::PrintLine; func Main() -> int { PrintLine("Hello, World!"); return 0; } ``` `import` brings `PrintLine` from the `Io` package into scope; the package is listed under `[Dependencies]` in the project's `Rux.toml`. [`Main`](https://rux-lang.dev/docs/lang/functions/main) is the entry point of an executable, and the `int` it returns is the process exit status. `rux run` builds and runs the program. ## How this reference is organised The chapters build from the bottom up: | Part | Chapters | | -------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Text of a program | [Lexical structure](https://rux-lang.dev/docs/lang/lexical/source-files) | | Values | [Types](https://rux-lang.dev/docs/lang/types/overview), [bindings](https://rux-lang.dev/docs/lang/bindings/overview), [expressions](https://rux-lang.dev/docs/lang/expressions/overview), [statements](https://rux-lang.dev/docs/lang/statements/overview), [patterns](https://rux-lang.dev/docs/lang/patterns/match) | | Declarations | [Functions](https://rux-lang.dev/docs/lang/functions/declaration), [structs](https://rux-lang.dev/docs/lang/structs/overview), [enums](https://rux-lang.dev/docs/lang/enums/overview), [variants](https://rux-lang.dev/docs/lang/variants/overview), [unions](https://rux-lang.dev/docs/lang/unions/overview) | | Compound types | [Tuples](https://rux-lang.dev/docs/lang/tuples/overview), [arrays](https://rux-lang.dev/docs/lang/arrays/overview), [slices](https://rux-lang.dev/docs/lang/slices/overview), [ranges](https://rux-lang.dev/docs/lang/ranges/overview), [references](https://rux-lang.dev/docs/lang/references/overview), [pointers](https://rux-lang.dev/docs/lang/pointers/overview) | | Absence and failure | [Optionals](https://rux-lang.dev/docs/lang/optionals/overview), [errors](https://rux-lang.dev/docs/lang/errors/overview), [sums](https://rux-lang.dev/docs/lang/sums/overview) | | Abstraction | [Ownership](https://rux-lang.dev/docs/lang/ownership/overview), [interfaces](https://rux-lang.dev/docs/lang/interfaces/overview), [generics](https://rux-lang.dev/docs/lang/generics/overview), [modules](https://rux-lang.dev/docs/lang/modules/overview) | | Compile time and FFI | [Compile-time evaluation](https://rux-lang.dev/docs/lang/comptime/overview), [attributes](https://rux-lang.dev/docs/lang/attributes/overview), [foreign functions](https://rux-lang.dev/docs/lang/ffi/overview), [memory layout](https://rux-lang.dev/docs/lang/memory/layout) | | Appendix | [Primitive types](https://rux-lang.dev/docs/lang/appendix/primitives), [tokens](https://rux-lang.dev/docs/lang/appendix/tokens), [the RCU object format](https://rux-lang.dev/docs/lang/appendix/rcu) | ## Notation Rux code blocks hold complete Rux, or a fragment of a function body that compiles once placed in one. Comments such as `// 255` show the value an expression produces. Grammar is given in plain-text blocks with this notation: | Notation | Meaning | | ------------ | ----------------------------------------------------- | | `Rule ::= …` | Defines the rule `Rule` | | `'func'` | The exact token, written as it appears in source | | `'a'…'z'` | Any one character in the range | | `Name` | Another rule, written in PascalCase | | `A B` | `A` followed by `B` | | `A | B` | Either `A` or `B` | | `A?` | `A`, optionally | | `A*` | Zero or more `A` | | `A+` | One or more `A` | | `( … )` | Grouping | | `…` | A part described in the prose rather than spelled out | For example, a type alias is: ```text TypeAlias ::= 'pub'? 'type' Identifier '=' Type ';' ``` Error messages are quoted exactly as `rux` prints them, without the file and position prefix: `error: integer literal is out of range for type 'uint8'`. ## Reference and Learn Rux The [Learn Rux](https://rux-lang.dev/docs/learn) course teaches the language in order, one runnable lesson at a time, and explains why each feature exists. This reference is for looking things up: each page states the complete rule for one construct, lists every form and error, and links to the lesson that teaches it. Read the course to learn Rux; come here to check a detail. ## See also - [Learn Rux](https://rux-lang.dev/docs/learn) — the course, from installation to complete programs - [Hello](https://rux-lang.dev/docs/learn/hello) — the first lesson, with this program explained line by line - [Playground](https://rux-lang.dev/play) — run Rux in the browser - [Packaging](https://rux-lang.dev/docs/packaging) — manifests, dependencies and publishing - [Command-line interface](https://rux-lang.dev/docs/cli) — every `rux` command # Source Files A Rux program is written in source files with the `.rux` extension. Each file is UTF-8 text that the compiler reads as a sequence of tokens — identifiers, keywords, literals, operators and punctuation — separated by whitespace and comments. ## Files and packages The source files of a package live under its `Src/` directory, beside the `Rux.toml` manifest. An executable package starts at `Src/Main.rux`, which defines [`Main`](https://rux-lang.dev/docs/lang/functions/main); a library package conventionally starts at `Src/Lib.rux`. Files are named in PascalCase: `Main.rux`, `HttpClient.rux`, `JsonParser.rux`. ```text Hello/ ├── Rux.toml └── Src/ └── Main.rux ``` [Package layout](https://rux-lang.dev/docs/packaging/layout) describes the directory structure, and [Modules](https://rux-lang.dev/docs/lang/modules/overview) how declarations in several files and `module` blocks are named and imported. ## Encoding A source file must be valid UTF-8. Non-ASCII characters may appear inside [comments](https://rux-lang.dev/docs/lang/lexical/comments) and inside [character and string literals](https://rux-lang.dev/docs/lang/lexical/literals); everywhere else the source is ASCII. | Problem | Error | | -------------------------------------- | ------------------------------------------------ | | A byte that is not valid UTF-8 | `error: source contains invalid UTF-8 byte 0xFF` | | A byte-order mark at the start | reported as an unexpected character, U+FEFF | | A non-ASCII character outside literals | `error: unexpected character 'é' (U+00E9)` | | A control byte outside literals | `error: unexpected control byte 0x0C` | Save files as UTF-8 without a byte-order mark. ## Whitespace and line endings Whitespace is the space, the horizontal tab, the carriage return and the line feed. It separates tokens and is otherwise ignored: Rux has no significant indentation, and statements end with `;`, not with a line break. Both LF and CRLF line endings are accepted. ```rux let total = 1 + 2; let same = 1 + 2; ``` A string or character literal cannot contain a raw line break or tab; write `\n` and `\t` instead. ## Tokens The compiler reads the source from left to right and always takes the **longest** token that can start at the current position. That rule settles every spelling that could be read two ways: | Source | Read as | Not as | | -------- | --------------- | -------------- | | `x<-1` | `x` `<-` `1` | `x` `<` `-1` | | `a**p` | `a` `*` `*` `p` | a power | | `a??b` | `a` `??` `b` | `a` `?` `?b` | | `0..=9` | `0` `..=` `9` | `0` `..` `=9` | | `x>>>=2` | `x` `>>>=` `2` | `x` `>>` `>=2` | So `x<-1` is a [move assignment](https://rux-lang.dev/docs/lang/expressions/assignment) into `x`, and on an immutable `x` it fails with `error: cannot modify immutable variable 'x'`. Write `x < -1` to compare. `a**p` multiplies `a` by the value `p` points to. Whitespace matters in exactly one place: before `?`. A `?` with whitespace before it is the conditional operator, `c ? a : b`; a `?` that touches the expression before it is postfix [propagation](https://rux-lang.dev/docs/lang/optionals/propagation), `value?`. So `c? 1 : 2` is reported as `error: expected ';' after the binding declaration before '1'`. The [Token Reference](https://rux-lang.dev/docs/lang/appendix/tokens) lists every token the lexer produces. ## See also - [Comments](https://rux-lang.dev/docs/lang/lexical/comments) — the other thing the lexer skips - [Package layout](https://rux-lang.dev/docs/packaging/layout) — where `Src/` sits in a package - [Hello](https://rux-lang.dev/docs/learn/hello) — a first source file, explained # Comments A comment is text the compiler skips. Rux has two ordinary forms, for notes to the reader, and two documentation forms, which describe the declaration that follows them and feed `rux doc`, `rux lint` and editors. | Form | Kind | Extent | | ------------- | ------------------- | --------------------------- | | `// text` | Line comment | To the end of the line | | `/* text */` | Block comment | To the matching `*/`; nests | | `/// text` | Documentation line | To the end of the line | | `/** text */` | Documentation block | To the matching `*/`; nests | Comment markers inside string and character literals are ordinary characters: `"// not a comment"` is a string. ## Line comments `//` starts a comment that runs to the end of the line. It may stand on a line of its own or follow code. ```rux // The everyday kind of comment. let width = 80; // It can follow code on the same line. ``` ## Block comments `/*` starts a comment that ends at the matching `*/`. It may span lines, or sit between any two tokens. ```rux /* A block comment over several lines. */ PrintLine(/* the message */ "inline"); ``` Block comments **nest**: each `/*` inside a block needs its own `*/`. That makes it safe to comment out code that already contains a block comment. ```rux /* Temporarily disabled: /* PrintLine("nested"); */ PrintLine("still inside the outer comment"); */ ``` A block that never closes is `error: block comment is not terminated`, reported at its opening `/*`. ## Documentation comments `///` and `/** … */` are documentation comments. They attach to the declaration that follows them and describe it as Markdown. ```rux /// Returns the larger of two values. /// @param a the first value /// @param b the second value /// @returns whichever of `a` and `b` is greater func Max(a: int, b: int) -> int { return a > b ? a : b; } /** Returns the smaller of two values. @param a the first value @param b the second value @returns whichever of `a` and `b` is smaller */ func Min(a: int, b: int) -> int { return a < b ? a : b; } /// A point on a plane. struct Point { /// The horizontal coordinate. x: int; /// The vertical coordinate. y: int; } ``` The markers are exact. `////` and longer runs of slashes are ordinary line comments, and `/**/`, `/***/` or any block opened with more than two stars is an ordinary block comment, so a decorative banner never becomes documentation. ### Attachment A documentation comment attaches to the nearest following declaration when: - it starts its own line (indentation is allowed); - no blank line, ordinary comment or other token comes between it and the declaration or the declaration's first attribute. Documentation attaches to functions, types, constants, modules, fields, enum and variant cases, interface and extension methods, and extern members. Parameters and type parameters are described with tags rather than with comments inside a parameter list. Inside a function body there is no declaration to document, so a documentation comment there is an error: ```text error: documentation comment inside a block is not attached to a declaration help: write an ordinary '//' comment here; '///' documents the declaration that follows it ``` A documentation comment that is detached elsewhere — trailing code, followed by a blank line, or at the end of a scope — does not stop compilation; `rux lint` reports it. ### Content and summary The text is Markdown. A line comment loses `///` and one following space; a block comment loses its delimiter lines and common indentation. The first sentence — up to the first `.`, `!` or `?` followed by whitespace — is the summary that tools show on its own. ### Structured tags Tags form a block after the prose. Each starts a line; a continuation line is indented by two spaces after the marker. | Tag | Use | | -------------------------- | ---------------------------------------------------------- | | `@param <name> <text>` | A parameter of the documented function, other than `self` | | `@typeParam <name> <text>` | A type parameter introduced by the declaration | | `@returns <text>` | The value a function returns | | `@see <target> [text]` | A related URL, Rux path or symbol in backticks; repeatable | | `@deprecated <text>` | Marks the item as deprecated in generated documentation | Tags are case-sensitive. A misspelled or misplaced tag, such as `@return` for `@returns`, never fails compilation; `rux lint` reports it. `@deprecated` is documentation only — the [`#Warn`](https://rux-lang.dev/docs/lang/attributes/warn) attribute is what makes the compiler warn at each use. ## See also - [Source Files](https://rux-lang.dev/docs/lang/lexical/source-files) — how the lexer reads a file - [Comment](https://rux-lang.dev/docs/learn/comment) — the lesson on all three everyday forms - [Documentation](https://rux-lang.dev/docs/learn/documentation) — writing documentation a package publishes - [`rux doc`](https://rux-lang.dev/docs/cli/doc) and [`rux lint`](https://rux-lang.dev/docs/cli/lint) — the tools that read documentation comments # Identifiers An identifier names a binding, function, type, field, module or other declaration. ```text Identifier ::= IdentStart IdentContinue* IdentStart ::= 'A'…'Z' | 'a'…'z' | '_' IdentContinue ::= IdentStart | '0'…'9' ``` An identifier starts with an ASCII letter or an underscore and continues with letters, digits and underscores. It cannot be one of the 38 [keywords](https://rux-lang.dev/docs/lang/lexical/keywords). ```rux let count = 1; let x1 = 2; let _scratch = 3; let parsedValue = 4; ``` ## Rules - **ASCII only.** Letters outside ASCII are not identifier characters: `let café = 1;` stops with `error: unexpected character 'é' (U+00E9)`. Non-ASCII text belongs in [literals](https://rux-lang.dev/docs/lang/lexical/literals) and [comments](https://rux-lang.dev/docs/lang/lexical/comments). - **Case-sensitive.** `count`, `Count` and `COUNT` are three different names. - **No keywords.** A keyword in a name's place is a syntax error, such as `error: expected a pattern after the binding keyword before 'while'` for `let while = 1;`. For `none` and `fail` the message names the problem directly: `error: 'none' is a reserved keyword and cannot name a binding`. - **A lone `_` is not a name.** In a binding or pattern, `_` discards the value instead of naming it: `let _ = Compute();`. See [Destructuring](https://rux-lang.dev/docs/lang/bindings/destructuring). Primitive type names such as `int`, `bool` and `char8` are not keywords; they are predefined type names, listed in the [Primitive Types](https://rux-lang.dev/docs/lang/appendix/primitives) appendix. A few other words have a meaning only in a particular position; [Keywords](https://rux-lang.dev/docs/lang/lexical/keywords#contextual-words) lists them. ## Naming conventions Rux code uses two spellings, and `rux lint` checks them: | Spelling | Used for | Examples | | ---------- | -------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------- | | PascalCase | Types (structs, enums, variants, unions, interfaces, aliases), enum and variant cases, functions and methods, constants, modules | `HttpRequest`, `ParseInput`, `MaxSize`, `Io` | | camelCase | Local bindings, parameters, loop variables, fields, named variant fields | `userId`, `fileName`, `red` | Neither spelling uses underscores. A name that breaks the convention compiles, and `rux lint` suggests the fix: ```text warning: function name 'parse_input' should be PascalCase help: rename it to 'ParseInput' warning: local variable name 'Result' should be camelCase help: rename it to 'result' ``` The primitive types and their built-in aliases (`int`, `float64`, `byte`) are lower case by long tradition. A declaration that has to keep a foreign spelling — a C type name in a binding, say — can opt out with [`#Allow("naming.type")`](https://rux-lang.dev/docs/lang/attributes/allow) or `#Allow("naming.const")`. ## See also - [Keywords](https://rux-lang.dev/docs/lang/lexical/keywords) — the words an identifier cannot be - [Modules](https://rux-lang.dev/docs/lang/modules/overview) — qualified names such as `Io::PrintLine` - [`rux lint`](https://rux-lang.dev/docs/cli/lint) — the naming checks - [Variable](https://rux-lang.dev/docs/learn/variable) — the lesson on naming values # Keywords A keyword is a word the language reserves. Keywords are lower case and case-sensitive, and none of them can be used as an [identifier](https://rux-lang.dev/docs/lang/lexical/identifiers): `While` is an ordinary name, `while` is not. ## Reserved keywords Rux reserves 38 words: ```text as break catch const continue defer do else enum extend extern fail false for func if import in interface intrinsic is let loop match module none null pub return self struct true type union var variant when while ``` | Keyword | Introduces | | ---------------------------------------------------------------------- | ---------------------------------------------------------------------------------- | | [`as`](https://rux-lang.dev/docs/lang/expressions/casts) | A conversion, `value as T` | | [`break`](https://rux-lang.dev/docs/lang/statements/break-continue) | An exit from the nearest enclosing loop | | [`catch`](https://rux-lang.dev/docs/lang/errors/handling) | A handler for the failure of a fallible expression, `x catch { … }` | | [`const`](https://rux-lang.dev/docs/lang/bindings/constants) | A compile-time constant | | [`continue`](https://rux-lang.dev/docs/lang/statements/break-continue) | A jump to the next iteration of a loop | | [`defer`](https://rux-lang.dev/docs/lang/ownership/defer) | A statement run when the enclosing scope exits | | [`do`](https://rux-lang.dev/docs/lang/statements/loops) | A `do { … } while condition;` loop, which tests after the body | | [`else`](https://rux-lang.dev/docs/lang/statements/if) | The alternative of an `if`, the default arm of a `match`, and the `? else` mapping | | [`enum`](https://rux-lang.dev/docs/lang/enums/overview) | An enumeration of named integer values | | [`extend`](https://rux-lang.dev/docs/lang/structs/extensions) | An extension block of methods, constructors and constants for a type | | [`extern`](https://rux-lang.dev/docs/lang/ffi/overview) | A declaration of a function defined outside Rux | | [`fail`](https://rux-lang.dev/docs/lang/errors/overview) | A failure from a fallible function | | [`false`](https://rux-lang.dev/docs/lang/types/booleans) | The boolean value false | | [`for`](https://rux-lang.dev/docs/lang/statements/loops) | A loop over a range, slice, array or iterable | | [`func`](https://rux-lang.dev/docs/lang/functions/declaration) | A function, a method or a function type | | [`if`](https://rux-lang.dev/docs/lang/statements/if) | A conditional statement | | [`import`](https://rux-lang.dev/docs/lang/modules/imports) | Names brought into scope from a package or module | | [`in`](https://rux-lang.dev/docs/lang/statements/loops) | The sequence of a `for` loop, `for item in items` | | [`interface`](https://rux-lang.dev/docs/lang/interfaces/overview) | A set of methods a type can implement | | [`intrinsic`](https://rux-lang.dev/docs/lang/comptime/intrinsics) | A declaration the compiler implements: a primitive type, function or value | | [`is`](https://rux-lang.dev/docs/lang/sums/type-tests) | A type test, `value is T` | | [`let`](https://rux-lang.dev/docs/lang/bindings/overview) | An immutable binding | | [`loop`](https://rux-lang.dev/docs/lang/statements/loops) | A loop with no condition | | [`match`](https://rux-lang.dev/docs/lang/patterns/match) | A selection by pattern | | [`module`](https://rux-lang.dev/docs/lang/modules/overview) | A named module block, `module A::B { … }` | | [`none`](https://rux-lang.dev/docs/lang/optionals/overview) | The absent value of an optional | | [`null`](https://rux-lang.dev/docs/lang/pointers/overview) | The null pointer | | [`pub`](https://rux-lang.dev/docs/lang/modules/visibility) | Visibility outside the declaring package | | [`return`](https://rux-lang.dev/docs/lang/statements/return) | A return from the enclosing function | | [`self`](https://rux-lang.dev/docs/lang/structs/methods) | The receiver parameter of a method | | [`struct`](https://rux-lang.dev/docs/lang/structs/overview) | A structure type | | [`true`](https://rux-lang.dev/docs/lang/types/booleans) | The boolean value true | | [`type`](https://rux-lang.dev/docs/lang/types/aliases) | A type alias, `type Name = T;` | | [`union`](https://rux-lang.dev/docs/lang/unions/overview) | A union type, whose fields share storage | | [`var`](https://rux-lang.dev/docs/lang/bindings/overview) | A mutable binding, and writability in `&var T`, `*var T` and `var T[..]` | | [`variant`](https://rux-lang.dev/docs/lang/variants/overview) | A tagged type whose cases may carry payloads | | [`when`](https://rux-lang.dev/docs/lang/comptime/conditional) | A compile-time conditional | | [`while`](https://rux-lang.dev/docs/lang/statements/loops) | A loop that tests a condition before each iteration | `true` and `false` are lexed as boolean [literals](https://rux-lang.dev/docs/lang/lexical/literals#boolean-literals), and are reserved like the other 36. ## Contextual words These words are ordinary identifiers except in one position, where they take a fixed meaning. Outside that position they can name things, although using them as names makes code harder to read. | Word | Meaning, and where | | ---------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `asm` | Directly before `func`: a function whose body is [assembly](https://rux-lang.dev/docs/lang/ffi/assembly) | | `sizeof`, `alignof` | In an expression: the size or alignment of a type, `sizeof(T)`. An expression cannot read a binding with either name. | | `Self` | In an interface or extension: the implementing type, as in `other: &Self` | | `_` | In a binding or pattern: discards the value instead of naming it | | `Success`, `Failure`, `Some` | After a leading `.`: the native constructors and patterns `.Success(v)`, `.Failure(e)` and `.Some(v)` of [fallibles](https://rux-lang.dev/docs/lang/errors/overview) and [optionals](https://rux-lang.dev/docs/lang/optionals/overview) | Primitive type names — `int`, `uint8`, `float64`, `bool`, `char` and the rest — are not keywords either. They are predefined type names, listed in the [Primitive Types](https://rux-lang.dev/docs/lang/appendix/primitives) appendix, and so is `opaque`, the unknown pointee of an untyped pointer `*opaque`. Some words that other languages reserve mean nothing special in Rux: `mut`, `try`, `unsafe`, `use`, `impl` and `fn` are ordinary identifiers. ## See also - [Identifiers](https://rux-lang.dev/docs/lang/lexical/identifiers) — what a name may be - [Token Reference](https://rux-lang.dev/docs/lang/appendix/tokens) — every token, keywords included - [Cheat sheet](https://rux-lang.dev/docs/learn/cheatsheet) — the whole language on one page # Literals A literal is a value written directly in the source. Rux has integer, floating-point, boolean, character and string literals. | Literal | Examples | Type without a suffix or prefix | | -------------- | --------------------------------------- | ------------------------------------------------ | | Integer | `42`, `0xFF`, `0o17`, `0b1010`, `200u8` | `int`, or the type the context requires | | Floating-point | `3.14`, `1e-9`, `0.5f32` | `float64` | | Boolean | `true`, `false` | `bool` | | Character | `'A'`, `'\n'`, `c8'A'`, `c16'Ж'` | `char32`, or `char8` / `char16` from the context | | String | `"text"`, `c16"text"`, `c32"text"` | `char8[..]` | ## Integer literals ```text IntegerLiteral ::= ( Decimal | '0x' Hex | '0o' Octal | '0b' Binary ) IntegerSuffix? Decimal ::= Digit ( '_'? Digit )* ``` An integer literal is written in decimal, or in another base after a prefix. The prefix letter may be upper or lower case, and so may hexadecimal digits. ```rux let decimal = 255; let hex = 0xFF; let octal = 0o377; let binary = 0b1111_1111; let grouped = 8_100_000_000; ``` The first four are the same value, 255; the base is only how the source spells it. An underscore may separate two digits, anywhere in the number, and is ignored. It must stand between digits: `1__0` and `1_` are `error: numeric separator '_' must appear between digits`. A minus sign is not part of the literal — it is the [negation](https://rux-lang.dev/docs/lang/expressions/arithmetic) operator — but a negated literal is range-checked as one value, so `-128i8` and `-9223372036854775808` are accepted. ### Suffixes A suffix fixes the literal's type: | Suffix | Type | Suffix | Type | | ------ | -------- | ------ | --------- | | `i` | `int` | `u` | `uint` | | `i8` | `int8` | `u8` | `uint8` | | `i16` | `int16` | `u16` | `uint16` | | `i32` | `int32` | `u32` | `uint32` | | `i64` | `int64` | `u64` | `uint64` | | `i128` | `int128` | `u128` | `uint128` | | `i256` | `int256` | `u256` | `uint256` | | `i512` | `int512` | `u512` | `uint512` | ```rux let small = 200u8; let mask = 0xFFFF_0000u32; let index = 3u; let huge = 340282366920938463463374607431768211455u128; ``` A float suffix (`f8` … `f512`) on a whole number makes a floating-point literal: `1f32` is the `float32` value `1.0`. In a hexadecimal literal, `a`–`f` are digits, so a trailing `f8` or `f32` is read as more digits: `0xFFf8` is the integer 65528. A suffix after a hexadecimal number has to start with a letter that is not a hexadecimal digit, as `u8` and `i32` do. ### Type of an unsuffixed integer An integer literal without a suffix has no fixed type. It takes the type its context requires: - the declared type of the binding, field, array element, parameter or return value it initialises; - the type of the other operand of an arithmetic, bitwise or comparison operator. With no such context it is an `int`. Either way, the value must fit: ```rux let level: uint8 = 200; let raised = level + 100; // 100 is a uint8; the sum wraps to 44 let plain = 200 + 100; // both are int: 300 ``` ```text let tooBig: uint8 = 256; error: integer literal is out of range for type 'uint8' let count: uint = 3; let missing = count == -1; error: integer literal is out of range for type 'uint' ``` An integer literal never becomes a float: `let ratio: float64 = 1;` is `error: cannot assign 'int' to 'float64'`. Write `1.0`. ## Floating-point literals ```text FloatLiteral ::= Decimal '.' Decimal Exponent? FloatSuffix? | Decimal Exponent FloatSuffix? | Decimal FloatSuffix Exponent ::= ( 'e' | 'E' ) ( '+' | '-' )? Decimal ``` A floating-point literal has digits on both sides of the point, an exponent, or both. The exponent is a power of ten. ```rux let pi = 3.141592653589793; let light = 2.998e8; let charge = 1.6e-19; let half = 0.5f32; ``` `1.` and `.5` are not literals; write `1.0` and `0.5`. Underscores may separate digits in each part, as in `1_000.25`. | Suffix | Type | Suffix | Type | | ------ | --------- | ------ | ---------- | | `f8` | `float8` | `f80` | `float80` | | `f16` | `float16` | `f128` | `float128` | | `f32` | `float32` | `f256` | `float256` | | `f64` | `float64` | `f512` | `float512` | A suffixed literal is read exactly at its own width, so `0.1f128` is the `float128` nearest to one tenth rather than a `float64` widened. A value too large for the width is an infinity: `300.0f8` is `Inf`, since a `float8` holds at most 240. An unsuffixed floating-point literal is always a `float64`. It does not narrow to fit another width: `let single: float32 = 0.75;` is `error: cannot assign 'float64' to 'float32'`, `single * 2.0` is a `float64`, and with a `float16` operand `2.0` is an error. Write `0.75f32`, `2.0f32` and `2.0f16`. ## Boolean literals `true` and `false` are the two boolean literals. Their type is `bool`, which converts implicitly to the other boolean widths. ```rux let ready = true; let wide: bool32 = false; ``` ## Character literals ```text CharLiteral ::= CharPrefix? "'" ( Character | Escape ) "'" CharPrefix ::= 'c8' | 'c16' | 'c32' | 'c64' | 'c128' | 'c256' | 'c512' ``` A character literal is exactly one character, or one [escape](https://rux-lang.dev/#escape-sequences), between single quotes. A prefix, written directly against the quote, chooses the character type: | Literal | Type | Holds | | ---------- | --------- | ---------------------------------------------------------- | | `'A'` | `char32` | Any Unicode scalar value; `char8` or `char16` by context | | `c8'A'` | `char8` | One UTF-8 code unit: U+0000 to U+007F | | `c16'Ж'` | `char16` | One UTF-16 code unit that is not a surrogate: up to U+FFFF | | `c32'😀'` | `char32` | Any Unicode scalar value | | `c64'😀'` | `char64` | Any Unicode scalar value, in eight bytes | | `c128'😀'` | `char128` | Any Unicode scalar value, in 16 bytes | | `c256'😀'` | `char256` | Any Unicode scalar value, in 32 bytes | | `c512'😀'` | `char512` | Any Unicode scalar value, in 64 bytes | ```rux let letter = 'A'; let emoji = '😀'; let unit = c8'R'; let word = c16'Ж'; let smile = '\u{263A}'; ``` An unprefixed literal is a `char32`, except that it becomes a `char8` or `char16` when it initialises or is assigned to one: `let initial: char8 = 'R';` works, and so does `return 'Ж';` from a function that returns `char16`. A character that does not fit one code unit of its type is refused, never truncated: ```text let accent = c8'é'; error: character 'é' (U+00E9) does not fit one 'char8' code unit help: write a string literal such as c8"é", or a byte such as 0xE9u8 ``` | Mistake | Error | | ------------------------- | ----------------------------------------------------------------------- | | `''` | `error: character literal is empty` | | `'ab'` | `error: character literal contains more than one character` | | `'a` at the end of a line | `error: character literal is not terminated before the end of the line` | A prefix is only a prefix when the quote follows at once: `c16 'x'`, with a space, is the identifier `c16` followed by a separate literal. ## String literals ```text StringLiteral ::= StringPrefix? '"' ( Character | Escape )* '"' StringPrefix ::= 'c8' | 'c16' | 'c32' ``` A string literal is a read-only [slice](https://rux-lang.dev/docs/lang/slices/overview) of character code units — Rux has no separate string type. The prefix chooses the encoding: | Literal | Type | Encoding | | ------------ | ------------ | -------- | | `"Hello"` | `char8[..]` | UTF-8 | | `c8"Hello"` | `char8[..]` | UTF-8 | | `c16"Hello"` | `char16[..]` | UTF-16 | | `c32"Hello"` | `char32[..]` | UTF-32 | There is no `c64`, `c128`, `c256` or `c512` string: those prefixes make only characters, so `c128"x"` is the identifier `c128` followed by a string literal. ```rux let greeting = "Hello, World!"; let path = "C:\\Rux\\Bin"; let quoted = "say \"hi\""; let wide = c16"\u{1F680}"; // two UTF-16 code units ``` `.length` counts code units of the encoding, not characters: `"€".length` is 3, `c16"€".length` is 1. The stored text ends with a NUL code unit that `.length` does not count, so `.data` can be passed to C. [Text](https://rux-lang.dev/docs/lang/types/text) describes string values in full. A string literal stays on one line. A raw line break or tab inside the quotes is an error — write `\n` and `\t` — and so is a missing closing quote: | Mistake | Error | | ----------------------------------- | -------------------------------------------------------------------- | | No closing `"` before the line ends | `error: string literal is not terminated before the end of the line` | | A tab typed inside the quotes | `error: string literal contains unescaped control byte 0x09` | ## Escape sequences Character and string literals share one set of escapes: | Escape | Meaning | Code point | | ------- | ------------------------------------------------------- | ---------- | | `\n` | Line feed | U+000A | | `\r` | Carriage return | U+000D | | `\t` | Horizontal tab | U+0009 | | `\v` | Vertical tab | U+000B | | `\f` | Form feed | U+000C | | `\b` | Backspace | U+0008 | | `\a` | Alert (bell) | U+0007 | | `\0` | NUL | U+0000 | | `\\` | Backslash | U+005C | | `\'` | Single quote | U+0027 | | `\"` | Double quote | U+0022 | | `\u{…}` | The Unicode scalar value with 1 to 8 hexadecimal digits | as written | ```rux let bell = '\a'; let euro = "\u{20AC}"; let rocket = '\u{1F680}'; ``` In a string the `\u{…}` escape is encoded in the literal's encoding: `"\u{20AC}"` stores three UTF-8 bytes, `c16"\u{20AC}"` one UTF-16 unit. | Mistake | Error | | ----------------- | --------------------------------------------------------------------------- | | `"\x41"` | `error: escape sequence '\x' is not recognized` | | `"C:\Rux"` | `error: escape sequence '\R' is not recognized` | | `"\u41"` | `error: Unicode escape requires '{' after '\u'` | | `"\u{}"` | `error: Unicode escape requires at least one hexadecimal digit` | | `"\u{000000041}"` | `error: Unicode escape contains more than eight hexadecimal digits` | | `'\u{D800}'` | `error: Unicode escape U+D800 is a surrogate, not a scalar value` | | `'\u{110000}'` | `error: Unicode escape U+110000 is above the maximum scalar value U+10FFFF` | There is no `\x` escape. A single byte that is not a character is written as an integer, such as `0xE9u8`. ## Other values written as keywords `none` is the absent value of an [optional](https://rux-lang.dev/docs/lang/optionals/overview) and `null` the null [pointer](https://rux-lang.dev/docs/lang/pointers/overview). They are keywords rather than literals, and take their type from the context. Arrays (`[1, 2, 3]`), tuples (`(1, "one")`) and struct values (`Point { x: 1, y: 2 }`) are expressions built from other values; see [Arrays](https://rux-lang.dev/docs/lang/arrays/overview), [Tuples](https://rux-lang.dev/docs/lang/tuples/overview) and [Structs](https://rux-lang.dev/docs/lang/structs/overview). ## See also - [Types](https://rux-lang.dev/docs/lang/types/overview) — the types these literals produce - [Integers](https://rux-lang.dev/docs/lang/types/integers), [Floating-Point](https://rux-lang.dev/docs/lang/types/floating-point), [Characters](https://rux-lang.dev/docs/lang/types/characters), [Text](https://rux-lang.dev/docs/lang/types/text) - [Literal](https://rux-lang.dev/docs/learn/literal) — the lesson on numeric literals - [Character](https://rux-lang.dev/docs/learn/character) and [String literal](https://rux-lang.dev/docs/learn/string-literal) — the lessons on character and text literals # Operators and Punctuation Operators and punctuation are the symbol tokens of Rux. The lexer reads them by the [longest-match rule](https://rux-lang.dev/docs/lang/lexical/source-files#tokens), so `>>=` is one token, not `>>` followed by `=`. This page lists every symbol and what it means; how operators bind is in the [precedence table](https://rux-lang.dev/docs/lang/expressions/overview). ## Arithmetic | Token | Meaning | Rules | | ----- | ------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------- | | `+` | Addition | [Arithmetic](https://rux-lang.dev/docs/lang/expressions/arithmetic) | | `-` | Subtraction; prefix negation | [Arithmetic](https://rux-lang.dev/docs/lang/expressions/arithmetic) | | `*` | Multiplication; prefix dereference of a pointer; pointer type `*T` | [Arithmetic](https://rux-lang.dev/docs/lang/expressions/arithmetic), [Pointers](https://rux-lang.dev/docs/lang/pointers/overview) | | `/` | Division | [Arithmetic](https://rux-lang.dev/docs/lang/expressions/arithmetic) | | `%` | Remainder | [Arithmetic](https://rux-lang.dev/docs/lang/expressions/arithmetic) | | `++` | Increment, prefix or postfix | [Arithmetic](https://rux-lang.dev/docs/lang/expressions/arithmetic) | | `--` | Decrement, prefix or postfix | [Arithmetic](https://rux-lang.dev/docs/lang/expressions/arithmetic) | There is no unary `+` and no power operator: `a ** p` is `a * *p`, a multiplication by the value `p` points to. ## Comparison | Token | Meaning | | ----- | --------------------- | | `==` | Equal | | `!=` | Not equal | | `<` | Less than | | `<=` | Less than or equal | | `>` | Greater than | | `>=` | Greater than or equal | See [Comparison](https://rux-lang.dev/docs/lang/expressions/comparison). ## Logical | Token | Meaning | | ----- | ------------------------------------------------ | | `&&` | Logical and, short-circuiting | | `||` | Logical or, short-circuiting | | `!` | Logical not; with a type, `! E` marks a fallible | See [Logical](https://rux-lang.dev/docs/lang/expressions/logical) and, for `T ! E`, [Errors](https://rux-lang.dev/docs/lang/errors/overview). ## Bitwise and shift | Token | Meaning | | ----- | ------------------------------------------------------------------- | | `&` | Bitwise and; in a type, a reference `&T` | | `|` | Bitwise or; in a type, a sum `A | B` | | `^` | Bitwise exclusive or | | `~` | Bitwise not; before a type name in `extend`, a destructor `func ~T` | | `<<` | Shift left | | `>>` | Shift right: arithmetic for signed operands, logical for unsigned | | `>>>` | Logical shift right, filling with zeros | See [Bitwise](https://rux-lang.dev/docs/lang/expressions/bitwise), [Shift](https://rux-lang.dev/docs/lang/expressions/shift), [References](https://rux-lang.dev/docs/lang/references/overview), [Sums](https://rux-lang.dev/docs/lang/sums/overview) and [Destructors](https://rux-lang.dev/docs/lang/ownership/destructors). Prefix `&` is not an expression operator; the address of a place is taken with `@`. ## Assignment | Token | Meaning | Token | Meaning | | ----- | ---------------------------- | ------ | ------------- | | `=` | Assign | `&=` | `x = x & y` | | `<-` | Move; prefix `<-x` moves `x` | `|=` | `x = x | y` | | `+=` | `x = x + y` | `^=` | `x = x ^ y` | | `-=` | `x = x - y` | `<<=` | `x = x << y` | | `*=` | `x = x * y` | `>>=` | `x = x >> y` | | `/=` | `x = x / y` | `>>>=` | `x = x >>> y` | | `%=` | `x = x % y` | | | See [Assignment](https://rux-lang.dev/docs/lang/expressions/assignment) and [Copy and Move](https://rux-lang.dev/docs/lang/ownership/copy-and-move). ## Optionals, errors and conditions | Token | Meaning | | ----- | ---------------------------------------------------------------------------------------------------------------------------------------- | | `?` | After a type, an optional `T?`. Touching an expression, postfix propagation `x?`. With whitespace before it, the conditional `c ? a : b` | | `??` | Coalescing, `x ?? fallback`. In a type, two optional levels `T??` | `?` is the one token whose meaning depends on whitespace. `value?` propagates and `flag ? a : b` selects, so `flag? a : b` is a syntax error. `??` is always one token: two propagations in a row are written `(x?)?`. See [Conditional](https://rux-lang.dev/docs/lang/expressions/conditional), [Coalescing](https://rux-lang.dev/docs/lang/optionals/coalescing), [Optional propagation](https://rux-lang.dev/docs/lang/optionals/propagation) and [Error propagation](https://rux-lang.dev/docs/lang/errors/propagation). ## Ranges | Token | Meaning | | ----- | -------------------------------------------------------------------------------------------------- | | `..` | Half-open range `a..b`; open ranges `a..`, `..b`, `..`; a slice type `T[..]` | | `..=` | Inclusive range `a..=b`, `..=b` | | `...` | Inclusive range in expressions and patterns `a...b`; spread `args...`; a variadic parameter `T...` | See [Ranges](https://rux-lang.dev/docs/lang/ranges/overview), [Slices](https://rux-lang.dev/docs/lang/slices/overview) and [Parameters](https://rux-lang.dev/docs/lang/functions/parameters). ## Punctuation | Token | Meaning | | ------- | ------------------------------------------------------------------------------------------- | | `(` `)` | Grouping, calls, parameter lists, tuples | | `[` `]` | Array literals, indexing, array and slice types | | `{` `}` | Blocks, declaration bodies, struct literals | | `,` | Separates list items | | `;` | Ends a statement or declaration | | `:` | Separates a name from its type or field value; the conditional's `:` | | `::` | Path separator, `Io::PrintLine`, `Color::Red` | | `.` | Member access `p.x`, tuple index `t.0`, method call `s.Len()`; leading `.` in `.Success(v)` | | `->` | Return type of a function or function type | | `=>` | Separates a `match` arm's pattern from its result | | `@` | Address of a place, `@value`, giving a pointer | | `#` | Attributes `#Link(…)` and compile-time values `#target` | See [Pointers](https://rux-lang.dev/docs/lang/pointers/overview), [Attributes](https://rux-lang.dev/docs/lang/attributes/overview) and [Compile-time evaluation](https://rux-lang.dev/docs/lang/comptime/overview). ## Operators a type can define A type can give operators such as `+`, `-`, `*`, `==` and `<` a meaning of its own by declaring them in an `extend` block, and can define indexing with an indexer. `??` is built in and cannot be declared. See [Operators](https://rux-lang.dev/docs/lang/interfaces/operators) and [Indexers](https://rux-lang.dev/docs/lang/interfaces/indexers). ## See also - [Expressions](https://rux-lang.dev/docs/lang/expressions/overview) — precedence and associativity of every operator - [Token Reference](https://rux-lang.dev/docs/lang/appendix/tokens) — the lexer's name for each token - [Operators](https://rux-lang.dev/docs/learn/operators) and [Precedence](https://rux-lang.dev/docs/learn/precedence) — the lessons # Types Every value in Rux has a type, fixed at compile time. The type decides what the value can hold, how much storage it takes, and which operations apply to it. There are no implicit conversions that can change a value: the few that happen on their own only widen, and every other conversion is written with [`as`](https://rux-lang.dev/docs/lang/expressions/casts). ## Kinds of type | Kind | Examples | Described in | | ----------------- | ----------------------------------------- | ------------------------------------------------------------------------- | | Integer | `int`, `uint8`, `int512` | [Integers](https://rux-lang.dev/docs/lang/types/integers) | | Floating-point | `float64`, `float8`, `float512` | [Floating-Point](https://rux-lang.dev/docs/lang/types/floating-point) | | Boolean | `bool`, `bool32`, `bool512` | [Booleans](https://rux-lang.dev/docs/lang/types/booleans) | | Character | `char`, `char8`, `char512` | [Characters](https://rux-lang.dev/docs/lang/types/characters) | | Text | `char8[..]`, `char16[..]` | [Text](https://rux-lang.dev/docs/lang/types/text) | | Array | `int[4]`, `float64[3][3]` | [Arrays](https://rux-lang.dev/docs/lang/arrays/overview) | | Slice | `int[..]`, `var int[..]` | [Slices](https://rux-lang.dev/docs/lang/slices/overview) | | Tuple | `(int, char8[..])` | [Tuples](https://rux-lang.dev/docs/lang/tuples/overview) | | Range | `int..int`, `int..=int`, `..` | [Ranges](https://rux-lang.dev/docs/lang/ranges/overview) | | Reference | `&T`, `&var T` | [References](https://rux-lang.dev/docs/lang/references/overview) | | Pointer | `*T`, `*var T`, `*opaque` | [Pointers](https://rux-lang.dev/docs/lang/pointers/overview) | | Optional | `T?` | [Optionals](https://rux-lang.dev/docs/lang/optionals/overview) | | Fallible | `T ! E`, `! E` | [Errors](https://rux-lang.dev/docs/lang/errors/overview) | | Sum | `int | bool` | [Sums](https://rux-lang.dev/docs/lang/sums/overview) | | Function | `func(int) -> int` | [Function types](https://rux-lang.dev/docs/lang/functions/function-types) | | Struct | `struct Point { … }` | [Structs](https://rux-lang.dev/docs/lang/structs/overview) | | Enum | `enum Color { … }` | [Enums](https://rux-lang.dev/docs/lang/enums/overview) | | Variant | `variant Shape { … }` | [Variants](https://rux-lang.dev/docs/lang/variants/overview) | | Union | `union Word { … }` | [Unions](https://rux-lang.dev/docs/lang/unions/overview) | | Interface | `interface Shape { … }` | [Interfaces](https://rux-lang.dev/docs/lang/interfaces/overview) | | Generic parameter | `T` in `func First<T>(items: T[..]) -> T` | [Generics](https://rux-lang.dev/docs/lang/generics/overview) | The integer, floating-point, boolean and character types are the **primitive** types. Their names are predefined, not keywords, and the [Primitive Types](https://rux-lang.dev/docs/lang/appendix/primitives) appendix lists all of them, with sizes. Text is not a separate type: a string is a slice of characters. Two more types have no family of their own: `opaque`, the unknown pointee of an untyped pointer `*opaque`, and `()`, the unit type of a function that returns nothing. ## Type expressions ```text Type ::= SumType ( '!' SumType )? | '!' SumType SumType ::= RangeType ( '|' RangeType )* RangeType ::= PostfixType ( ( '..' | '..=' ) PostfixType? )? | ( '..' | '..=' ) PostfixType? | 'var' PostfixType PostfixType ::= PrimaryType ( '?' | '[' ']' | '[' Expression ']' | '[' '..' ']' )* PrimaryType ::= Path TypeArguments? | '*' 'var'? PostfixType | '&' 'var'? PostfixType | 'func' '(' … ')' ( '->' Type )? | '(' Type ( ',' Type )* ')' | '(' ')' ``` The forms bind in this order, tightest first: 1. **Postfix suffixes**, applied left to right: `?` optional, `[N]` array, `[..]` slice, and `[]`, the flexible array tail a struct's last field may have (see [Memory Layout](https://rux-lang.dev/docs/lang/memory/layout)). 2. **Range** bounds `T..T`, `T..=T`, and the `var` of a writable slice `var T[..]`. 3. **Sum** `A | B`. 4. **Fallible** `T ! E` — one `!` per type; a leading `! E` is a fallible with no success value. The pointer and reference forms take a postfix type, so `*int?` is a pointer to an optional, `*(int?)`. | Written | Means | | --------------- | ----------------------------------------------- | | `int32?[..]` | A slice of optional `int32` | | `int32[..]?` | An optional slice of `int32` | | `int[3][2]` | An array of 2 elements, each an `int[3]` | | `int??` | An optional of an optional `int` | | `A | B ! E | F` | `(A | B) ! (E | F)` | | `T ! (E?)` | A fallible whose error is an optional — grouped | | `A | (B?)` | A sum with an optional member — grouped | An optional member of a sum and an optional error of a fallible must be written in parentheses, since `A | B?` could mean either `A | (B?)` or `(A | B)?`. Ungrouped, they are `error: an optional sum member must be grouped` and `error: an optional error type must be grouped`. ```rux variant ParseError { Empty, Bad(char8) } func Double(x: int) -> int { return x * 2; } func Check(text: char8[..]) -> ! ParseError { if text.length == 0 { fail ParseError::Empty; } } func Main() -> int { let grid: int[3][2] = [[1, 2, 3], [4, 5, 6]]; let pair: (int, char8[..]) = (1, "one"); let span: int..int = 0..10; let maybe: int? = none; let either: int | bool = 7; let op: func(int) -> int = Double; var storage: int[4] = [1, 2, 3, 4]; let view: var int[..] = storage[..]; let address: *int = @grid[0][0]; let pointerToOptional: *int? = null; view[0] = 10; return grid[1][2] + op(pair.0); // 6 + 2 } ``` ## Type identity Two type expressions denote the same type when they are spelled the same after [aliases](https://rux-lang.dev/docs/lang/types/aliases) are resolved. A `type` alias is another name for its target, never a new type. Each `struct`, `enum`, `variant`, `union` and `interface` declaration, on the other hand, introduces a type distinct from every other, even one with identical fields. A generic type is a different type for each set of type arguments: `Box<int>` and `Box<bool>` are unrelated. `int` and `int64` are distinct types — a function can be overloaded on them — that convert to each other implicitly, because `int` is 64 bits wide on every supported target. The same holds for `uint` and `uint64`. ## Implicit conversions A value converts to another type without `as` only when no value can change: | From | To | Example | | ------------------------------- | --------------------------------------- | --------------------------------------------------------------------------------------------------------------------------- | | An integer | A wider integer of the same signedness | `int8` → `int32`, `uint32` → `uint` | | `int` / `uint` | `int64` / `uint64`, and back | | | `float32` | `float64` | | | `char32` … `char256` | A wider character, up to `char512` | `char32` → `char64`, `char64` → `char512` | | Any boolean width | Any other boolean width | `bool` → `bool32` | | `T[N]` | `T[..]` | An array viewed as a slice | | `var T[..]`, `*var T`, `&var T` | `T[..]`, `*T`, `&T` | Dropping write access | | Any pointer | `*opaque` | | | `T` | `T?`, or a sum that has `T` as a member | See [Optionals](https://rux-lang.dev/docs/lang/optionals/overview) and [Sums](https://rux-lang.dev/docs/lang/sums/overview) | Everything else needs [`as`](https://rux-lang.dev/docs/lang/expressions/casts): narrowing, changing signedness, crossing between integers, floats, characters and booleans, and every conversion between floating-point widths other than `float32` to `float64`. Each family page lists its conversions. Unsuffixed integer literals are the one flexible case: they take the type their context needs, as [Literals](https://rux-lang.dev/docs/lang/lexical/literals#type-of-an-unsuffixed-integer) describes. Two integer operands of one signedness meet at the wider type, as an assignment would widen the narrower one. Operands of different signedness have no common type: ```text let u: uint64 = 3; let s: int64 = -5; let mixed = u + s; error: operator '+' cannot combine left operand 'uint64' with right operand 'int64' ``` A result that is wider than its destination is not narrowed back: with `small: int32` and `big: int64`, `let t: int32 = small + big;` is `error: cannot assign 'int64' to 'int32'`. ## Size and alignment `sizeof(T)` and `alignof(T)` give a type's storage size and alignment in bytes, as `uint` values computed at compile time. Every primitive's size is fixed by its name — `int` and `uint` are 8 bytes on every supported target — and [Memory Layout](https://rux-lang.dev/docs/lang/memory/layout) describes how compound types are laid out. ## See also - [Primitive Types](https://rux-lang.dev/docs/lang/appendix/primitives) — every primitive in one table - [Casts](https://rux-lang.dev/docs/lang/expressions/casts) — `as` and `is` - [Types](https://rux-lang.dev/docs/learn/types) — the Learn part on building your own types - [Convert](https://rux-lang.dev/docs/learn/convert) — the lesson on conversions # Integers An integer type holds a whole number in a fixed number of bits. The signed types `int8` to `int512` use two's complement; the unsigned types `uint8` to `uint512` hold zero and up. `int` and `uint` are as wide as a pointer. ## The integer types | Type | Bits | Bytes | Min | Max | Suffix | | --------- | ---- | ----- | --------------------- | ----------------------- | ------ | | `int8` | 8 | 1 | −128 | 127 | `i8` | | `int16` | 16 | 2 | −32,768 | 32,767 | `i16` | | `int32` | 32 | 4 | −2,147,483,648 | 2,147,483,647 | `i32` | | `int64` | 64 | 8 | −263 ≈ −9.22 × 1018 | 263 − 1 | `i64` | | `int128` | 128 | 16 | −2127 ≈ −1.70 × 1038 | 2127 − 1 | `i128` | | `int256` | 256 | 32 | −2255 ≈ −5.79 × 1076 | 2255 − 1 | `i256` | | `int512` | 512 | 64 | −2511 ≈ −6.70 × 10153 | 2511 − 1 | `i512` | | `int` | 64 | 8 | as `int64` | as `int64` | `i` | | `uint8` | 8 | 1 | 0 | 255 | `u8` | | `uint16` | 16 | 2 | 0 | 65,535 | `u16` | | `uint32` | 32 | 4 | 0 | 4,294,967,295 | `u32` | | `uint64` | 64 | 8 | 0 | 264 − 1 ≈ 1.84 × 1019 | `u64` | | `uint128` | 128 | 16 | 0 | 2128 − 1 ≈ 3.40 × 1038 | `u128` | | `uint256` | 256 | 32 | 0 | 2256 − 1 ≈ 1.16 × 1077 | `u256` | | `uint512` | 512 | 64 | 0 | 2512 − 1 ≈ 1.34 × 10154 | `u512` | | `uint` | 64 | 8 | 0 | as `uint64` | `u` | `byte` is a built-in [alias](https://rux-lang.dev/docs/lang/types/aliases#built-in-aliases) of `uint8`, for values that are raw storage rather than numbers. `int` and `uint` are pointer-sized: their width follows the target, and it is 64 bits on every target rux 0.4.0 supports. `int` is the type of an unsuffixed integer literal and of `Main`'s exit status; `uint` is the type of lengths, indices and `sizeof`. When a value must keep a width across targets — a file format, a protocol, a C structure — name a fixed-width type. The 128-, 256- and 512-bit types are ordinary integers: they support every operator and conversion below. ## Associated constants Every integer type has four constants. They are declared in an extension in the standard `Core` package, so the extension has to be imported from it, by the type's name, and `Core` listed under `[Dependencies]`: | Constant | Type | Value | | -------- | -------- | --------------------- | | `Bits` | `uint` | Width in bits | | `Bytes` | `uint` | Storage size in bytes | | `Min` | the type | Smallest value | | `Max` | the type | Largest value | ```rux import Core::{ int, int8, uint64 }; import Io::PrintLine; func Main() -> int { PrintLine("int8 {} to {}", int8::Min, int8::Max); // -128 to 127 PrintLine("uint64 max {}", uint64::Max); // 18446744073709551615 PrintLine("int {} bits", int::Bits); // 64 return 0; } ``` Without the import, the constant is not found: `error: 'Max' not found in extend for type 'int8'`. An alias carries the constants of its target, so `byte::Max` is 255 once `byte` (or `uint8`) is imported. ## Literals Integer literals are decimal, hexadecimal (`0x`), octal (`0o`) or binary (`0b`), with `_` between digits, and an optional suffix from the table above. An unsuffixed literal takes the type its context requires — the declared type it initialises, or the other operand's type — and is an `int` otherwise. It must fit that type: ```rux let level: uint8 = 200; let raised = level + 100; // 100 is a uint8 let mask = 0xFF00u16; ``` `let tooBig: uint8 = 256;` is `error: integer literal is out of range for type 'uint8'`. [Literals](https://rux-lang.dev/docs/lang/lexical/literals#integer-literals) gives the full spelling rules. ## Operations | Operators | Result | Rules | | --------------------------------- | ----------------------- | ------------------------------------------------------------- | | `+` `-` `*` | The operand type | Wrap around modulo 2bits | | `/` `%` | The operand type | Truncate toward zero; panic on a zero divisor | | prefix `-` | The operand type | Wraps; on an unsigned type, gives 2bits − x | | `&` `|` `^` `~` | The operand type | Bitwise | | `<<` `>>` `>>>` | The left operand's type | See [Shift](https://rux-lang.dev/docs/lang/expressions/shift) | | `==` `!=` `<` `<=` `>` `>=` | `bool` | Numeric order | | `++` `--` and compound assignment | — | As the operator they stand for | ### Wrapping `+`, `-` and `*` wrap: a result that does not fit keeps its low bits, in every build profile. ```rux var level: uint8 = 250; level += 10; // 4 var small: int8 = 127; small += 1; // -128 ``` When overflow must be detected, use the `Core` functions `AddChecked`, `SubChecked` and `MulChecked`, which report it, or `AddSaturating` and its siblings, which stop at the limits: ```rux import Core::{ AddChecked, AddSaturating }; import Io::PrintLine; func Main() -> int { let level: uint8 = 250; var sum: uint8 = 0; if AddChecked(level, 10u8, @sum) { PrintLine("overflow; wrapped to {}", sum); // 4 } PrintLine("saturated: {}", AddSaturating(level, 10u8)); // 255 return 0; } ``` ### Division `/` truncates toward zero and `%` takes the sign of the dividend: `-7 / 2` is `-3`, and `-7 % 2` is `-1`. A zero divisor stops the program with a panic, on every target and in every build profile. So does the one signed quotient that does not fit, a type's `Min` divided by `-1`, and the matching `%`: ```text Panic: division by zero at Divide (Src/Main.rux:5:14) Panic: division overflow at Main (Src/Main.rux:16:23) ``` ### Mixed operands Two operands of the same signedness meet at the wider type: an `int32` plus an `int64` is an `int64`. Operands of different signedness are an error, since either conversion could change a value — convert one with `as` to choose: ```text error: operator '+' cannot combine left operand 'uint64' with right operand 'int64' error: operator '<' cannot compare left operand 'uint64' with right operand 'int64' ``` ## Conversions An integer widens implicitly to a wider integer of the **same** signedness, and `int` and `int64` (likewise `uint` and `uint64`) convert to each other freely. Everything else is written with `as`: | Conversion | Result | | --------------------------- | ----------------------------------------------------------------------------------------------------------- | | To a narrower integer | Keeps the low bits: `300 as int8` is 44 | | Between signed and unsigned | Keeps the bit pattern: `-1 as uint8` is 255 | | To a wider integer | Sign-extends a signed value: `(-1i32) as uint64` is 264 − 1 | | To a floating-point type | The nearest representable value | | To a boolean type | `false` for zero, `true` for anything else | | To a character type | The character with that code; see [Characters](https://rux-lang.dev/docs/lang/types/characters#conversions) | ```rux let big: int32 = 300; let narrowed = big as int8; // 44 let negative: int32 = -1; let unsigned = negative as uint8; // 255 let ratio = 7 as float64 / 2.0; // 3.5 let flag = 256 as bool; // true ``` A narrowing `as` never fails; it produces a different value. To find out whether a value fits first, compare it with the target's `Min` and `Max`, or call `Core::ConvertChecked`, which returns `true` when the conversion lost the value. Implicit widening refuses what it cannot do losslessly: `let d: int16 = c;` for a `uint8` `c` is `error: cannot assign 'uint8' to 'int16'`, and `let i: int32 = n;` for an `int` `n` is `error: cannot assign 'int' to 'int32'`. ## See also - [Floating-Point](https://rux-lang.dev/docs/lang/types/floating-point) — the other numeric family - [Arithmetic](https://rux-lang.dev/docs/lang/expressions/arithmetic), [Bitwise](https://rux-lang.dev/docs/lang/expressions/bitwise), [Shift](https://rux-lang.dev/docs/lang/expressions/shift) — the operators in full - [Casts](https://rux-lang.dev/docs/lang/expressions/casts) — `as` for every type - [Integer](https://rux-lang.dev/docs/learn/integer), [Number limit](https://rux-lang.dev/docs/learn/number-limit), [Wide integer](https://rux-lang.dev/docs/learn/wide-integer) — lessons - [Wrapping arithmetic](https://rux-lang.dev/docs/learn/wrapping-arithmetic), [Checked arithmetic](https://rux-lang.dev/docs/learn/checked-arithmetic), [Checked convert](https://rux-lang.dev/docs/learn/checked-convert) — lessons on overflow # Floating-Point A floating-point type holds a binary fraction with an exponent, covering a vast range at a fixed number of significant digits. Rux has eight widths: the two IEEE 754 formats every supported machine computes in hardware, `float32` and `float64`, and six more that the compiler computes itself. ## The floating-point types | Type | Bits | Bytes | Format | Significant digits | Largest finite value | Suffix | | ---------- | ---- | ----- | --------------------------------- | ------------------ | -------------------- | ------ | | `float8` | 8 | 1 | E4M3: 4 exponent, 3 fraction bits | about 1 | 240 | `f8` | | `float16` | 16 | 2 | IEEE 754 binary16 | about 3 | 65,504 | `f16` | | `float32` | 32 | 4 | IEEE 754 binary32 | about 7 | ≈ 3.40 × 1038 | `f32` | | `float64` | 64 | 8 | IEEE 754 binary64 | about 16 | ≈ 1.80 × 10308 | `f64` | | `float80` | 80 | 16 | x87 extended precision | about 19 | ≈ 1.19 × 104932 | `f80` | | `float128` | 128 | 16 | IEEE 754 binary128 | about 34 | ≈ 1.19 × 104932 | `f128` | | `float256` | 256 | 32 | IEEE 754 binary256 | about 71 | ≈ 1.61 × 1078913 | `f256` | | `float512` | 512 | 64 | binary512: 23 exponent bits | about 147 | ≈ 2.07 × 101262611 | `f512` | `float` is a built-in [alias](https://rux-lang.dev/docs/lang/types/aliases#built-in-aliases) of `float64`, and `float64` is the type of an unsuffixed floating-point literal. Use `float64` by default, and `float32` where storage or bandwidth matters more than precision, such as large arrays of samples. The other widths are for data that arrives in their format and for precision beyond `float64`. They cost more: the compiler [computes them](https://rux-lang.dev/#how-each-width-is-computed) with integer instructions rather than the machine's floating-point unit. - `float8` is the E4M3 format: one sign bit, four exponent bits with a bias of 7, and three fraction bits. It keeps IEEE-style infinities and NaNs in the all-ones exponent, so its largest finite value is 240. - `float80` is the x87 extended format: a 64-bit significand with its integer bit stored, and a 15-bit exponent. Its 80 bits of value are held in 16 bytes, so `float80::Bits` is 80 while `float80::Bytes` and `sizeof(float80)` are 16. - `float512` continues the IEEE 754 pattern past binary256, with a 23-bit exponent and 489 bits of precision. ## Associated constants Imported from `Core` like the [integer constants](https://rux-lang.dev/docs/lang/types/integers#associated-constants), every width has the same eight: | Constant | Meaning | | ------------- | ------------------------------------------- | | `Bits` | Width of the value in bits (`uint`) | | `Bytes` | Storage size in bytes (`uint`) | | `Max` | Largest finite value | | `Lowest` | Most negative finite value, `-Max` | | `MinPositive` | Smallest positive normal value | | `Epsilon` | Gap between 1.0 and the next value up | | `Infinity` | Positive infinity, which prints as `Inf` | | `NaN` | A quiet not-a-number, which prints as `NaN` | | Type | `Max` | `MinPositive` | `Epsilon` | | ---------- | ----------------------- | ----------------------------- | --------------------- | | `float8` | 240 | 2−6 = 0.015625 | 2−3 = 0.125 | | `float16` | 65,504 | 2−14 ≈ 6.10 × 10−5 | 2−10 ≈ 9.77 × 10−4 | | `float32` | 3.4028235e+38 | 1.1754944e-38 | 1.1920929e-07 | | `float64` | 1.7976931348623157e+308 | 2.2250738585072014e-308 | 2.220446049250313e-16 | | `float80` | ≈ 1.19 × 104932 | 2−16382 ≈ 3.36 × 10−4932 | 2−63 ≈ 1.08 × 10−19 | | `float128` | ≈ 1.19 × 104932 | 2−16382 ≈ 3.36 × 10−4932 | 2−112 ≈ 1.93 × 10−34 | | `float256` | ≈ 1.61 × 1078913 | 2−262142 ≈ 2.48 × 10−78913 | 2−236 ≈ 9.06 × 10−72 | | `float512` | ≈ 2.07 × 101262611 | 2−4194302 ≈ 1.94 × 10−1262611 | 2−488 ≈ 1.25 × 10−147 | `Core` writes the limits of `float8` through `float64` as literals. `Infinity` and `NaN` at every width, and every limit of `float80` and wider, are [intrinsic constants](https://rux-lang.dev/docs/lang/comptime/intrinsics#constants) whose values the compiler takes from the format itself. ```rux import Core::{ float16, float64 }; import Io::PrintLine; func Main() -> int { PrintLine("{} {}", float64::Max, float64::Epsilon); PrintLine("{} {}", float64::Infinity, -float64::Infinity); // Inf -Inf PrintLine("{} {}", float16::Max, float16::Epsilon); // 65500.0 0.000977 return 0; } ``` `float16::Max` prints as `65500.0` because `{}` writes the shortest decimal that reads back as the same value *at its own width*, and no other `float16` is nearer to 65,500 than 65,504 is. ### Printing the wide widths `float8` through `float64` implement `Display` and `Debug`, so `{}` prints them. `float80` and wider do not: the exact arithmetic that finds their digits allocates, and those protocols offer nowhere to pass an allocator. `PrintLine("{}", 1.0f80)` is therefore an error: ```text error: no matching overload for 'PrintLine' with argument types (char8[..], float80) ``` Render one through the `Format` package's [`Float80` to `Float512`](https://rux-lang.dev/docs/api/format/float128) values instead, which take the allocator explicitly: ```rux import Allocator::{ Allocator, SystemAllocator }; import Core::{ Succeeded, float128 }; import Format::{ ByteCursor, Float128 }; import Io::PrintLine; import Text::{ FormatSpec, TextWriter }; func Main() -> int { let third = 1.0f128 / 3.0f128; var system = SystemAllocator(); let allocator: Allocator = system; var storage: char8[64]; var cursor = ByteCursor(storage[..]); let writer: &var TextWriter = cursor; if !Succeeded(Float128::FromValue(third).FormatWith(allocator, writer, FormatSpec::Plain())) { return 1; } PrintLine("{}", cursor.Written()); // 0.3333333333333333333333333333333333 return 0; } ``` ## Literals A floating-point literal has digits on both sides of a point, an exponent, or a float suffix: `3.14`, `2.998e8`, `1.6e-19`, `0.5f32`, `1f16`. A suffixed literal is read exactly at its own width: `0.1f128` is the `float128` nearest to one tenth, not a `float64` widened. Without a suffix a literal is a `float64`, whatever the context: ```text let single: float32 = 0.75; error: cannot assign 'float64' to 'float32' ``` Write `0.75f32`. A literal too large for its width is an infinity: `300.0f8` is `Inf`. [Literals](https://rux-lang.dev/docs/lang/lexical/literals#floating-point-literals) gives the full grammar and every suffix. ## Operations | Operators | Result | Rules | | --------------------------- | ---------------- | --------------------------------------------------- | | `+` `-` `*` `/` | The operand type | IEEE 754, rounded to nearest with ties to even | | `%` | The operand type | Remainder of truncated division: `7.5 % 2.0` is 1.5 | | prefix `-` | The operand type | Flips the sign, including of zero and infinity | | `==` `!=` `<` `<=` `>` `>=` | `bool` | IEEE 754 comparison | At every width, `%` is the exact remainder of truncating division, with the dividend's sign, as C's `fmod` computes it. Its non-NaN result agrees bit for bit with constant folding on every target, including large quotients. On x86-64, `float32` and `float64` remainder use x87 `fprem`; on AArch64 they use compiler-generated helpers. Floating-point arithmetic never panics, at any width. Results follow IEEE 754: | Expression | Result | | ------------ | ------ | | `1.0 / 0.0` | `Inf` | | `-1.0 / 0.0` | `-Inf` | | `0.0 / 0.0` | `NaN` | A NaN is unordered: every comparison with it is `false` except `!=`, so `x != x` is `true` exactly when `x` is a NaN. The `Core` functions `IsNaN`, `IsInfinite`, `IsFinite`, `IsZero` and `IsNegativeZero` test for special values at every width. The bitwise and shift operators do not apply to floats: `a & 1.0` is `error: operator '&' requires an integer, bool, or character left operand, but found 'float64'`. Most decimal fractions have no exact binary form, so arithmetic on them rounds: `0.1 + 0.2 == 0.3` is `false`. Compare against a tolerance, or count in integer units such as cents. ### Mixed widths A `float32` operand meets a `float64` operand at `float64`. No other two widths mix: with `half: float16` and `single: float32`, `half + single` is `error: operator '+' cannot combine left operand 'float16' with right operand 'float32'`. Convert one operand with `as`. Because an unsuffixed literal is a `float64`, `single * 2.0` is a `float64`, and `half * 2.0` is an error. Write `single * 2.0f32` to stay in `float32`, and `half * 2.0f16`. ## How each width is computed `float32` and `float64` use the machine's floating-point instructions. Every other width is computed by helper functions the compiler synthesizes from integer operations while it lowers the program. They are named `__rux_float_f<bits>_<operation>`, generated only for the operations a program uses, and private to it. They depend on no package, `Core` included, so arithmetic at every width works in a program with no dependencies. `float80` on x86-64 is the exception, because the x87 unit computes in exactly that format. `+`, `-`, `*`, `/`, `%`, the comparisons, conversion between `float80` and `float32` or `float64`, and conversion from a signed integer of at most 64 bits run on x87. Around each of these that rounds, the compiler sets the x87 control word to 64-bit precision with round-to-nearest and restores the caller's word afterwards, since Windows leaves the unit at 53-bit precision. `--emit asm` shows this code. Every other `float80` conversion goes through the helpers, as all of `float80` does on AArch64. For `float8`, `float16` and `float80` through `float512`, every result that is not a NaN is **bit-identical on every target**, and identical to what the compiler computes when it folds the same expression while compiling. A NaN result is only guaranteed to be a NaN: its sign and payload may differ between targets, and between folding and running. A program that needs a NaN writes `T::NaN`, and tests for one with `x != x` or `IsNaN`, never by its bits. ## Conversions `float32` converts to `float64` implicitly; every `float32` value is exactly a `float64` value. That is the only implicit conversion between floating-point widths. Every other one, and every conversion between a float and another type, is written with `as`: | Conversion | Result | | ---------------------- | ----------------------------------------------------------------------------------- | | To another float width | Rounded to nearest with ties to even; a value beyond its range becomes an infinity | | To an integer type | Truncated toward zero; beyond the range, saturated at `Min` or `Max`; NaN becomes 0 | | From an integer type | The nearest representable value | | To a boolean type | `false` for a zero of either sign; `true` for anything else, NaN included | ```rux let ratio = 3.9; let whole = ratio as int32; // 3 let down = -3.9 as int32; // -3 let capped = 1e10 as int32; // 2147483647 let floor = -1.0 as uint8; // 0 let single = 3.141592653589793 as float32; // 3.1415927 let back = 7 as float64; // 7.0 let tenth = 0.1 as float16; // 0.1, stored as 0.0999755859375 let zero = -0.0f16 as bool; // false ``` Float-to-integer conversion is the same for every float width and every integer width, on every target, and whether it runs or is folded at compile time. It never wraps: `1e20 as int32` is `int32::Max`, not its low bits, and `float512::Infinity as int512` is `int512::Max`. Round first, with the `Math` package, when rounding rather than truncation is meant. ## The C boundary C's `float` and `double` are `float32` and `float64`, and they are the only floating-point widths the C calling convention knows. The others are passed by the compiler's own convention, which matches no C type — not `_Float16`, `long double` or `__float128` — so one of them in an `extern` or `#Abi` signature, or as a C-variadic argument, is an error. See [Foreign Function Interface](https://rux-lang.dev/docs/lang/ffi/overview#floating-point-widths). ## See also - [Integers](https://rux-lang.dev/docs/lang/types/integers) — the other numeric family - [Arithmetic](https://rux-lang.dev/docs/lang/expressions/arithmetic) and [Casts](https://rux-lang.dev/docs/lang/expressions/casts) - [Intrinsics](https://rux-lang.dev/docs/lang/comptime/intrinsics) — the compiler-supplied constants - API: [Core floating-point types](https://rux-lang.dev/docs/api/core/floating-point), [`Float128`](https://rux-lang.dev/docs/api/format/float128) - [Float](https://rux-lang.dev/docs/learn/float) and [Float special](https://rux-lang.dev/docs/learn/float-special) — lessons on precision, infinities and NaN - [Math](https://rux-lang.dev/docs/learn/math) — rounding, powers and roots # Booleans A boolean holds one of two values, `true` or `false`. Comparisons produce booleans, and `if`, `while` and the logical operators consume them. ## The boolean types | Type | Bits | Bytes | Values | | --------- | ---- | ----- | --------------- | | `bool8` | 8 | 1 | `false`, `true` | | `bool16` | 16 | 2 | `false`, `true` | | `bool32` | 32 | 4 | `false`, `true` | | `bool64` | 64 | 8 | `false`, `true` | | `bool128` | 128 | 16 | `false`, `true` | | `bool256` | 256 | 32 | `false`, `true` | | `bool512` | 512 | 64 | `false`, `true` | `bool` is a built-in [alias](https://rux-lang.dev/docs/lang/types/aliases#built-in-aliases) of `bool8`, and the everyday spelling. The wider types hold the same two values in more storage; they exist to match the layout of foreign code, such as the four-byte `BOOL` of the Windows API, which is a `bool32` in Rux. A compiler message names the canonical type, so a mistake with a `bool` usually reports `bool8`; the message for a condition spells it `bool` on both sides, as in `condition for 'if' must have type 'bool', but found 'bool ! RegexError'`. ## Associated constants Imported from `Core`, each boolean type has `Bits` and `Bytes` (both `uint`): `bool32::Bits` is 32 and `bool32::Bytes` is 4; `bool512::Bytes` is 64. ## Literals `true` and `false` are the only boolean literals. Both are keywords, and their type is `bool`. ```rux let ready = true; let finished: bool = false; let wide: bool32 = ready; ``` ## Operations | Operator | Meaning | | ------------------ | ------------------------------------------------------- | | `!a` | Not | | `a && b` | And; `b` is evaluated only when `a` is `true` | | `a || b` | Or; `b` is evaluated only when `a` is `false` | | `a & b` | And, always evaluating both operands | | `a | b` | Or, always evaluating both operands | | `a ^ b` | Exclusive or: `true` when exactly one operand is `true` | | `a == b`, `a != b` | Equality | ```rux let a = true; let b = false; let both = a && b; // false let either = a || b; // true let differ = a ^ b; // true ``` `&&` binds more tightly than `||`, so `a || b && c` is `a || (b && c)`. See [Logical](https://rux-lang.dev/docs/lang/expressions/logical) for short-circuiting and [Expressions](https://rux-lang.dev/docs/lang/expressions/overview) for precedence. ### Conditions A condition must be a boolean. A number is not treated as one: ```text if 1 { … } error: condition for 'if' must have type 'bool', but found 'int' let flag = !5; error: operator '!' requires a bool operand, but found 'int' ``` Write the comparison you mean, `count != 0`. Comparing a boolean with a literal, `ready == true`, is legal but says nothing `ready` does not. ## Conversions Every boolean width converts implicitly to every other, since all of them hold the same two values: ```rux let flag: bool = true; let wide: bool32 = flag; let back: bool = wide; ``` Between booleans and other types, conversion is written with `as`: | Conversion | Result | | ---------------------------------------- | ------------------------------------------ | | Boolean to an integer or float | `1` for `true`, `0` for `false` | | Integer, float or character to a boolean | `false` for zero, `true` for anything else | ```rux let one = true as int; // 1 let zero = false as uint8; // 0 let set = 256 as bool; // true let some = 0.5 as bool; // true ``` A cast to a boolean tests the whole value for zero; it does not keep low bits. `256 as bool` is `true` even though the low byte of 256 is zero, and the result reads back as exactly 1. Without `as`, a number is never a boolean: `let on: bool = 1;` is `error: cannot assign 'int' to 'bool8'`, and `let n: int = true;` is `error: cannot assign 'bool8' to 'int'`. ## See also - [Logical](https://rux-lang.dev/docs/lang/expressions/logical) and [Comparison](https://rux-lang.dev/docs/lang/expressions/comparison) — the operators that make and use booleans - [if](https://rux-lang.dev/docs/lang/statements/if) and [Loops](https://rux-lang.dev/docs/lang/statements/loops) — where conditions appear - [Boolean](https://rux-lang.dev/docs/learn/boolean) and [Logical](https://rux-lang.dev/docs/learn/logical) — lessons # Characters A character type holds one unit of text. Rux distinguishes two kinds, and the difference decides which values are valid: - A **code unit** is one piece of an encoding. `char8` is one byte of UTF-8 and `char16` one 16-bit unit of UTF-16. Every value that fits the width is a valid code unit, but a code unit is a whole character only when the character is small enough to be encoded in one. - A **scalar value** is one Unicode character: a code point from U+0000 to U+10FFFF, excluding the surrogates U+D800 to U+DFFF. `char32`, `char64`, `char128`, `char256` and `char512` hold scalar values — the same ones at every width. ## The character types | Type | Bits | Bytes | Holds | Range | Literal prefix | | --------- | ---- | ----- | ---------------------- | -------------------------------------- | -------------- | | `char8` | 8 | 1 | A UTF-8 code unit | 0 to 255 | `c8` | | `char16` | 16 | 2 | A UTF-16 code unit | 0 to 65,535 | `c16` | | `char32` | 32 | 4 | A Unicode scalar value | U+0000 to U+10FFFF, without surrogates | `c32`, or none | | `char64` | 64 | 8 | A Unicode scalar value | U+0000 to U+10FFFF, without surrogates | `c64` | | `char128` | 128 | 16 | A Unicode scalar value | U+0000 to U+10FFFF, without surrogates | `c128` | | `char256` | 256 | 32 | A Unicode scalar value | U+0000 to U+10FFFF, without surrogates | `c256` | | `char512` | 512 | 64 | A Unicode scalar value | U+0000 to U+10FFFF, without surrogates | `c512` | `char` is a built-in [alias](https://rux-lang.dev/docs/lang/types/aliases#built-in-aliases) of `char32`, and the type of an unprefixed character literal. Use `char` for characters, and `char8` or `char16` when working with encoded text one unit at a time — indexing a [string](https://rux-lang.dev/docs/lang/types/text) gives code units, not characters. The scalar widths past `char32` add storage, not characters: a `char512` holds exactly the values a `char32` holds, in 64 bytes. ## Associated constants Imported from `Core`: | Constant | `char8` | `char16` | `char32` | `char64` | `char128` | `char256` | `char512` | | -------- | ------- | -------- | -------- | -------- | --------- | --------- | --------- | | `Bits` | 8 | 16 | 32 | 64 | 128 | 256 | 512 | | `Bytes` | 1 | 2 | 4 | 8 | 16 | 32 | 64 | | `Min` | 0 | 0 | U+0000 | U+0000 | U+0000 | U+0000 | U+0000 | | `Max` | 255 | 65,535 | U+10FFFF | U+10FFFF | U+10FFFF | U+10FFFF | U+10FFFF | `Min` and `Max` have the character type itself; `char::Max as uint32` and `char512::Max as uint32` are both 1114111. ## Literals A character literal is one character or [escape](https://rux-lang.dev/docs/lang/lexical/literals#escape-sequences) in single quotes. The prefix selects the type, and the character must be exactly one unit of it: | Literal | Type | Accepts | | ----------------- | --------- | --------------------------------------------------- | | `c8'A'` | `char8` | U+0000 to U+007F — one UTF-8 byte | | `c16'Ж'` | `char16` | U+0000 to U+FFFF, not a surrogate — one UTF-16 unit | | `'😀'`, `c32'😀'` | `char32` | Any scalar value | | `c64'😀'` | `char64` | Any scalar value | | `c128'😀'` | `char128` | Any scalar value | | `c256'😀'` | `char256` | Any scalar value | | `c512'😀'` | `char512` | Any scalar value | An unprefixed literal initialising or assigned to a `char8` or `char16` takes that type by the same rule, so `let initial: char8 = 'R';` works. A character that does not fit is refused, never truncated: ```text let accent = c8'é'; error: character 'é' (U+00E9) does not fit one 'char8' code unit help: write a string literal such as c8"é", or a byte such as 0xE9u8 let emoji: char16 = '😀'; error: character '😀' (U+1F600) does not fit one 'char16' code unit ``` `é` takes two bytes of UTF-8 and `😀` two units of UTF-16; text that needs several units is a [string](https://rux-lang.dev/docs/lang/types/text). The prefixes `c64` to `c512` make characters only: there is no string of those widths, so `c128"x"` is the identifier `c128` followed by a string literal, and `c64`, `c128`, `c256` and `c512` stay ordinary identifiers everywhere else. ```rux let letter = 'A'; let emoji = '😀'; let unit = c8'R'; let word = c16'Ж'; let wide = c64'\u{1F600}'; let widest = c512'😀'; let initial: char8 = 'R'; ``` ## Operations Characters compare by their numeric value — code-point order for scalar values, unit value for code units — with `==`, `!=`, `<`, `<=`, `>` and `>=`. The order is not alphabetical in any language's sense: `'Z' < 'a'`, because U+005A comes before U+0061. ```rux let c = c8'7'; let isDigit = c >= c8'0' && c <= c8'9'; // true ``` Arithmetic on characters goes through an integer: convert with `as`, compute, and convert back. ```rux let lower = c8'a'; let upper = ((lower as uint8) - 32) as char8; // 'A' let value = (c8'7' as int) - (c8'0' as int); // 7 let next = ('a' as uint32 + 1) as char; // 'b' ``` ## Conversions ### Between character types A scalar width widens implicitly to any wider scalar width — `char32` to `char64`, `char64` to `char128`, `char32` straight to `char512` — since they all hold the same scalar values. No other character conversion is implicit. A scalar width never narrows on its own, and `char8` and `char16` widen to nothing: they are units of different encodings, and a UTF-8 byte above 0x7F is not the UTF-16 unit, or the scalar value, with the same number. ```rux let scalar: char32 = 'λ'; let wide: char64 = scalar; let wider: char128 = wide; let widest: char512 = scalar; ``` ```text let unit: char8 = 'a'; let crossed: char16 = unit; error: cannot assign 'char8' to 'char16' let lifted: char128 = unit; error: cannot assign 'char8' to 'char128' let scalar: char32 = 'a'; let narrowed: char16 = scalar; error: cannot assign 'char32' to 'char16' let wide: char128 = c128'a'; let back: char64 = wide; error: cannot assign 'char128' to 'char64' ``` With `as`, a conversion to a wider character keeps the value, and a conversion to a narrower one checks it: a value the target cannot hold stops the program with `Panic: invalid character cast` rather than keeping its low bits. Between two scalar widths a scalar value always comes through unchanged: `wide as char32` is the same character. It never re-encodes: for a `face: char32` holding U+1F600, `face as char16` stops the program, since 0x1F600 is no `char16` unit, rather than giving 0xF600 or a surrogate pair. A constant that does not fit is refused instead, as `'😀' as char16` is with `error: constant cast from 'char32' to 'char16' is outside the target type's range`. To transcode text, use the Unicode and Text packages. ### To and from integers `as` converts a character to any integer type, giving its numeric value, and an integer to any character type: ```rux let code = 'A' as uint32; // 65 let byte = c8'A' as uint8; // 65 let smile = 0x263A as char; // '☺' ``` When the integer is a constant, the compiler checks that the character type can hold it: ```text let past: char8 = 0x100 as char8; error: constant cast from 'int' to 'char8' is outside the target type's range let surrogate: char32 = 0xD800 as char32; error: cast from 'int' to 'char32' uses invalid surrogate code point U+D800 ``` Every scalar width takes U+0000 to U+10FFFF and no more, however wide it is, and the check reads the whole constant, wide integers included: `0x1_0000_0000_0000_0041u128 as char128` is `error: constant cast from 'uint128' to 'char128' is outside the target type's range`, not the `A` its low 64 bits spell. A conversion at run time checks the full original value before narrowing. A negative value, an out-of-range value, or a surrogate for a scalar character type stops the program with `Panic: invalid character cast`. Code-unit types accept every value in their range, so `char16` still accepts surrogates. Mask an integer explicitly before casting when extracting its low byte is intended. ### Other conversions Characters convert with `as` to floating-point types (`'A' as float64` is 65.0) and to booleans (`false` only for U+0000). Without `as`, a character is never a number: `let n: uint8 = c8'a';` is `error: cannot assign 'char8' to 'uint8'`. ## See also - [Text](https://rux-lang.dev/docs/lang/types/text) — strings as slices of code units - [Literals](https://rux-lang.dev/docs/lang/lexical/literals#character-literals) — the full literal grammar - [Patterns](https://rux-lang.dev/docs/lang/patterns/patterns) — matching characters and character ranges - [Character](https://rux-lang.dev/docs/learn/character), [Character pattern](https://rux-lang.dev/docs/learn/character-pattern), [Unicode](https://rux-lang.dev/docs/learn/unicode) — lessons # Text Rux has no built-in string type. Text is a [slice](https://rux-lang.dev/docs/lang/slices/overview) of character code units, and a string literal is a read-only slice of code units stored in the program: | Type | Encoding | Literal | | ------------ | -------- | ---------------------- | | `char8[..]` | UTF-8 | `"Hello"`, `c8"Hello"` | | `char16[..]` | UTF-16 | `c16"Hello"` | | `char32[..]` | UTF-32 | `c32"Hello"` | `char8[..]` is the everyday text type: source files are UTF-8, unprefixed literals are UTF-8, and the standard packages take and return `char8[..]`. The wider encodings exist for foreign APIs that use them, such as UTF-16 on Windows. Owned, growable text — `String`, `StringBuilder` and the validated `StringView` — comes from the [Text package](https://rux-lang.dev/docs/api/text), not from the language. ## Code units, not characters Everything a slice does, it does in code units of its encoding: `.length` counts them, `[i]` returns one, and `for` visits each one. A character outside ASCII takes several UTF-8 units, or two UTF-16 units outside the Basic Multilingual Plane: | Text | `char8[..]` length | `char16[..]` length | `char32[..]` length | | -------------- | ------------------ | ------------------- | ------------------- | | `Hello` | 5 | 5 | 5 | | `€` (U+20AC) | 3 | 1 | 1 | | `🚀` (U+1F680) | 4 | 2 | 1 | ```rux let euro = "€uro"; let units = euro.length; // 6 let first = euro[0] as uint8; // 226, the first UTF-8 byte of € let tail = euro[3..]; // "uro" let wide = c16"\u{1F680}"; let pair = wide.length; // 2, a surrogate pair ``` A sub-slice can therefore cut a character in half. The Text and Unicode packages provide validated text, iteration by character and grapheme boundaries when an operation needs them. ## Members and operations | Form | Type | Meaning | | --------------- | ----------------------- | ------------------------------ | | `text.length` | `uint` | Number of code units | | `text.data` | `*char8` (and so on) | Pointer to the first code unit | | `text[i]` | `char8` (and so on) | The code unit at index `i` | | `text[a..b]` | `char8[..]` (and so on) | A view of units `a` up to `b` | | `for u in text` | — | Visits each code unit in order | These members need no import. An index past the end stops the program with `Panic: index out of range`. [Slices](https://rux-lang.dev/docs/lang/slices/overview) describes indexing and sub-slicing in full. ```rux func CountSpaces(text: char8[..]) -> uint { var spaces: uint = 0; for unit in text { if unit == ' ' { spaces += 1; } } return spaces; } ``` ### Comparing text `==` is not defined on slices, because comparing two views would compare where they point rather than what they hold: ```text error: operator '==' is not defined for slice type 'char8[..]' note: a slice is a view, so comparing the views would compare addresses rather than elements help: declare '==' on 'char8[..]', or compare the elements one at a time ``` Compare the units, or use `StringView::Equals` from the Text package: ```rux func SameText(a: char8[..], b: char8[..]) -> bool { if a.length != b.length { return false; } for i in 0..a.length { if a[i] != b[i] { return false; } } return true; } ``` ## Storage A literal's code units are stored in read-only data, followed by a NUL code unit that `.length` does not count. `"Hello".data` can therefore be passed to a C function that expects a NUL-terminated string. A slice value itself is a pointer and a length — 16 bytes — so passing or copying text never copies its units. A literal is read-only, and so is any `char8[..]`: ```text let word = "word"; word[0] = c8'W'; error: cannot modify elements through read-only slice 'char8[..]' help: use a 'var T[..]' view to write through the sequence ``` To change text, copy it into storage the program owns and take a writable view `var char8[..]` of that: ```rux let word = "word"; var letters: char8[4]; for i in 0..word.length { letters[i] = word[i]; } letters[0] = c8'W'; let changed: var char8[..] = letters[..]; // "Word" ``` ## Constants and parameters A string literal can initialise a constant, a field, or a parameter of the matching slice type: ```rux const Greeting: char8[..] = "Hello"; struct Message { text: char8[..]; tag: int32; } func Shout(text: char8[..]) -> uint { return text.length; } ``` Escapes such as `\n`, `\"` and `\u{1F680}` are encoded in the literal's own encoding. [Literals](https://rux-lang.dev/docs/lang/lexical/literals#string-literals) lists them. ## See also - [Characters](https://rux-lang.dev/docs/lang/types/characters) — the code unit and scalar value types - [Slices](https://rux-lang.dev/docs/lang/slices/overview) — the type text is made of - [Text package](https://rux-lang.dev/docs/api/text) — `String`, `StringBuilder` and friends - [String literal](https://rux-lang.dev/docs/learn/string-literal), [Encoding](https://rux-lang.dev/docs/learn/encoding), [UTF-8](https://rux-lang.dev/docs/learn/utf8), [String view](https://rux-lang.dev/docs/learn/string-view) — lessons # Type Aliases A type alias gives an existing type a second name. It introduces no new type: the alias and its target are the same type, interchangeable everywhere without a conversion. ```text TypeAlias ::= 'pub'? 'type' Identifier '=' Type ';' ``` ```rux type UserId = uint64; type Matrix = float32[2][2]; type Bytes = uint8[..]; type MaybeId = UserId?; ``` An alias is declared at the top level of a file or inside a `module` block. Like any declaration it is private to its package unless marked [`pub`](https://rux-lang.dev/docs/lang/modules/visibility). ## Transparency Because an alias names the same type as its target, values pass between the two in both directions, and a type test answers to either spelling: ```rux type Count = int32; func Main() -> int { let counted: Count = 7; let plain: int32 = counted; // no conversion let back: Count = plain; // and none back let same = counted is int32; // true return back as int; } ``` An alias also carries everything attached to its target. Its [associated constants](https://rux-lang.dev/docs/lang/types/integers#associated-constants) are reachable through it — `Count::Max` is `int32::Max` once Core's `int32` constants are imported, where `Count` is declared or where it is used — and its methods are callable on it. The reverse holds too: an `extend` block written for an alias extends the target type itself. ```rux type Celsius = float64; extend Celsius { func Fahrenheit(self: &Celsius) -> float64 { return self * 1.8 + 32.0; } } ``` After this, every `float64` has a `Fahrenheit` method, not only values declared as `Celsius`. ## An alias is not a distinct type An alias gives a name, never type safety. Two aliases of the same type are the same type as each other, so nothing stops them being mixed: ```rux type Metres = float64; type Feet = float64; func Main() -> int { let height: Metres = 1.8; let step: Feet = 2.5; let nonsense = height + step; // accepted: both are float64 return 0; } ``` When the compiler should keep two kinds of value apart, wrap the value in a single-field [struct](https://rux-lang.dev/docs/lang/structs/overview); each struct declaration is a type of its own. ```rux struct Metres { value: float64; } struct Feet { value: float64; } ``` ## What can be aliased Any type can be aliased: primitives, slices, arrays, tuples, optionals, sums, fallibles, pointers and references, [function types](https://rux-lang.dev/docs/lang/functions/function-types), user-defined types and instantiations of generic types. ```rux struct Point { x: int; y: int; } struct Box<T> { value: T; } type Position = Point; type IntBox = Box<int>; type Pair = (int, int); type Callback = func(int) -> bool; func Main() -> int { let here = Position { x: 1, y: 2 }; let boxed: IntBox = Box<int> { value: 3 }; let pair: Pair = (4, 5); return here.x + boxed.value + pair.1; // 9 } ``` An alias of a struct can be used to write a struct literal, as `Position { x: 1, y: 2 }` shows. An alias of a generic type's instantiation also names the associated constants that an `extend` block of that instantiation declares. A path cannot spell type arguments, so this is how one is reached — and how a module variable of a generic type starts as a constant, since a module variable needs a compile-time value and a constructor call is not one: ```rux import Atomic::Atomic; type Hits = Atomic<uint64>; var Count: Hits = Hits::Zero; // the Zero that `extend Atomic<uint64>` declares ``` ::note **Limits in rux 0.4.0.**:br rux 0.4.0 resolves an alias where it is declared, so the type it names must be declared above it in the file. It does not yet accept a struct literal written through an alias of a generic instantiation, such as `IntBox { value: 3 }`; write `Box<int> { value: 3 }`. And an alias named through a module path from outside its module, such as `Units::Metres`, is not yet resolved to its target. :: An alias cannot take type parameters. `type Pair<T> = (T, T);` is a syntax error, `error: expected '=' after the type alias name before '<'`; write a generic struct instead. An alias cannot name itself, directly or through other aliases: ```text type A = B; type B = A; error: type alias 'A' has a cyclic definition ``` ## Built-in aliases Four primitive names are aliases, built into the compiler like every primitive type: | Alias | Target | Meaning | | ------- | --------- | --------------------------------------------------- | | `bool` | `bool8` | The everyday boolean | | `byte` | `uint8` | A raw byte of storage, as opposed to a small number | | `char` | `char32` | One Unicode scalar value | | `float` | `float64` | The everyday floating-point type | They behave exactly like their targets — same representation, ABI, constants, conversions and overloads — and compiler messages name the target: a mistake with a `bool` reports `bool8`. The names can be used as types without an import, and no package may declare them: `type bool = int32;` is rejected as already declared. Their associated constants, like any primitive's, need an import, and an alias imports its target's: `import Core::byte;` makes `byte::Max` and `uint8::Max` available, the same constant. `int` and `uint` are not aliases. They are distinct primitive types that convert implicitly to and from `int64` and `uint64`; see [Integers](https://rux-lang.dev/docs/lang/types/integers). ## See also - [Types](https://rux-lang.dev/docs/lang/types/overview) — type identity and conversions - [Function types](https://rux-lang.dev/docs/lang/functions/function-types) — naming a callable signature - [Structs](https://rux-lang.dev/docs/lang/structs/overview) — when a distinct type is wanted - [Type alias](https://rux-lang.dev/docs/learn/type-alias) — the lesson # Bindings A *binding* gives a name to a value. Rux has three kinds, each introduced by its own keyword: | Keyword | Binds | Can change | Computed | Page | | ------- | --------------------------- | ---------- | --------------- | -------------------------------------------------------------- | | `let` | an immutable run-time value | no | at run time | this page | | `var` | a mutable run-time value | yes | at run time | this page | | `const` | a compile-time value | no | by the compiler | [Constants](https://rux-lang.dev/docs/lang/bindings/constants) | ```text binding = ("let" | "var") pattern [":" type] [initializer] ";" initializer = "=" expression | "<-" expression ``` The pattern is usually a single name. It can also take a tuple or a structure apart — see [Destructuring](https://rux-lang.dev/docs/lang/bindings/destructuring). ```rux let answer = 42; var counter = 0; counter += 1; ``` ## let `let` binds a value that never changes. The name keeps the value it was given for as long as it is in scope: ```rux let limit: int32 = 10; limit = 11; ``` ```text error: cannot modify immutable variable 'limit' help: declare 'limit' with 'var' to make it mutable ``` Because a `let` can never be assigned later, it must be initialized where it is declared. `let total: int32;` is `error: immutable variable requires an initializer`. Prefer `let`. A name that cannot change is one less thing for the reader to track, and the compiler rejects an accidental write instead of letting it through. ## var `var` binds a value that may be replaced. Assignment, the compound operators and `++`/`--` all need a `var` (or another mutable place, such as a field of one): ```rux var score: int32 = 10; score = 12; score += 5; score++; ``` A `var` may also be declared without a value and assigned later. Until then it holds nothing, and the compiler makes sure no path reads it too early — see [Initialization](https://rux-lang.dev/docs/lang/bindings/initialization). ## Types and inference With an initializer and no annotation, the binding takes the initializer's type. Literals have a default type: | Initializer | Inferred type | | ------------------------ | --------------------------- | | `42`, `3000000000` | `int` | | `1.5` | `float64` | | `'A'` | `char32` | | `true` | `bool` | | `"text"` | `char8[..]` | | `7u8`, `2.5f32`, `c8'A'` | the suffix or prefix's type | An annotation, `: Type`, chooses the type instead. An unsuffixed integer literal then takes the annotated type, provided its value fits: ```rux let small: uint8 = 200; let wide: int64 = 5; ``` `let small: uint8 = 300;` is `error: integer literal is out of range for type 'uint8'`. A binding's type is fixed once it is declared. A value of another type is not converted to fit, with one exception: an integer widens to a wider integer of the same signedness, because no value can change on the way. Every other change of type is written with [`as`](https://rux-lang.dev/docs/lang/expressions/casts): ```rux let narrow: int32 = 7; let widened: int64 = narrow; let converted = narrow as float64; ``` The reverse, `let back: int32 = widened;`, is `error: cannot assign 'int64' to 'int32'`. ## = and <- An initializer is written with `=` or `<-`, and the two mean different things: | Form | Meaning | | ------------- | ------------------------------------------------------------------- | | `let b = a;` | **copy**: `b` gets its own copy, and `a` is unchanged | | `let b <- a;` | **move**: the value is handed to `b`, and `a` may not be read again | ```rux let first = Buffer { size: 4 }; let second <- first; PrintLine("{}", second.size); ``` Reading `first` after the move is `error: value 'first' is used after it was moved`. A type that cannot be copied, such as one that owns a resource, can only be bound with `<-` from a named source; a freshly made value, such as the result of a call, needs no `<-`. The full rules are in [Copy and move](https://rux-lang.dev/docs/lang/ownership/copy-and-move). ## Mutability Mutability belongs to the binding and reaches all the way into the value. A `let` structure cannot have any field changed, at any depth; a `var` one can have every field changed, or be replaced whole: ```rux let fixed = Point { x: 1, y: 2 }; var moving = Point { x: 1, y: 2 }; moving.x = 5; moving = Point { x: 0, y: 0 }; ``` `fixed.x = 5;` is `error: cannot modify immutable variable 'fixed'`. There is no per-field opt-out in either direction. The same holds for tuples and fixed-size arrays. A function changes a caller's value only through a writable reference, `&var T`, or a writable pointer, `*var T` — see [References](https://rux-lang.dev/docs/lang/references/overview) and [Pointers](https://rux-lang.dev/docs/lang/pointers/overview). A parameter itself is always immutable; a function that needs a mutable copy moves the argument into a local, as in `var local <- value;`. ## Scope A binding is visible from its declaration to the end of the block that contains it. Declaring the same name twice in one block is an error: ```rux let total = 1; let total = 2; ``` ```text error: variable 'total' is already declared in this scope ``` Each name a [destructuring](https://rux-lang.dev/docs/lang/bindings/destructuring) pattern declares counts separately, so `let (p, p) = (1, 2);` is refused the same way. A block nested inside another — the body of an `if` or a loop — may declare a name that is already used outside it. The inner binding hides the outer one until the block ends, and the two stay separate bindings: after the inner block the name reads the outer binding's own value again. ```rux let total = 1; if ready { let total = 2; PrintLine("{}", total); // 2 } PrintLine("{}", total); // 1 ``` ## Discarding a value `_` is not a name. `let _ = value;` evaluates `value` and throws it away, and nothing can read `_` afterwards — see [Destructuring](https://rux-lang.dev/docs/lang/bindings/destructuring#discarding-a-value). ## See also - [Constants](https://rux-lang.dev/docs/lang/bindings/constants) — names the compiler computes - [Initialization](https://rux-lang.dev/docs/lang/bindings/initialization) — declaring a `var` now and giving it a value later - [Destructuring](https://rux-lang.dev/docs/lang/bindings/destructuring) — binding several names from one value - [Assignment](https://rux-lang.dev/docs/lang/expressions/assignment) — `=`, `<-`, compound assignment, `++` and `--` - [Copy and move](https://rux-lang.dev/docs/lang/ownership/copy-and-move) — what `=` and `<-` do to the source - Learn: [Variable](https://rux-lang.dev/docs/learn/variable), [Mutable](https://rux-lang.dev/docs/learn/mutable) # Constants A *constant* is a name for a value the compiler computes once, before the program runs. It is declared with `const`, can never change, and can be used wherever the language needs a compile-time value — an array size, for instance. ```text constant = ["pub"] "const" Name [":" type] "=" expression ";" ``` ```rux const MaxConnections = 100; const Ratio: float64 = 1.5; const Greeting: char8[..] = "hello"; ``` The type annotation is optional. Without one, the constant takes its initializer's type, exactly as a [`let`](https://rux-lang.dev/docs/lang/bindings/overview#types-and-inference) would: `MaxConnections` above is an `int`. With one, an unsuffixed literal takes the annotated type, and must fit it — `const Small: uint8 = 300;` is `error: integer literal is out of range for type 'uint8'`. By convention, constant names are PascalCase. ## Where a constant may appear | Place | Example | Named as | | ---------------------- | ------------------------------------ | ------------- | | A module, at top level | `const Limit: uint = 4;` | `Limit` | | A function body | `const Local = Limit * 2;` | `Local` | | An `extend` block | `const Zero = Point { x: 0, y: 0 };` | `Point::Zero` | A module-level constant may be `pub`, like any other declaration — see [Visibility](https://rux-lang.dev/docs/lang/modules/visibility). A constant declared in an `extend` block is an *associated constant* of the type, and is named through it: ```rux extend Point { const Zero = Point { x: 0, y: 0 }; const Dimensions: int = 2; } ``` ```rux PrintLine("{} {}", Point::Zero.x, Point::Dimensions); ``` The primitive types carry associated constants of their own, such as `int8::Min` and `float64::Epsilon`, once Core's extension of their type is imported — see [Integers](https://rux-lang.dev/docs/lang/types/integers). ## What the initializer may contain The initializer is computed by the compiler, so everything in it must be known before the program runs. It may use: - literals, and other constants - the [arithmetic](https://rux-lang.dev/docs/lang/expressions/arithmetic), [comparison](https://rux-lang.dev/docs/lang/expressions/comparison), [logical](https://rux-lang.dev/docs/lang/expressions/logical), [bitwise](https://rux-lang.dev/docs/lang/expressions/bitwise) and [shift](https://rux-lang.dev/docs/lang/expressions/shift) operators, [casts](https://rux-lang.dev/docs/lang/expressions/casts) and the [conditional](https://rux-lang.dev/docs/lang/expressions/conditional) `? :` - `sizeof(T)` and `alignof(T)` - compile-time values such as `#target` — see [Compile-time context](https://rux-lang.dev/docs/lang/comptime/context) - structure, array, tuple and enum values built from all of these ```rux const Limit: uint = 4; const Area = Limit * Limit + 1; const Mask = (1u32 << 4) - 1; const Origin = Point { x: 0, y: 0 }; const Primes: int32[4] = [2, 3, 5, 7]; const Pair = (1, true); const Favourite = Color::Green; const Bytes = sizeof(Point) + alignof(Point); const OnWindows = #target.os == OperatingSystem::Windows; ``` A function call and a variable hold run-time values, so neither may appear: ```rux const FromCall = Seven(); const FromVariable = counter; ``` ```text error: call to 'Seven' is not a compile-time value help: declare 'FromCall' with 'let' to compute it at run time error: 'counter' is not a compile-time constant help: declare 'FromVariable' with 'let' to compute it at run time ``` The same is true of a parameter. When the value can only be known as the program runs, it belongs in a `let`. ## Constants as compile-time integers An integer constant is a compile-time integer wherever one is required. It can give an array its size and a repeated array literal its count, and another constant can be computed from it: ```rux const Limit: uint = 4; const Area = Limit * Limit + 1; func Main() -> int { const Local = Area * 2; var flags: bool[Limit] = [false; Limit]; let grid: int32[Local] = [0; Local]; PrintLine("{} {}", flags.length, grid.length); return 0; } ``` This prints `4 34`. A `let` holding the same number could not do this: its value exists only at run time. ## A constant cannot change A constant is not a variable, and nothing can assign to it. `MaxConnections = 5;` is `error: cannot modify constant 'MaxConnections'`. ## Constants are not patterns In a [`match`](https://rux-lang.dev/docs/lang/patterns/match) arm, a bare name always binds a new variable, so a constant's name cannot be used to compare against its value. Writing one is an error rather than a silent new binding: ```text error: pattern 'Limit' cannot bind a new variable because 'Limit' already names a constant help: a pattern compares with literal values; write the value of 'Limit', or bind the value and compare it with 'Limit' in a guard such as 'value if value >= Limit' ``` Compare in a [guard](https://rux-lang.dev/docs/lang/patterns/patterns#guards) instead: ```rux match n { v if v == Limit => PrintLine("at the limit"), else => PrintLine("elsewhere") } ``` ## const or let | | `const` | `let` | | ------------------------ | ------------------------ | ----------------------- | | Computed | by the compiler, once | each time the line runs | | Initializer | compile-time values only | any expression | | Module level | allowed | not allowed | | `extend` block | allowed, as `Type::Name` | not allowed | | Array size, repeat count | allowed | not allowed | ## See also - [Bindings](https://rux-lang.dev/docs/lang/bindings/overview) — `let` and `var` - [Compile-time evaluation](https://rux-lang.dev/docs/lang/comptime/overview) — `when` and the compile-time values - [Arrays](https://rux-lang.dev/docs/lang/arrays/overview) — sizes and repeated literals - Learn: [Const](https://rux-lang.dev/docs/learn/const) # Initialization Every binding holds a value before anything reads it. A `let` gets its value where it is declared. A `var` may be declared without one, and what happens then depends on its type: ```text var-declaration = "var" Name ":" type ";" ``` | Declaration | When `T` … | The variable starts as | | --------------- | ----------------------------------- | ------------------------------------------------------ | | `var value: T;` | has an accessible constructor `T()` | the value `T()` returns | | `var value: T;` | has no such constructor | nothing — it must be assigned before it is read | | `let value: T;` | — | an error: `immutable variable requires an initializer` | There is no hidden default. A number declared without a value is not zero; it holds nothing until the program says what it is. ## A default constructor runs When the type has a [constructor](https://rux-lang.dev/docs/lang/structs/constructors) that takes no arguments, `var value: T;` calls it, and the variable is initialized from the start: ```rux struct Tally { count: int32; } extend Tally { func Tally() -> Tally { return Tally { count: 10 }; } } ``` ```rux var tally: Tally; tally.count += 1; PrintLine("{}", tally.count); ``` This prints `11`. The `+=` reads `count` before changing it, and that read is fine: `Tally()` has already run. ## Tracked storage Without such a constructor, the variable holds nothing, and the compiler tracks it. Every path from the declaration to a read must assign it first: ```rux func Grade(score: int32) -> char8[..] { var grade: char8[..]; if score >= 90 { grade = "excellent"; } else if score >= 50 { grade = "pass"; } else { grade = "retry"; } return grade; } ``` Each branch assigns `grade`, so the `return` is accepted. Remove the final `else`, and a score below 50 reaches the `return` with nothing assigned: ```text error: value 'grade' may be uninitialized on some control-flow paths help: initialize or preserve 'grade' on every path before this use ``` A read with no assignment before it at all is reported directly: ```rux var total: int32; PrintLine("{}", total); ``` ```text error: variable 'total' is used before it is initialized help: assign a value to 'total' before this use ``` ## One part at a time A value of a plain type — one with nothing to destroy, such as a structure of numbers — may be filled in one part at a time: field by field, tuple element by tuple element. A part that has been written may be read at once. The whole value counts as initialized once every part has been written on every path that reaches the use: ```rux var p: Point; p.x = 1; p.y = 2; PrintLine("{} {}", p.x, p.y); ``` Before `p.y` is written, reading it — or using `p` whole — is refused, with a note that names what has been written: ```text error: variable 'p' is used before it is initialized note: only 'p.x' has been written, not 'p.y' ``` A fixed-size array of plain elements counts as initialized from its declaration, so a loop can fill it: ```rux var values: int32[3]; for i in 0..3 { values[i] = (i as int32) * 10; } ``` ## A value with a destructor is written whole A type that needs destroying — one with a [destructor](https://rux-lang.dev/docs/lang/ownership/destructors), or with a field that has one — cannot be built a part at a time. A part written into a variable that holds no value would belong to no whole value, and nothing would ever destroy it: ```rux var holder: Holder; holder.handle <- Handle { code: 1 }; ``` ```text error: cannot write field 'handle' of 'holder', which holds no value help: initialize 'holder' whole, as in 'holder = Holder { ... }' ``` Assign such a variable whole — `holder = Holder { … };` or `holder <- other;` — and from then on its parts can be replaced like any other place. Taking the address of a part, `@holder.handle`, is refused for the same reason. ## Taking the address initializes Taking the writable address of a whole uninitialized variable with `@` counts as initializing it, because the address exists to be filled through. The compiler trusts the function that receives it to write a complete value: ```rux func Fill(target: *var Point) { *target = Point { x: 3, y: 4 }; } ``` ```rux var q: Point; Fill(@q); PrintLine("{} {}", q.x, q.y); ``` This is how a variable is handed to a C function that fills it in — see [FFI](https://rux-lang.dev/docs/lang/ffi/overview). ## After a move A variable that has been [moved](https://rux-lang.dev/docs/lang/ownership/copy-and-move) from holds nothing again, as if it had just been declared. Reading it is an error — for a variable named `moved`, `error: value 'moved' is used after it was moved` — until it is assigned whole once more. ## See also - [Bindings](https://rux-lang.dev/docs/lang/bindings/overview) — `let`, `var` and their types - [Constructors](https://rux-lang.dev/docs/lang/structs/constructors) — the `T()` that `var value: T;` calls - [Destructors](https://rux-lang.dev/docs/lang/ownership/destructors) — why some values are written whole - [Copy and move](https://rux-lang.dev/docs/lang/ownership/copy-and-move) — what a move leaves behind - Learn: [Initialization](https://rux-lang.dev/docs/learn/initialization) # Destructuring A `let` or `var` may bind a [pattern](https://rux-lang.dev/docs/lang/patterns/patterns) instead of a single name. The pattern mirrors the shape of the value and takes it apart, declaring one new binding for each name it contains: ```rux let (quotient, remainder) = Divide(17, 5); let Point { x: px, y: py } = point; ``` ```text binding-pattern = Name | "_" | "(" binding-pattern { "," binding-pattern } ")" | TypeName "{" field-pattern { "," field-pattern } "}" field-pattern = Name [":" binding-pattern] ``` ## Irrefutable patterns only A `let` has no second branch to take when a pattern does not fit, so its pattern must match every value of its type. It is built only from names, `_`, tuple patterns and structure patterns, nested to any depth. A literal, a range, an enum or variant case, a typed pattern, `none` or a presence pattern could fail, and is refused: ```rux let (s, 1) = (1, 1); ``` ```text error: refutable pattern in 'let' binding note: a 'let' pattern must match every value, so each part is a name, '_', a tuple, or a structure help: test the value with 'match' instead ``` To test a value against a pattern that may not match, use [`match`](https://rux-lang.dev/docs/lang/patterns/match). ## Tuple patterns A tuple pattern has one element per member of the tuple, in order: ```rux let (quotient, remainder) = Divide(17, 5); let ((x1, y1), (x2, y2)) = ((0, 0), (6, 8)); ``` The pattern must have exactly as many elements as the tuple. `let (a, b) = (1, 2, 3);` is `error: tuple pattern has 2 elements but type '(int, int, int)' has 3`, and a tuple pattern over anything that is not a tuple, as in `let (x, y) = 5;`, is `error: cannot destructure non-tuple type 'int'`. ## Structure patterns A structure pattern names the type and lists fields by name, in any order. `field: pattern` binds the field through a pattern; `field` alone is shorthand for `field: field`, binding a variable with the field's own name: ```rux let point = Point { x: 3, y: 4 }; let Point { x: px, y: py } = point; let Point { y } = point; ``` A field the pattern does not mention is simply not bound, so there is no need to list every field. Structure and tuple patterns nest inside each other: ```rux let segment = Segment { start: Point { x: 1, y: 2 }, end: Point { x: 5, y: 6 } }; let Segment { start: Point { x: sx }, end } = segment; ``` This binds `sx` to `1` and `end` to the whole end point. The type in the pattern must be the value's type — `let Handle { code } = point;` is `error: struct pattern 'Handle' cannot match value of type 'Point'` — and every field must exist: `let Point { z } = point;` is `error: struct 'Point' has no field 'z'`. ## var patterns With `var`, every name the pattern declares is mutable: ```rux var (low, top) = (1, 9); low -= 1; top += 1; ``` There is no way to make some of the names mutable and others not. ## Annotations A type annotation after the pattern applies to the whole value: ```rux let (pair, count): ((int, int), int) = ((1, 2), 3); ``` A pattern cannot annotate one of its own parts: `let (a: int32, b) = …` is a typed pattern, and typed patterns are refutable. ## Discarding a value `_` matches anything and binds nothing. Inside a pattern it skips a part; on its own, `let _ = value;` evaluates a value and throws it away at once, like a temporary nobody kept: ```rux let (_, high) = Bounds(readings); let _ = Divide(1, 1); ``` `_` names nothing, so it cannot be read afterwards — `return _;` is `error: cannot read '_', because it discards the value it binds` — and several `let _` lines in one block do not clash. A [fallible](https://rux-lang.dev/docs/lang/errors/overview) result is the exception. Binding it to `_` would lose its failure without a word, so binding one to `_` is refused: ```text error: fallible result of type 'int ! ConfigError' is discarded note: binding a fallible to '_' does not handle its failure help: propagate it with '?', recover with 'catch', or match both '.Success' and '.Failure' ``` Handle the failure instead, as [Handling errors](https://rux-lang.dev/docs/lang/errors/handling) shows. ## Copying and moving patterns A pattern initialized with `=` copies the parts it binds and leaves the source as it was. One initialized with `<-` takes the value over: each bound part moves into its binding, and each part bound to `_` or left out of a structure pattern is destroyed on the spot. A type that declares its own [destructor](https://rux-lang.dev/docs/lang/ownership/destructors) is destroyed whole, so it cannot be split into parts: ```rux let File { handle: h } <- file; ``` ```text error: cannot split 'File' with a moving pattern, because it declares destructor '~File' note: '~File' runs on the whole value, so no part of it can be taken out on its own help: bind the whole value and read its fields, or match a value that stays with its owner ``` See [Copy and move](https://rux-lang.dev/docs/lang/ownership/copy-and-move) for what a move does to the source. ## Patterns only declare Destructuring always declares new names. It cannot assign to names that already exist, so a swap written as `(m, n) = (n, m);` is `error: operator '=' requires an assignable target, but its left operand has type '(int, int)'`. Assign the variables one at a time, through a temporary. Each name in a pattern is its own declaration, so `let (p, p) = (1, 2);` is `error: variable 'p' is already declared in this scope`. A `for` loop variable is a single name, never a pattern — see [Loops](https://rux-lang.dev/docs/lang/statements/loops#for). ## See also - [Patterns](https://rux-lang.dev/docs/lang/patterns/patterns) — every pattern form, refutable ones included - [match](https://rux-lang.dev/docs/lang/patterns/match) — testing a value against patterns that may fail - [Tuples](https://rux-lang.dev/docs/lang/tuples/overview) and [Structures](https://rux-lang.dev/docs/lang/structs/overview) — the values being taken apart - Learn: [Destructure](https://rux-lang.dev/docs/learn/destructure), [Struct pattern](https://rux-lang.dev/docs/learn/struct-pattern) # Module variables A *module variable* is one storage location for the whole program, declared at module level with `var`. Every function that can name it reads and writes the same place. A *thread-local variable*, declared with `thread var`, is the same except that every thread has its own copy. ```text module-variable = ["pub"] ["thread"] "var" Name ":" type "=" expression ";" ``` ```rux var Requests: uint64 = 0; pub var Verbosity: int32 = 1; func Record() { Requests += 1; } ``` The type is always written, because other functions and packages agree on the variable's layout, and an initial value is required. `let` has no module-level form: a value that never changes is a [constant](https://rux-lang.dev/docs/lang/bindings/constants). ## The initial value The initial value follows the rules of a constant's initializer: the compiler computes it from literals, operators, casts, constants, and struct, array and tuple values built from them. A call or another variable is rejected with the same messages a constant gets. The program starts with the variable holding exactly those bytes. A value whose bytes are all zero is placed in zero-fill storage and takes no space in the executable; any other value is placed in initialized data. ## Visibility and paths `pub var` publishes a module variable like any other declaration, so another package can import it, read it and assign to it. A variable in another module is reached through its path: ```rux Settings::Level = 5; ``` Module variables are named in PascalCase, like other module-level declarations. Inside a function body, `var` declares an ordinary local, and `pub var` there is an error. ## Addresses `@Name` is a writable `*var T` to the variable's storage, aligned as `alignof(T)` reports. Every `@Name`, in every package, names the same address. That is what makes a module variable usable with the [atomic operations](https://rux-lang.dev/docs/lang/memory/atomics), which take the address of the value they act on. ## What a module variable may hold Module storage lives until the program exits and is never destroyed, so a module variable cannot have a type that needs destruction. It cannot hold a [slice](https://rux-lang.dev/docs/lang/slices/overview) either, since a slice borrows storage the variable does not own. Nothing moves out of a module variable: every function shares it, so it must always hold a value. ```text error: cannot move out of module variable 'Requests' note: a module variable is shared by every function and must always hold a value help: copy the value, or assign a new value to the variable after reading it ``` ## Thread-local variables `thread var` gives every thread its own copy of the variable. Each thread's copy starts as the initial value, whether the thread is the main one or one started later, and keeps its address for the thread's life, so `@Name` on two threads gives two addresses. ```rux thread var Depth: int32 = 0; func Enter() -> int32 { Depth += 1; return Depth; } ``` Everything else follows the rules above: the type and a compile-time initial value are written out, `pub thread var` publishes the variable, a variable in another module is reached through its path, a type that needs destruction or a slice is rejected, and nothing moves out. `thread` is not a keyword: it means this only before a module-level `var`, and stays an ordinary name everywhere else. A thread-local variable costs one or two instructions more than a module variable to reach: | Target | How a thread finds its copy | | -------------- | -------------------------------------------------------------------------------------------------------- | | Linux, FreeBSD | at a fixed offset from the thread pointer, set up by the dynamic loader; the program links the C library | | Windows | through the image's TLS directory, from which the loader gives each thread a copy of the template | | macOS | through a descriptor that dyld binds; reading the variable calls through it | A shared library or a static library with thread-local variables is rejected for now. ## See also - [Constants](https://rux-lang.dev/docs/lang/bindings/constants) — the initializer rules a module variable's initial value follows - [Atomics](https://rux-lang.dev/docs/lang/memory/atomics) — reading and writing shared memory from several threads - [Visibility](https://rux-lang.dev/docs/lang/modules/visibility) — what `pub` publishes # Expressions An *expression* computes a value: a literal, a name, a call, or operators applied to other expressions. This chapter covers the operators; the values they work on are described with their [types](https://rux-lang.dev/docs/lang/types/overview). ```rux let total = price * quantity + shipping; let ready = count > 0 && !paused; let label = n % 2 == 0 ? "even" : "odd"; ``` ## Operators | Kind | Operators | | --------------------------------------------------------------------- | ----------------------------------------- | | [Arithmetic](https://rux-lang.dev/docs/lang/expressions/arithmetic) | `+` `-` `*` `/` `%`, unary `-` | | [Comparison](https://rux-lang.dev/docs/lang/expressions/comparison) | `==` `!=` `<` `<=` `>` `>=` | | [Logical](https://rux-lang.dev/docs/lang/expressions/logical) | `&&` `||` `!` | | [Bitwise](https://rux-lang.dev/docs/lang/expressions/bitwise) | `&` `|` `^` `~` | | [Shift](https://rux-lang.dev/docs/lang/expressions/shift) | `<<` `>>` `>>>` | | [Assignment](https://rux-lang.dev/docs/lang/expressions/assignment) | `=` `<-` `+=` `-=` … `>>>=`, `++` `--` | | [Conditional](https://rux-lang.dev/docs/lang/expressions/conditional) | `c ? a : b` | | [Casts](https://rux-lang.dev/docs/lang/expressions/casts) | `as` | | [Type tests](https://rux-lang.dev/docs/lang/sums/type-tests) | `is` | | [Ranges](https://rux-lang.dev/docs/lang/ranges/overview) | `..` `..=` `...` | | [Coalescing](https://rux-lang.dev/docs/lang/optionals/coalescing) | `??` | | [Propagation](https://rux-lang.dev/docs/lang/errors/propagation) | postfix `?`, `? else (e => …)` | | [Recovery](https://rux-lang.dev/docs/lang/errors/handling) | postfix `catch { … }` | | [Pointers](https://rux-lang.dev/docs/lang/pointers/overview) | `@` (address of), unary `*` (dereference) | | [Moves](https://rux-lang.dev/docs/lang/ownership/copy-and-move) | unary `<-` | There is no unary `+` and no power operator; [Arithmetic](https://rux-lang.dev/docs/lang/expressions/arithmetic#no-power-operator) explains what `**` means instead. ## Precedence When an expression mixes operators, *precedence* decides how it groups: an operator on a higher level takes its operands before one on a lower level. Parentheses override precedence everywhere. Rux has 17 levels: | Level | Operators | Associativity | | ----- | ---------------------------------------------------------------------------------------------------------------------------------- | -------------- | | 17 | postfix: `.field` `.0` `.Method()` `::Name` `Type { … }` `f<T>()` `f()` `a[i]` `x?` `x? else (e => …)` `x catch { … }` `x++` `x--` | left to right | | 16 | prefix: `<-` `!` `-` `~` `*` `@` `++` `--` | right to left | | 15 | `as` `is` | left to right | | 14 | `*` `/` `%` | left to right | | 13 | `+` `-` | left to right | | 12 | `<<` `>>` `>>>` | left to right | | 11 | `<` `<=` `>` `>=` | left to right | | 10 | `==` `!=` | left to right | | 9 | `&` | left to right | | 8 | `^` | left to right | | 7 | `|` | left to right | | 6 | `&&` | left to right | | 5 | `||` | left to right | | 4 | `??` | right to left | | 3 | `c ? a : b` | right to left | | 2 | `a..b` `a..=b` `a...b` `..b` `..=b` `...b` `a..` `..` | does not chain | | 1 | `=` `<-` `+=` `-=` `*=` `/=` `%=` `&=` `|=` `^=` `<<=` `>>=` `>>>=` | right to left | Operators on one level group from the left where the table says so: `100 / 10 / 5` is `(100 / 10) / 5`, which is 2. `??` and `? :` group from the right, so `a ?? b ?? c` is `a ?? (b ?? c)`. A range does not chain: `0..1..2` does not parse. A few entries need a word: - **Postfix `?` and the conditional `?`.** A `?` written directly after an expression, with no space before it, is postfix [propagation](https://rux-lang.dev/docs/lang/errors/propagation). A `?` with whitespace before it opens a [conditional](https://rux-lang.dev/docs/lang/expressions/conditional). - **Casts and tests take a type.** The right side of `as` and `is` is a type, not an expression. It ends before `..`, `|` and `!`, so a sum or fallible target is grouped: `value is (A | B)`. - **The coalescing fallback may leave.** The right side of `??` may be `fail`, `return`, `break` or `continue` instead of a value — see [Coalescing](https://rux-lang.dev/docs/lang/optionals/coalescing). - **Prefix `&` does not exist.** Taking an address is `@`; `&x` is `error: '&' does not take an address; write '@' to take the address of a value`. ## Consequences Most of the order matches ordinary arithmetic and needs no thought: `2 + 3 * 4` is 14, and `age >= 18 && age < 65` compares before it combines. A few places are worth knowing by heart. **Bitwise operators bind more loosely than comparisons.** `x & 1 == 0` is `x & (1 == 0)`, an integer and a `bool`: ```text error: operator '&' cannot combine left operand 'int32' with right operand 'bool8' ``` Write `(x & 1) == 0`. **`as` binds more tightly than arithmetic.** It converts only the operand next to it, so `a as float64 / b as float64` converts both operands before dividing, and `(a / b) as float64` divides integers first. A prefix operator binds more tightly still: `-x as int64` is `(-x) as int64`. **Shifts bind more loosely than `+` and `-`.** `1 << 2 + 1` is `1 << 3`, which is 8. **`==` binds more tightly than `??`.** `value ?? 0 == 0` is `value ?? (0 == 0)`. Write `(value ?? 0) == 0`. **The conditional binds more loosely than almost everything.** `price - member ? 5 : 0` is `(price - member) ? 5 : 0`. A conditional inside a larger expression is wrapped: `price - (member ? 5 : 0)`. ```mermaid flowchart TD e["`flags & mask == 0`"] --> g["`flags & (mask == 0)`"] g --> x["`error: int & bool`"] f["`(flags & mask) == 0`"] --> ok["a `bool`, as intended"] ``` ## Evaluation order Operands are evaluated from left to right, and so are the arguments of a call: in `Note(1) + Note(2) * Note(3)`, the three calls run in the order they are written, even though the multiplication happens first. `&&`, `||`, `??` and the conditional evaluate their right side only when it is needed — see [Logical](https://rux-lang.dev/docs/lang/expressions/logical#short-circuit-evaluation) and [Conditional](https://rux-lang.dev/docs/lang/expressions/conditional). ## Operand types Rux never changes a value's type behind your back. The operands of a binary operator must agree on a type, by these rules: | Operands | Result | | ------------------------------------------------ | ------------------------------------------- | | two values of one type | that type | | an unsuffixed integer literal and an integer | the integer's type; the literal must fit it | | two integers of one signedness, different widths | the wider type | | a `float32` and a `float64` | `float64` | | any other pair of floating-point widths | an error: convert one with `as` | | a signed and an unsigned integer | an error: convert one with `as` | | an integer and a floating-point value | an error: convert one with `as` | ```rux let small: int32 = 1; let big: int64 = 5000000000; let sum = small + big; let doubled = 2 * small; ``` `sum` is an `int64` and `doubled` an `int32`. Mixing signedness is refused with a note saying why: ```text error: operator '+' cannot combine left operand 'uint64' with right operand 'int64' note: the operands differ in signedness, so neither converts to the other's type help: convert one operand with 'as' to the type the operation should use ``` A literal that does not fit the other operand's type is an error rather than a silent wrap: with `count: uint64`, `count == -1` is `error: integer literal is out of range for type 'uint64'`. ## Statements and values An assignment is an expression in the grammar but produces no value, so it cannot be used inside another expression — see [Assignment](https://rux-lang.dev/docs/lang/expressions/assignment). An expression followed by `;` is an [expression statement](https://rux-lang.dev/docs/lang/statements/overview). ## See also - [Operators and punctuation](https://rux-lang.dev/docs/lang/lexical/operators) — how the operator tokens are spelt - [Statements](https://rux-lang.dev/docs/lang/statements/overview) — where expressions are used - [Operator interfaces](https://rux-lang.dev/docs/lang/interfaces/operators) — giving your own types operators - Learn: [Precedence](https://rux-lang.dev/docs/learn/precedence), [Arithmetic](https://rux-lang.dev/docs/learn/arithmetic) # Arithmetic The arithmetic operators compute with integers and floating-point numbers. | Operator | Operation | Example | Level | | -------- | ----------------- | ------- | ----- | | `-` | negation (prefix) | `-a` | 16 | | `*` | multiplication | `a * b` | 14 | | `/` | division | `a / b` | 14 | | `%` | remainder | `a % b` | 14 | | `+` | addition | `a + b` | 13 | | `-` | subtraction | `a - b` | 13 | ```rux let a: int32 = 17; let b: int32 = 5; PrintLine("{} {} {} {} {} {}", a + b, a - b, a * b, a / b, a % b, -a); ``` This prints `22 12 85 3 2 -17`. Multiplication, division and remainder bind more tightly than addition and subtraction, and each level groups from the left — see [Precedence](https://rux-lang.dev/docs/lang/expressions/overview#precedence). ## Operand types Both operands must agree on a type, following the [operand rules](https://rux-lang.dev/docs/lang/expressions/overview#operand-types): one type, a literal that takes the other operand's type, or two integers of one signedness, where the narrower widens. The result has that type. An unsuffixed integer literal adapts only to another integer. Beside a floating-point value, write a floating-point literal: ```rux let half = 1.5 + 2; ``` ```text error: operator '+' cannot combine left operand 'float64' with right operand 'int' ``` Write `1.5 + 2.0`. A `bool` is not a number, and `flag + flag` is `error: operator '+' cannot combine left operand 'bool8' with right operand 'bool8'`. To compute with a character's code, convert it with [`as`](https://rux-lang.dev/docs/lang/expressions/casts) first, as in `(c as int32) - ('0' as int32)`. ## Integer overflow wraps Integer `+`, `-`, `*` and unary `-` wrap: a result that does not fit the type keeps its low bits, the two's-complement result, in every build profile. ```rux var top: int8 = int8::Max; top += 1; let small: uint8 = 0; let m: uint8 = 200; PrintLine("{} {} {}", top, small - 1, m * 2); ``` This prints `-128 255 144`. Negating an unsigned value wraps the same way. When overflow must be noticed instead, Core's `AddChecked`, `SubChecked` and `MulChecked` report it — see the Learn lessons [Wrapping arithmetic](https://rux-lang.dev/docs/learn/wrapping-arithmetic) and [Checked arithmetic](https://rux-lang.dev/docs/learn/checked-arithmetic). A literal is not allowed to wrap on its way in: `let narrow: uint8 = 0; narrow + 300` is `error: integer literal is out of range for type 'uint8'`. ## Integer division Integer `/` truncates towards zero, and `%` gives the remainder that goes with it, so it has the sign of the dividend: | Expression | Value | | ---------- | ----- | | `7 / 2` | `3` | | `-7 / 2` | `-3` | | `7 % 2` | `1` | | `-7 % 2` | `-1` | | `7 % -2` | `1` | Dividing by zero is never allowed to produce a value. Integer `/` and `%`, and the compound `/=` and `%=`, stop the program when the divisor is zero, on every target and in every build profile: ```rux func Divide(a: int32, b: int32) -> int32 { return a / b; } ``` ```text Panic: division by zero at Divide (Src/Main.rux:4:14) ``` The same happens to the one signed division whose quotient does not fit its type — the type's minimum divided by `-1` — which stops with `Panic: division overflow`. A divisor written as a non-zero literal needs no check, and a release build drops a check it can prove will pass. The panic is the same kind a call to `Panic` produces — see [Panics](https://rux-lang.dev/docs/lang/errors/panics). ## Floating-point arithmetic Floating-point arithmetic follows IEEE 754 at every width, from `float8` to `float512`. Division by zero does not stop the program; it gives an infinity, or NaN for `0.0 / 0.0`: ```rux PrintLine("{} {}", 1.0 / 0.0, 0.0 / 0.0); PrintLine("{} {}", 7.5 % 2.0, -7.5 / 2.0); ``` This prints `Inf NaN`, then `1.5 -3.75`. `%` on floating-point values is the remainder of truncated division, with the sign of the dividend. See [Floating-point types](https://rux-lang.dev/docs/lang/types/floating-point) for the special values and their comparisons. ## No power operator Rux has no exponentiation operator. `a ** b` is two operators, multiplication and a [dereference](https://rux-lang.dev/docs/lang/pointers/overview), `a * (*b)`, so with integers it fails: ```text error: operator '*' requires a pointer operand, but found 'int' ``` Use [`Pow`](https://rux-lang.dev/docs/api/math/powers#pow) from the Math package for floating-point powers, or a loop for small integer ones. There is no unary `+` either: `+5` does not parse. ## Compound assignment Each binary arithmetic operator has a compound form, `+=` `-=` `*=` `/=` `%=`, that updates a mutable place, and `++` and `--` add or subtract one — see [Assignment](https://rux-lang.dev/docs/lang/expressions/assignment). ## See also - [Integers](https://rux-lang.dev/docs/lang/types/integers) and [Floating-point types](https://rux-lang.dev/docs/lang/types/floating-point) — the types and their limits - [Casts](https://rux-lang.dev/docs/lang/expressions/casts) — converting between numeric types - [Comparison](https://rux-lang.dev/docs/lang/expressions/comparison) — relating the results - Learn: [Arithmetic](https://rux-lang.dev/docs/learn/arithmetic), [Wrapping arithmetic](https://rux-lang.dev/docs/learn/wrapping-arithmetic) # Comparison A comparison tests two values and produces a `bool`. | Operator | Test | Level | | -------- | --------------------- | ----- | | `<` | less than | 11 | | `<=` | less than or equal | 11 | | `>` | greater than | 11 | | `>=` | greater than or equal | 11 | | `==` | equal | 10 | | `!=` | not equal | 10 | ```rux let a = 10; let b = 20; PrintLine("{} {} {} {}", a == b, a != b, a < b, a >= b); ``` This prints `false true true false`. The ordering operators bind more tightly than `==` and `!=`, and all of them bind more tightly than `&&` and `||`, so `offset + length <= capacity && capacity != 0` needs no parentheses. ## Operand types Numbers compare under the same [operand rules](https://rux-lang.dev/docs/lang/expressions/overview#operand-types) as arithmetic: one type, a literal that takes the other operand's type, or two integers of one signedness, where the narrower widens. A signed and an unsigned integer have no common type: ```text error: operator '<' cannot compare left operand 'uint64' with right operand 'int64' note: the operands differ in signedness, so neither converts to the other's type help: convert one operand with 'as' to the type the operation should use ``` A literal must fit the other operand's type, so a test that could never be true is caught: with `count: uint64`, `count == -1` is `error: integer literal is out of range for type 'uint64'`. ## What can be compared | Type | `==` `!=` | `<` `<=` `>` `>=` | | --------------------------------- | --------------------------------------------------- | ------------------------------- | | integers, floating-point numbers | yes | yes | | characters | yes | yes, by code | | `bool` | yes | yes, `false` before `true` | | enums | yes | yes, by the members' values | | pointers | yes, and with `null` | yes, by address | | structures | yes, field by field, when every field supports `==` | only through declared operators | | tuples | yes, element by element | no | | fixed-size arrays | yes, element by element | no | | variants | yes, case and payload | no | | optionals, fallibles and sums | yes, between values of one type | no | | slices, including string literals | no | no | A structure, tuple or variant compares structurally only when every part can be compared. A structure gets ordering only from the operators it declares: `!=` is derived from a declared `==`, `>` from `<`, and `<=` and `>=` from `<` and `==` together — see [Operator interfaces](https://rux-lang.dev/docs/lang/interfaces/operators). Without them: ```text error: operator '<' is not defined for 'Point' note: a struct is compared through the operators it declares, never by its representation help: declare '<' on 'Point' ``` An optional compares with `none` and with a present value directly: `found == none`, `found == 5`. See [Optionals](https://rux-lang.dev/docs/lang/optionals/overview). A fixed-size array compares with an array literal directly, element by element: the literal takes the type of the other operand, so with `values: int32[2]` holding 1 and 2, `values == [1, 2]` is `true`. Arrays have no ordering: ```text error: operator '<' is not defined for array 'int32[2]' note: arrays have element-wise equality but no built-in ordering help: compare the elements in the order that defines it ``` ### Slices A [slice](https://rux-lang.dev/docs/lang/slices/overview) is a view of elements stored elsewhere. Comparing two views would compare the addresses they hold rather than the elements, so Rux refuses it — and a string literal is a `char8[..]` slice: ```rux let same = name == "Rux"; ``` ```text error: operator '==' is not defined for slice type 'char8[..]' note: a slice is a view, so comparing the views would compare addresses rather than elements ``` Compare the elements one at a time, or use a type that declares `==`, such as the Text package's `String`. ## Floating-point comparisons Floating-point comparisons follow IEEE 754. NaN is unordered: it is not equal to anything, itself included, and every ordering test with it is `false`: ```rux let n = float64::NaN; PrintLine("{} {} {}", n == n, n != n, n < 1.0); ``` This prints `false true false`. See [Floating-point types](https://rux-lang.dev/docs/lang/types/floating-point) for testing for NaN and for comparing computed values with a tolerance. ## Comparisons do not chain `a < b < c` is not a range test. It groups as `(a < b) < c`, which compares a `bool` with a number: ```rux let inside = 1 < 2 < 3; ``` ```text error: operator '<' cannot compare left operand 'bool8' with right operand 'int' ``` Combine two comparisons with [`&&`](https://rux-lang.dev/docs/lang/expressions/logical): `low <= value && value <= high`. ## See also - [Logical](https://rux-lang.dev/docs/lang/expressions/logical) — combining comparisons - [Casts](https://rux-lang.dev/docs/lang/expressions/casts) — matching operand types before comparing - [Operator interfaces](https://rux-lang.dev/docs/lang/interfaces/operators) — `==` and `<` for your own types - Learn: [Comparison](https://rux-lang.dev/docs/learn/comparison), [Equatable](https://rux-lang.dev/docs/learn/equatable), [Comparable](https://rux-lang.dev/docs/learn/comparable) # Logical The logical operators combine and invert `bool` values. | Operator | Operation | Result | Level | | -------- | --------- | ------------------------------------ | ----- | | `!` | not | `true` when the operand is `false` | 16 | | `&&` | and | `true` when both operands are `true` | 6 | | `||` | or | `true` when either operand is `true` | 5 | ```rux let isReady = true; let hasWork = false; PrintLine("{} {} {}", isReady && hasWork, isReady || hasWork, !isReady); ``` This prints `false true false`. ## bool operands only Every operand must be a `bool`. A number, a pointer or an optional is never treated as true or false; write the comparison you mean: ```rux let count: int32 = 3; let zero = !count; let both = count && true; ``` ```text error: operator '!' requires a bool operand, but found 'int32' error: operator '&&' requires a bool left operand, but found 'int32' ``` Write `count == 0` and `count != 0 && true`. The same rule applies to the conditions of `if`, `while` and the conditional operator. ## Short-circuit evaluation `&&` and `||` evaluate their left operand first and evaluate the right one only when it can still change the answer: | Expression | The right side runs when | | --------------- | ------------------------ | | `left && right` | `left` is `true` | | `left || right` | `left` is `false` | That makes it safe to guard a test with another one: ```rux if index < values.length && values[index] == target { PrintLine("found"); } ``` `values[index]` is read only after the bounds test has passed. A call on the right side is skipped the same way: ```rux let a = Check("left", false) && Check("right", true); ``` Only `left` is checked; `Check("right", true)` never runs. ## Precedence `!` is a prefix operator, so it applies only to the operand right after it: `!ready && busy` is `(!ready) && busy`, and `!count == 0` is `(!count) == 0`. Negate a larger expression by wrapping it, `!(ready && busy)`. `&&` binds more tightly than `||`, the way `*` binds more tightly than `+`: ```rux PrintLine("{}", true || false && false); ``` This is `true || (false && false)`, which prints `true`. Both bind more loosely than every comparison, so comparisons combine without parentheses. ## Non-short-circuiting forms The [bitwise](https://rux-lang.dev/docs/lang/expressions/bitwise) operators `&`, `|`, `^` and `~` also accept `bool` operands. `&` and `|` compute the same answer as `&&` and `||`, but always evaluate both sides, and `^` is exclusive or: ```rux let c = Check("left", false) & Check("right", true); PrintLine("{}", true ^ true); ``` Both checks run here. Use `&&` and `||` for conditions, and `&` or `|` only when the right side must run for its effect. ## See also - [Comparison](https://rux-lang.dev/docs/lang/expressions/comparison) — producing the `bool` operands - [Booleans](https://rux-lang.dev/docs/lang/types/booleans) — the `bool` types - [if](https://rux-lang.dev/docs/lang/statements/if) — conditions in statements - Learn: [Logical](https://rux-lang.dev/docs/learn/logical) # Bitwise The bitwise operators work on the individual bits of their operands. | Operator | Operation | Compound form | Level | | -------- | ------------ | ------------- | ----- | | `~` | not (prefix) | — | 16 | | `&` | and | `&=` | 9 | | `^` | exclusive or | `^=` | 8 | | `|` | or | `|=` | 7 | ```rux let a: uint8 = 0b00001100; let b: uint8 = 0b00001010; PrintLine("{} {} {} {}", a & b, a | b, a ^ b, ~a); ``` This prints `8 14 6 243`: the bits set in both, in either, in exactly one, and every bit of `a` inverted. ## Operand types | Operand | `&` `|` `^` | `~` | | ---------- | ---------------------------------------------- | ----------------- | | integers | bit by bit | inverts every bit | | `bool` | logical and, or, exclusive or — both sides run | logical not | | characters | bit by bit on the code | — | The two operands follow the [operand rules](https://rux-lang.dev/docs/lang/expressions/overview#operand-types): one type, a literal that takes the other operand's type, or two integers of one signedness, where the narrower widens. A floating-point operand is refused: ```text error: operator '&' requires an integer, bool, or character left operand, but found 'float64' error: operator '~' requires an integer or bool operand, but found 'float64' ``` Unsigned integers are the natural home for bit work, since none of their bits is a sign. On `bool`, `&` and `|` are the non-short-circuiting forms of `&&` and `||` — see [Logical](https://rux-lang.dev/docs/lang/expressions/logical#non-short-circuiting-forms). ## Precedence The binary bitwise operators bind **more loosely than the comparisons**, and among themselves `&` binds most tightly, then `^`, then `|`. A test of a masked value therefore needs parentheses: ```rux let x: int32 = 6; let even = x & 1 == 0; ``` This groups as `x & (1 == 0)`: ```text error: operator '&' cannot combine left operand 'int32' with right operand 'bool8' ``` Write `(x & 1) == 0`. Shifts and arithmetic bind more tightly than all three, so `flags & 1 << 2` is `flags & (1 << 2)`; parentheses still make it easier to read. ## Masks and flags With a [shift](https://rux-lang.dev/docs/lang/expressions/shift) to build the mask, the four single-bit operations are: ```rux var flags: uint32 = 0; flags |= 1 << 3; flags &= ~(1u32 << 3); flags ^= 1 << 2; let isSet = (flags & (1 << 2)) != 0; ``` `|=` sets bit 3, `&=` with the inverted mask clears it, `^=` toggles bit 2, and the last line tests it. The `1u32` in the clearing mask gives `~` a `uint32` to invert. With an unsuffixed `1`, `~(1 << 3)` is an `int`, and `flags &= ~(1 << 3)` is `error: operator '&=' cannot combine left operand 'uint32' with right operand 'int'`. ## Compound forms `&=`, `|=` and `^=` update a mutable place: `flags |= mask` is `flags = flags | mask`. The target must be a `var` or another writable place — see [Assignment](https://rux-lang.dev/docs/lang/expressions/assignment). ## See also - [Shift](https://rux-lang.dev/docs/lang/expressions/shift) — moving bits, and building masks - [Logical](https://rux-lang.dev/docs/lang/expressions/logical) — the short-circuiting `&&` and `||` - [Integers](https://rux-lang.dev/docs/lang/types/integers) — widths and signedness - Learn: [Bitwise](https://rux-lang.dev/docs/learn/bitwise), [Bit operation](https://rux-lang.dev/docs/learn/bit-operation) # Shift A shift moves every bit of an integer left or right by a number of places. Bits that move past the end are dropped, and new bits come in at the other end. | Operator | Operation | Compound form | Level | | -------- | ------------------------------------------------------ | ------------- | ----- | | `<<` | left shift: zeros come in at the bottom | `<<=` | 12 | | `>>` | right shift: arithmetic on signed, logical on unsigned | `>>=` | 12 | | `>>>` | logical right shift: zeros come in at the top | `>>>=` | 12 | ```rux let value: uint8 = 0b00010100; PrintLine("{} {}", value << 2, value >> 2); ``` This prints `80 5`. ## Operand types The left operand is an integer (or a character), and the result has its type: a shift never changes the width of the value being shifted. The right operand, the *count*, is any integer type. It keeps its own type and is not converted to the left operand's: ```rux let one: uint32 = 1; let count: uint8 = 5; PrintLine("{}", one << count); ``` This prints `32`, a `uint32`. A floating-point operand on either side is refused, with `error: operator '<<' requires an integer or character left operand, but found 'float64'` or `error: operator '<<' requires an integer right operand, but found 'float64'`. A left shift keeps only the bits that still fit. A `uint8` holding 200 shifted left by one is `144`, not 400: the top bit fell off. Shift a wider type when the result needs the room. ## Right shifts Shifting right empties the top bits, and there are two ways to fill them: | Left operand | `>>` fills with | `>>>` fills with | | ------------ | ----------------------------------- | ---------------- | | signed | copies of the sign bit (arithmetic) | zeros (logical) | | unsigned | zeros (logical) | — not allowed | ```rux let negative: int8 = -8; PrintLine("{} {}", negative >> 2, negative >>> 2); ``` This prints `-2 62`. The arithmetic shift keeps the sign and divides by four, rounding towards minus infinity — so `-7 >> 1` is `-4`, where `-7 / 2` is `-3`. The logical shift treats the value as plain bits. An unsigned `>>` is already logical, so `>>>` exists only for signed operands: ```text error: operator '>>>' requires a signed integer left operand, but found 'uint8' ``` ## The shift count A count must be at least zero and less than the bit width of the left operand: `0` to `31` for an `int32`, `0` to `7` for a `uint8`. Shifting by the full width or more does not produce a meaningful value; to clear a value, assign zero. A constant count outside that range is an error: ```rux let x: int32 = 1; let y = x << 32; ``` ```text error: shift count 32 is out of range for 'int32', which takes counts from 0 to 31 note: a '<<' by the width or more, or by a negative count, has no meaningful result help: to clear the value, assign zero ``` Any other count is checked when the program runs, and one out of range stops it with `Panic: shift count out of range`. A count masked below the width, such as `x << (n & 31)` on an `int32`, is always in range and is not checked. ## Precedence Shifts bind more loosely than `+` and `-` and more tightly than the comparisons and the bitwise operators: ```rux PrintLine("{}", 1 << 2 + 1); ``` This is `1 << (2 + 1)`, which prints `8`. Parenthesise a shift that builds a mask, as in `flags & (1 << n)`, even where precedence would already group it that way. ## Compound forms `<<=`, `>>=` and `>>>=` update a mutable place. Like `>>>`, `>>>=` needs a signed target: ```rux var bits: int32 = -16; bits >>>= 1; bits <<= 2; ``` ## Packing fields Shifts and [masks](https://rux-lang.dev/docs/lang/expressions/bitwise) together store several small fields in one integer. Each field is shifted into place and combined with `|`, and read back by shifting it down and masking off the rest: ```rux let red: uint32 = 0xFF; let green: uint32 = 0x80; let blue: uint32 = 0x20; let color = (red << 16) | (green << 8) | blue; let g = (color >> 8) & 0xFF; ``` ## See also - [Bitwise](https://rux-lang.dev/docs/lang/expressions/bitwise) — combining shifted masks - [Arithmetic](https://rux-lang.dev/docs/lang/expressions/arithmetic) — division and multiplication by powers of two - [Integers](https://rux-lang.dev/docs/lang/types/integers) — widths and signedness - Learn: [Shift](https://rux-lang.dev/docs/learn/shift) # Assignment An assignment stores a new value in a place that already exists — a `var`, a field, an element, or the target of a writable pointer. | Operator | Meaning | | ---------------------------------------- | ----------------------------------------------------------------------- | | `place = value` | copy `value` into `place` | | `place <- value` | move `value` into `place` | | `place += value`, `-=`, `*=`, `/=`, `%=` | `place = place + value`, and so on | | `place &= value`, `|=`, `^=` | the [bitwise](https://rux-lang.dev/docs/lang/expressions/bitwise) forms | | `place <<= value`, `>>=`, `>>>=` | the [shift](https://rux-lang.dev/docs/lang/expressions/shift) forms | | `place++`, `++place` | add one | | `place--`, `--place` | subtract one | ```rux var n: int32 = 10; n += 5; n -= 3; n *= 4; n /= 5; n %= 5; ``` Each line starts from the result of the one before: 15, 12, 48, 9, 4. ## The target The left side must be an assignable place: a variable, a field (`p.x`), a tuple element (`pair.0`), an indexed element (`values[i]`), or a dereferenced pointer (`*ptr`). And it must be mutable — a `var`, or something reached through one, a `&var` reference or a `*var` pointer: ```rux var p = Point { x: 1, y: 2 }; p.x += 10; p.y++; var values: int32[3] = [1, 2, 3]; values[1] *= 7; ``` | Target | Error | | --------------------------- | --------------------------------------------------------------------------------- | | a `let` | `cannot modify immutable variable 'fixed'` | | a constant | `cannot modify constant 'Limit'` | | a value that is not a place | `operator '=' requires an assignable target, but its left operand has type 'int'` | | through a read-only pointer | `cannot modify data through read-only pointer '*int'` | The error for a `let` comes with `help: declare 'fixed' with 'var' to make it mutable`. ## Type rules The value must have the place's type, or widen to it without loss — an integer of the same signedness and a smaller width, as in a [binding](https://rux-lang.dev/docs/lang/bindings/overview#types-and-inference). A compound assignment follows the rules of its operator, and its result must still fit the place: ```rux var total: int32 = 0; let big: int64 = 5; total += big; ``` ```text error: operator '+=' produces 'int64', which cannot be stored in target type 'int32' ``` `total += big as int32` converts first. Mixing kinds is refused just as the plain operator would refuse it: on an `int32`, `score += 1.5` is `error: operator '+=' cannot combine left operand 'int32' with right operand 'float64'`, and on a `uint8`, `u += 300` is `error: integer literal is out of range for type 'uint8'`. ## An assignment produces no value An assignment is a complete action, not a value. The grammar reads `a = b = c` from the right, as `a = (b = c)`, but `b = c` has nothing to give `a`: ```rux first = second = 7; ``` ```text error: an assignment produces no value and cannot be chained help: assign each target in its own statement ``` For the same reason `=` cannot stand in for `==` in a condition: `if a = 5 { … }` is refused, because the condition is not a `bool`. ## ++ and -- `++` adds one and `--` subtracts one. They apply to any integer or floating-point place, and need it to be mutable like any other assignment: on a `let`, `k++` is `error: cannot modify immutable variable 'k'`. On a line of its own, the prefix and postfix forms are the same. Used as a value, they differ in what they hand back: | Form | Value of the expression | Afterwards | | --------- | ----------------------- | ---------- | | `count++` | the old value | one higher | | `++count` | the new value | one higher | | `count--` | the old value | one lower | | `--count` | the new value | one lower | ```rux var count: int32 = 1; let before = count++; let after = ++count; PrintLine("{} {} {}", before, after, count); ``` This prints `1 3 3`. Code that leans on the difference is easy to misread; most Rux code keeps `++` and `--` on lines of their own. Rux has no unary `+`, so `a =+ 3` does not parse; and `a =- 3` is `a = -3`, a valid assignment of minus three. The operator always comes before the `=`. ## Moving with <- `place <- value` moves instead of copying: the value is handed over and its source may not be read again. The place's old value is destroyed as it is replaced, just as with `=`: ```rux let first = Buffer { size: 4 }; var second = Buffer { size: 0 }; second <- first; ``` Reading `first` afterwards is `error: value 'first' is used after it was moved`. A type that cannot be copied is assigned from a named source only with `<-`. When copy and move apply, and what replacing a value destroys, are covered in [Copy and move](https://rux-lang.dev/docs/lang/ownership/copy-and-move). ## See also - [Bindings](https://rux-lang.dev/docs/lang/bindings/overview) — declaring the places that are assigned to - [Initialization](https://rux-lang.dev/docs/lang/bindings/initialization) — the first assignment of a `var` declared without a value - [Arithmetic](https://rux-lang.dev/docs/lang/expressions/arithmetic) — the operators inside the compound forms - [Copy and move](https://rux-lang.dev/docs/lang/ownership/copy-and-move) — `=` and `<-` - Learn: [Assignment](https://rux-lang.dev/docs/learn/assignment) # Conditional The conditional operator chooses one of two values by a condition. It is the only operator with three operands, and is often called the *ternary* operator. ```text conditional = condition "?" then-value ":" else-value then-value = an expression above level 3, or a parenthesised conditional else-value = an expression above level 3, or another conditional ``` ```rux let label = n % 2 == 0 ? "even" : "odd"; ``` When the condition is `true` the result is the first value, otherwise the second. Only the chosen value is evaluated; the other is skipped, just as an untaken `if` block is. ## The space before ? A `?` written directly after an expression is postfix [propagation](https://rux-lang.dev/docs/lang/errors/propagation): `Read()?` passes a failure on. The conditional's `?` is told apart by the whitespace in front of it, so it must not touch the condition: ```rux let a = n > 0 ? 1 : 2; let b = n > 0? 1 : 2; ``` The first line is a conditional. In the second, `0?` is a propagation of `0`, and the line fails to parse with `error: expected ';' after the binding declaration before '1'`. The space after the `?` does not matter, but write one for symmetry. ## The condition The condition must be a `bool`. A number is not true or false by itself: ```text error: condition for '?:' must have type 'bool', but found 'int32' ``` Write the comparison: `n % 2 != 0 ? "odd" : "even"`. ## Branch types The conditional produces one value, so its two branches must have one type. The second converts to the first or the first to the second, as two `match` arms do; two unrelated types are an error: ```rux let answer = ready ? "yes" : 7; ``` ```text error: conditional branch type mismatch: expected 'char8[..]', found 'int' help: make both branches produce the same type ``` Where the context fixes the type — an annotated binding, an assignment, a `return`, a call argument — both branches take it, and an unsuffixed literal in either branch must fit it: ```rux let wide: uint128 = n > 2 ? 18446744073709551616 : 0; ``` A branch that never produces a value, such as a call to `Panic`, does not take part: ```rux func Checked(n: int32) -> int32 { return n >= 0 ? n : Panic("negative"); } ``` `return`, `fail`, `break` and `continue` cannot be a branch — `error: 'return' cannot be used as a value here`. Use an `if`, or the fallback of [`??`](https://rux-lang.dev/docs/lang/optionals/coalescing), which accepts them. ## Nesting The conditional groups from the right, so a chain in the else branch reads as a list of cases tested in order: ```rux let sign = n < 0 ? "negative" : n == 0 ? "zero" : "positive"; ``` A conditional in the **then** branch must be in parentheses. The then branch ends at the first `:`, and an unparenthesised `?` inside it stops the parse with `error: expected ':' between the conditional expression branches before '?'`: ```rux let size = n > 0 ? (n > 5 ? "big" : "small") : "none"; ``` Past two or three cases, an `if`/`else if` chain or a [`match`](https://rux-lang.dev/docs/lang/patterns/match) expression reads better. ## Precedence The conditional is on [level 3](https://rux-lang.dev/docs/lang/expressions/overview#precedence), below every operator but ranges and assignment. Its condition takes in everything before the `?`, including `||` and `??`: ```rux let total = price - (member ? 5 : 0); ``` Without the parentheses, `price - member ? 5 : 0` would subtract a `bool` from `price` and use the result as the condition. Wrap a conditional whenever it sits inside a larger expression. ## See also - [if](https://rux-lang.dev/docs/lang/statements/if) — choosing between statements rather than values - [match](https://rux-lang.dev/docs/lang/patterns/match) — choosing among many values - [Propagation](https://rux-lang.dev/docs/lang/errors/propagation) — the postfix `?` - Learn: [Ternary](https://rux-lang.dev/docs/learn/ternary) # Casts Rux converts a value to another type only when asked. The `as` operator is the request: ```text cast = operand "as" type ``` ```rux let ratio = count as float64 / total as float64; ``` The right side is a type, not an expression. It is a *postfix* type — a name with any `?`, `[]`, `[N]` or `[..]` suffixes — so a sum or fallible target must be grouped: `value as (T ! E)`. Writing `f as int32 ! bool` is `error: a fallible type after 'as' must be grouped`. `as` is on [level 15](https://rux-lang.dev/docs/lang/expressions/overview#precedence), above every binary operator and below the prefix ones. It converts only the operand next to it: `a / b as float64` converts `b` alone, while `-x as int64` is `(-x) as int64`. ## What converts | From | To | Result | | ------------------------- | ------------------------------ | ------------------------------------------------------------------- | | an integer | an integer | the low bits, reinterpreted in the new type | | an integer | a floating-point type | the nearest representable value | | a floating-point type | an integer | truncated towards zero, saturating at the type's limits; NaN is `0` | | a floating-point type | a floating-point type | the nearest representable value, ties to even | | a number | `bool` | `true` when the value is not zero; NaN is `true`, `-0.0` is `false` | | `bool` | a number | `1` or `0` | | `bool` | another `bool` width | the same truth value | | a character or an integer | a character or an integer | the code, as a number, or the number, as a code | | an enum | an integer | the member's value | | an integer | an enum | the member with that value — not checked | | a pointer | a pointer, integer or function | see [Pointers](https://rux-lang.dev/docs/lang/pointers/overview) | ```rux let big: int32 = 300; PrintLine("{} {} {}", big as uint8, -1i32 as uint32, 200u8 as int8); ``` This prints `44 4294967295 -56`. An integer conversion never saturates and never fails: it keeps the bits that fit. ## Floating-point to integer A float converts to an integer by truncating towards zero while the result fits. A value beyond the range saturates — one above `T::Max`, positive infinity included, becomes `T::Max`, and one below `T::Min` becomes `T::Min` — and NaN becomes `0`. The rule is the same for every float width from `float8` to `float512` and every integer width, on every target, and whether the compiler folds the cast or it runs: ```rux PrintLine("{} {} {} {}", 3.99 as int32, -3.99 as int32, 1e20 as int32, -1e20 as int32); PrintLine("{} {}", -5.0 as uint8, float64::NaN as int32); ``` This prints `3 -3 2147483647 -2147483648`, then `0 0`: a negative value converts to `0` for an unsigned type. ## bool Any number converts to `bool` by testing it against zero, and a `bool` converts to `1` or `0`: ```rux PrintLine("{} {} {}", 5 as bool, 0 as bool, true as int32); ``` This prints `true false 1`. Where the intent is a test, a comparison says it more plainly: `n != 0`. ## Characters A character converts to its code, and an integer to the character with that code: ```rux PrintLine("{} {} {}", 'A' as int32, 66 as char32, 'λ' as uint32); ``` This prints `65 B 955`. Between character widths, the code is kept, and a code a narrower target cannot hold stops the program with `Panic: invalid character cast` rather than keeping its low bits; mask an integer first to keep its low bits on purpose. A constant is checked against the target's range, at every width from `char8` to `char512` and for integer constants of any width: a code that cannot exist is refused rather than wrapped. | Cast | Error | | ---------------------------------------- | ------------------------------------------------------------------------------ | | `0x110000 as char32` | `constant cast from 'int' to 'char32' is outside the target type's range` | | `-1 as char32` | `constant cast from 'int' to 'char32' is outside the target type's range` | | `300 as char8` | `constant cast from 'int' to 'char8' is outside the target type's range` | | `0xD800 as char32` | `cast from 'int' to 'char32' uses invalid surrogate code point U+D800` | | `0x1_0000_0000_0000_0041u128 as char128` | `constant cast from 'uint128' to 'char128' is outside the target type's range` | See [Characters](https://rux-lang.dev/docs/lang/types/characters) for what each width holds. ## Enums An enum member converts to the integer it stands for, and an integer back to a member: ```rux enum Level: uint8 { Low = 1, Mid = 5, High = 9 } ``` ```rux PrintLine("{}", Level::Mid as int32); let raw: uint8 = 9; let level = raw as Level; ``` The conversion from an integer is not checked. A number that is no member's value gives a value that equals no member, so convert only numbers known to be valid, or test with a [`match`](https://rux-lang.dev/docs/lang/patterns/match) on the integer first. One enum does not convert to another: `Level::Low as Other` is `error: cannot cast enum 'Level' directly to unrelated enum 'Other'`. Go through an integer when that is really meant. ## What does not convert `as` converts scalars. Text, structures, tuples, arrays and variants have no cast: ```text error: cannot cast value of type 'char8[..]' to 'int' error: cannot cast value of type 'Point' to 'int64' error: cannot cast variant 'Shape' to scalar type 'int32' ``` Parsing text into a number is a function call, not a cast — see Learn: [Parse](https://rux-lang.dev/docs/learn/parse). Building a value of another type from this one is a [constructor](https://rux-lang.dev/docs/lang/structs/constructors). A [sum](https://rux-lang.dev/docs/lang/sums/overview) is not narrowed with `as` either: `value as int32` on an `int32 | bool` is `error: cannot cast value of type 'bool8 | int32' to 'int32'`. Test the member with [`is`](https://rux-lang.dev/docs/lang/sums/type-tests), and reach the value with a [typed pattern](https://rux-lang.dev/docs/lang/patterns/patterns#typed-patterns). ## See also - [Expressions](https://rux-lang.dev/docs/lang/expressions/overview#operand-types) — the conversions Rux does without `as` - [Integers](https://rux-lang.dev/docs/lang/types/integers), [Floating-point types](https://rux-lang.dev/docs/lang/types/floating-point), [Characters](https://rux-lang.dev/docs/lang/types/characters) — the types converted between - [Enums](https://rux-lang.dev/docs/lang/enums/overview) — member values - Learn: [Convert](https://rux-lang.dev/docs/learn/convert), [Checked convert](https://rux-lang.dev/docs/learn/checked-convert) # Statements A function body is a block: a sequence of statements between `{` and `}`, run in order. Every statement is one of these: | Statement | Form | Page | | ---------------------------------- | -------------------------- | ------------------------------------------------------------------------------ | | Binding | `let x = …;` `var x = …;` | [Bindings](https://rux-lang.dev/docs/lang/bindings/overview) | | Constant | `const X = …;` | [Constants](https://rux-lang.dev/docs/lang/bindings/constants) | | Expression | `expression;` | below | | `if` | `if c { … } else { … }` | [if](https://rux-lang.dev/docs/lang/statements/if) | | `when` | `when c { … }` | [Conditional compilation](https://rux-lang.dev/docs/lang/comptime/conditional) | | `match` | `match v { … }` | [match](https://rux-lang.dev/docs/lang/patterns/match) | | `while`, `do while`, `loop`, `for` | `while c { … }` … | [Loops](https://rux-lang.dev/docs/lang/statements/loops) | | `break`, `continue` | `break;` `continue label;` | [break and continue](https://rux-lang.dev/docs/lang/statements/break-continue) | | `return` | `return value;` | [return](https://rux-lang.dev/docs/lang/statements/return) | | `fail` | `fail error;` | [Errors](https://rux-lang.dev/docs/lang/errors/overview) | | `defer` | `defer statement` | [defer](https://rux-lang.dev/docs/lang/ownership/defer) | ## Expression statements An expression followed by `;` is a statement, run for its effect: a call, an assignment, an increment. ```rux PrintLine("hello"); total += price; count++; ``` The `;` is required. When something else follows a complete expression, the compiler names it: `error: expected ';' after expression, but found ':'`. A call to a [fallible](https://rux-lang.dev/docs/lang/errors/overview) function cannot be a bare statement, because its failure would be lost; handle it with `?`, `catch` or `match`. A `match` at the start of a statement is a `match` statement; to use a match's value there, bind it or wrap it in parentheses. ## Blocks are bodies Braces appear only as the body of something — a function, an `if` branch, a loop, a `match` arm. A block on its own is not a statement: ```rux let x = 1; { let y = 2; } ``` ```text error: expected an expression before '{' ``` A body is always a block, even when it holds one statement: `if ready return 1;` is `error: expected '{' to start the 'if' body before 'return'`. A value that needs a few statements to compute belongs in a function, or in a `match` arm. ## Conditions `if`, `while`, `do while` and the conditional operator test a condition, and every condition follows the same rules. **It is a `bool`.** A number, a pointer or an optional is never true or false by itself: ```rux let count: int32 = 3; if count { } ``` ```text error: condition for 'if' must have type 'bool', but found 'int32' ``` Write the test: `if count != 0`. **It needs no parentheses.** `if count > 0 { … }` is the usual form. Parentheses are allowed, as around any expression, but add nothing: `if (count > 0) { … }` means the same. **A structure literal inside it is parenthesised.** After `if`, `while`, `for … in`, `match` and `when`, the first `{` that could start the body does start the body. So `Point { x: 1, y: 2 }` cannot appear bare in a condition — its brace would be taken as the body: ```rux if p == (Point { x: 1, y: 2 }) { PrintLine("at the start"); } ``` Without the parentheses the compiler reports `error: expected ';' after expression, but found ':'` at the first field. A structure literal inside a call's argument list needs no extra parentheses, since the call's own parentheses already enclose it. ## See also - [if](https://rux-lang.dev/docs/lang/statements/if), [Loops](https://rux-lang.dev/docs/lang/statements/loops), [break and continue](https://rux-lang.dev/docs/lang/statements/break-continue), [return](https://rux-lang.dev/docs/lang/statements/return) - [match](https://rux-lang.dev/docs/lang/patterns/match) — choosing by the shape of a value - [Expressions](https://rux-lang.dev/docs/lang/expressions/overview) — what statements are built from - Learn: [Control flow](https://rux-lang.dev/docs/learn/control-flow) # if `if` runs a block when a condition is `true`. `else if` tests further conditions in turn, and a final `else` runs when none of them held. The first branch whose condition is `true` runs, and the rest are skipped. ```text if-statement = "if" condition block { "else" "if" condition block } [ "else" block ] ``` ```rux if x > 0 { PrintLine("positive"); } else if x < 0 { PrintLine("negative"); } else { PrintLine("zero"); } ``` ## The condition The condition is a `bool`, written without parentheses, and a structure literal inside it is wrapped in parentheses — the rules every condition follows, set out in [Statements](https://rux-lang.dev/docs/lang/statements/overview#conditions). Combine tests with the [logical operators](https://rux-lang.dev/docs/lang/expressions/logical): ```rux if age >= 18 && hasTicket { Admit(); } ``` A [type test](https://rux-lang.dev/docs/lang/sums/type-tests) is a `bool` too, so `if shape is Circle { … }` reads naturally. ## Bodies Every branch is a block, even for a single statement, and the braces are what end the condition. A binding declared in a branch lasts until that branch's closing brace. ## if is not an expression `if` chooses between statements; it does not produce a value, so `let s = if ready { 1 } else { 2 };` does not parse. To choose a value, use the [conditional operator](https://rux-lang.dev/docs/lang/expressions/conditional) or a [`match`](https://rux-lang.dev/docs/lang/patterns/match) expression: ```rux let label = count == 1 ? "item" : "items"; let size = match count { 0 => "none", 1 => "one", else => "many" }; ``` Or declare a `var` and assign it in each branch; the compiler checks that every branch does — see [Initialization](https://rux-lang.dev/docs/lang/bindings/initialization). ## if and when `when` has the same shape as `if` but is decided by the compiler, which keeps only the branch it selects — see [Conditional compilation](https://rux-lang.dev/docs/lang/comptime/conditional). A chain keeps the keyword it starts with: ```text error: expected 'if' after 'else' in a run-time 'if' chain; 'when' is the compile-time conditional ``` ## See also - [Statements](https://rux-lang.dev/docs/lang/statements/overview) — the rules every condition follows - [Conditional](https://rux-lang.dev/docs/lang/expressions/conditional) — choosing between two values - [match](https://rux-lang.dev/docs/lang/patterns/match) — choosing by the shape of a value - Learn: [If](https://rux-lang.dev/docs/learn/if), [Else if](https://rux-lang.dev/docs/learn/else-if) # Loops Rux has four loops. Each runs a block repeatedly; they differ in when, or whether, they test a condition. | Loop | Tests | The body runs | | ------------------- | ------------------------- | --------------------------- | | `while c { … }` | before each pass | zero or more times | | `do { … } while c;` | after each pass | at least once | | `loop { … }` | never | until a `break` or `return` | | `for x in s { … }` | for a next element of `s` | once per element | ```text while-loop = [label ":"] "while" condition block do-while = [label ":"] "do" block "while" condition ";" loop = [label ":"] "loop" block for-loop = [label ":"] "for" Name "in" expression block ``` Any loop may carry a label, so that a `break` or `continue` inside a nested loop can name it — see [break and continue](https://rux-lang.dev/docs/lang/statements/break-continue). Conditions follow the rules in [Statements](https://rux-lang.dev/docs/lang/statements/overview#conditions): a `bool`, no parentheses needed, a structure literal wrapped in parentheses. ## while `while` tests its condition before every pass, including the first, so the body may never run: ```rux var i = 0; while i < 3 { PrintLine("{}", i); i++; } ``` ## do while `do … while` runs the body first and tests afterwards, so the body always runs at least once. The statement ends with `;`: ```rux var tries = 5; do { tries--; } while tries > 10; ``` The condition is false from the start, but `tries` is still decremented once, to 4. A `continue` in the body goes straight to the test. ## loop `loop` repeats until something leaves it — a [`break`](https://rux-lang.dev/docs/lang/statements/break-continue), a [`return`](https://rux-lang.dev/docs/lang/statements/return), a `fail`, or a panic. It says "until I stop it" more directly than `while true`: ```rux var n = 0; loop { n += 1; if n == 4 { break; } } ``` ## for `for` runs its body once for each element of a sequence, binding the element to the loop variable: ```rux let values = [10, 20, 30]; for v in values { PrintLine("{}", v); } ``` The subject is evaluated once, before the first pass. What `for` can iterate: | Subject | Elements | | ------------------------------------- | --------------------------------------------------------- | | a fixed-size array `T[N]` | each element, in order | | a slice `T[..]` | each element, in order | | a string literal or other `char8[..]` | each `char8` code unit — a byte of UTF-8, not a character | | a range `a..b`, `a..=b`, `a...b` | each integer from `a`, up to `b` exclusive or inclusive | | an open range `a..` | each integer from `a`, until the loop is left | | a type with an iterator | each value its iterator's `Next` returns | ```rux for k in 0..3 { Print("{} ", k); } for k in 0..=3 { Print("{} ", k); } ``` This prints `0 1 2 0 1 2 3`. A range whose start is past its end runs zero times. When both ends are constants, the compiler catches it instead: `for k in 5..2` is `error: range start cannot be greater than its end`. See [Ranges](https://rux-lang.dev/docs/lang/ranges/overview). Any other type is iterated through the iterator convention: a container declares a parameterless `Iterate` returning an iterator, and the iterator declares `func Next(self: &var Iterator) -> Item?`. Each pass calls `Next` once; a present result is the element, and `none` ends the loop. See [Iteration](https://rux-lang.dev/docs/lang/interfaces/iteration). ```rux for left in countdown { Print("{} ", left); } ``` A type with neither is refused: ```text error: cannot iterate over 'int' help: iterate an array, a slice, a range, or a type declaring 'Next' or 'Iterate' ``` ### The loop variable The loop variable is a single name, fresh on every pass and immutable: `i = 10;` inside `for i in 0..3` is `error: cannot modify immutable variable 'i'`. It cannot be declared `var`, and it cannot be a pattern — `for (a, b) in pairs` does not parse. Bind a mutable copy or take an element apart inside the body: ```rux for pair in pairs { let (a, b) = pair; PrintLine("{} {}", a, b); } ``` Over an array or a slice, each pass gets a copy of its element, made the way the element's type copies — through its own `=` for a `String` — and destroyed at the end of the pass, so the sequence keeps its elements. A [move-only](https://rux-lang.dev/docs/lang/ownership/copy-and-move) element cannot be copied, so a direct loop over one is refused; loop over the indices and borrow each element in place: ```text error: 'for' cannot copy elements of move-only type 'Handle' out of 'Handle[..]' note: a direct loop over an array or a slice gives each pass a copy of its element help: loop over the indices and borrow each element in place ``` ## Moving inside a loop A loop body runs again from where its last pass ended, so a value one pass moves out is not there for the next. Moving an outer variable inside a loop is an error unless the same pass gives it a new value before the loop repeats, or leaves the loop after the move: ```rux for i in 0..3 { Consume(<- buffer); } ``` ```text error: value 'buffer' may have been moved on some control-flow paths ``` The loop variable, and bindings declared inside the body, are new on every pass and may be moved freely. See [Copy and move](https://rux-lang.dev/docs/lang/ownership/copy-and-move). ## See also - [break and continue](https://rux-lang.dev/docs/lang/statements/break-continue) — leaving a loop early, and labels - [Ranges](https://rux-lang.dev/docs/lang/ranges/overview) — the values `for` counts through - [Iteration](https://rux-lang.dev/docs/lang/interfaces/iteration) — making a type iterable - [Arrays](https://rux-lang.dev/docs/lang/arrays/overview) and [Slices](https://rux-lang.dev/docs/lang/slices/overview) — the sequences `for` walks - Learn: [While](https://rux-lang.dev/docs/learn/while), [Do while](https://rux-lang.dev/docs/learn/do-while), [Loop](https://rux-lang.dev/docs/learn/loop), [For](https://rux-lang.dev/docs/learn/for), [Iterator](https://rux-lang.dev/docs/learn/iterator) # break and continue `break` leaves a loop at once. `continue` ends the current pass and moves on to the next one. ```text break-statement = "break" [label] ";" continue-statement = "continue" [label] ";" ``` | Statement | In `while` and `loop` | In `do while` | In `for` | | ---------- | -------------------------------------------------------- | --------------------- | ------------------------- | | `break` | leaves the loop | leaves the loop | leaves the loop | | `continue` | goes back to the condition (`while`) or the top (`loop`) | goes to the condition | moves to the next element | ```rux for v in values { if v == 0 { break; } if v < 0 { continue; } sum += v; } ``` Without a label, both act on the innermost loop around them. Outside every loop they are errors: `error: 'break' can only be used inside 'while', 'for', or 'loop'`, and the same for `continue`. `break` takes no value; a loop does not produce one. ## Labels A label names a loop. It is written before the loop keyword, followed by `:`, and any of the four loops may carry one: ```rux outer: for row in 0..3 { for col in 0..3 { if col == 2 { continue outer; } if row == 2 { break outer; } Print("({} {}) ", row, col); } } ``` `continue outer` abandons the inner loop and starts the next pass of `outer`; `break outer` leaves both. This prints `(0 0) (0 1) (1 0) (1 1)`. A label names exactly one loop at a time. An inner loop may not reuse the label of a loop around it, because `break outer` inside it would then read as either one: ```text error: loop label 'outer' shadows an enclosing loop label help: give the inner loop a different label ``` Loops that follow one another, rather than nest, may reuse a label. A label must belong to a loop that encloses the statement: `continue missing;` is `error: 'continue' refers to unknown loop label 'missing'`. Only loops take labels. ## Inside expressions `break` and `continue`, with or without a label, may also stand where an expression would leave rather than produce a value: as a whole `match` arm, or as the fallback of [`??`](https://rux-lang.dev/docs/lang/optionals/coalescing): ```rux for v in values { let step = match v { 0 => break, -1 => continue, else => v }; sum += step; } ``` ```rux for v in values { let x = maybe ?? continue; PrintLine("{}", x); } ``` They cannot be used as an ordinary value: `n > 0 ? n : break` is `error: 'break' cannot be used as a value here`. ## See also - [Loops](https://rux-lang.dev/docs/lang/statements/loops) — the four loops - [return](https://rux-lang.dev/docs/lang/statements/return) — leaving the whole function - [Coalescing](https://rux-lang.dev/docs/lang/optionals/coalescing) — `?? break` and `?? continue` - Learn: [Break](https://rux-lang.dev/docs/learn/break), [Continue](https://rux-lang.dev/docs/learn/continue), [Label](https://rux-lang.dev/docs/learn/label) # return `return` ends the function it is in and hands a value back to the caller. ```text return-statement = "return" [expression] ";" ``` ```rux func Sign(n: int32) -> int32 { if n < 0 { return -1; } match n { 0 => return 0, else => return 1 } } ``` ## With and without a value A function with a return type returns a value of that type; one without a return type returns with a bare `return;`, or simply by reaching the end of its body: ```rux func Log(message: char8[..]) { if message.length == 0 { return; } PrintLine("{}", message); } ``` | Mistake | Error | | ------------------------------------------- | ---------------------------------------------------------------- | | a value of the wrong type | `'return' value must have type 'int', but found 'char8[..]'` | | a value from a function with no return type | `'return' cannot have a value in a function with no return type` | | no value from a function with a return type | `'return' requires a value of type 'int'` | The value takes its type from the function the way an annotated binding does: an unsuffixed literal takes the return type, and a narrower integer widens to it. In a [fallible](https://rux-lang.dev/docs/lang/errors/overview) function, `return value;` is the success and `fail error;` the failure. ## Every path returns A function with a return type must return on every path through its body. The compiler follows each branch, and one that can reach the closing brace is an error: ```rux func Positive(x: int) -> int { if x > 0 { return 1; } } ``` ```text error: function 'Positive' must return a value of type 'int' on every control-flow path ``` A path that cannot continue counts as finished: a `match` whose every arm returns, a `loop` with no `break`, a call to `Panic` or to any function marked [`#NoReturn()`](https://rux-lang.dev/docs/lang/attributes/noreturn): ```rux func Day(n: uint) -> char8[..] { if n < 7 { return "weekday"; } Panic("no such day"); } ``` ## Returning a move-only value `return name;` copies `name` into the result, like any other use by value. A type that cannot be copied is handed out with `<-`: ```rux func Pass(token: Token) -> Token { return <- token; } ``` Without the `<-`: ```text error: move-only value 'token' requires an explicit '<-' in return note: plain by-value use copies its source, but 'Token' prohibits copying help: prefix the return value with '<-', as in 'return <-token' ``` A freshly made value, such as a structure literal or the result of a call, needs no `<-`. See [Copy and move](https://rux-lang.dev/docs/lang/ownership/copy-and-move). ## return and defer `return value;` evaluates `value` exactly once, then runs the function's deferred statements, newest first, and only then leaves. Changes a deferred statement makes to a local after that point do not alter the value already captured. See [defer](https://rux-lang.dev/docs/lang/ownership/defer). ## Inside expressions `return`, with or without a value, may also stand where an expression would leave rather than produce one: as a whole `match` arm, as the fallback of [`??`](https://rux-lang.dev/docs/lang/optionals/coalescing), or in an error mapping: ```rux func First(values: int32[..]) -> int32 { let found: int32? = values.length > 0 ? .Some(values[0]) : none; let v = found ?? return -1; return v; } ``` Anywhere else it is `error: 'return' cannot be used as a value here`. ## See also - [Functions](https://rux-lang.dev/docs/lang/functions/declaration) — return types - [main](https://rux-lang.dev/docs/lang/functions/main) — what `Main` returns to the operating system - [Errors](https://rux-lang.dev/docs/lang/errors/overview) — `fail`, the other way out of a fallible function - [defer](https://rux-lang.dev/docs/lang/ownership/defer) — what runs on the way out - Learn: [Return](https://rux-lang.dev/docs/learn/return) # match `match` compares a value, the *subject*, against a list of [patterns](https://rux-lang.dev/docs/lang/patterns/patterns) and runs the first arm whose pattern fits. It is both a statement and an expression. ```text match = "match" subject "{" arm { "," arm } "}" arm = pattern "=>" body | "else" "=>" body body = expression | block | "return" [expression] | "fail" expression | "break" [label] | "continue" [label] ``` ```rux match status { 200 => PrintLine("OK"), 404 => PrintLine("Not Found"), else => PrintLine("Unknown") } ``` ## Arms Each arm is a pattern, `=>`, and a body. Arms are separated by commas, block arms included, and the last arm takes **no** trailing comma: ```text error: trailing comma is not allowed in match blocks ``` The arms are tried from the top, and the first whose pattern fits — and whose [guard](https://rux-lang.dev/docs/lang/patterns/patterns#guards), if it has one, is `true` — is the one that runs. No other arm runs, and nothing falls through. `else` is the default arm. It matches whatever no earlier arm did, and must come last: an arm after it can never be reached, which is `error: match arm is unreachable because an earlier pattern matches every value`. `_` is a pattern, not a default, so `_ =>` as a whole arm is `error: use 'else' for the default match arm`. Two arms with the same pattern are refused rather than one silently hiding the other: `error: duplicate pattern in match`. A runtime arm takes one pattern; several values that share an outcome are written as separate arms, or as a [range](https://rux-lang.dev/docs/lang/patterns/patterns#range-patterns) or a guard. ## The subject The subject is any expression and is evaluated exactly once, before the first arm is tried. Like a condition, it ends at the first `{` that could open the arms, so a structure literal subject is parenthesised: `match (Point { x: 0, y: 0 }) { … }`. A match normally only reads its subject. Written `match <- value { … }`, it takes the value over, so that its arms can move the parts they bind — see [Copy and move](https://rux-lang.dev/docs/lang/ownership/copy-and-move). ## Arm bodies | Body | Use | | ------------------------------------- | --------------------------------------------- | | an expression | the arm's value, or a call run for its effect | | a block `{ … }` | several statements, in a match statement | | `return`, `fail`, `break`, `continue` | leave the function or loop from this arm | ```rux match Direction::East { .North => { effect = 1; }, .East => { effect = 2; }, else => {} } ``` ## Statement and expression A `match` at the start of a statement is a **statement**: its arms run for their effect, and it produces no value. Anywhere else — after `=`, after `return`, as an argument — it is an **expression**, and every arm produces the match's value: ```rux let label = match status { 200 => "OK", 404 => "Not Found", else => "Unknown" }; ``` The arms of a match expression must agree on a type, as the branches of a [conditional](https://rux-lang.dev/docs/lang/expressions/conditional) do: ```text error: match arm type mismatch: expected 'char8[..]', found 'int' ``` An arm that leaves — `return`, `fail`, `break`, `continue`, or a call that never returns, such as `Panic` — produces no value and does not take part. Where the context fixes the type, such as an annotated binding or a return, every arm takes it: an unsuffixed literal in an arm must fit it, and `none`, `.Success(…)` and `.Failure(…)` arms are completed by it. See [Optionals](https://rux-lang.dev/docs/lang/optionals/overview) and [Errors](https://rux-lang.dev/docs/lang/errors/handling). A statement cannot be followed by a postfix operator: `match … { … } catch { … }` at the start of a statement is an error. To use the value of a match there, bind it, or wrap the match in parentheses. ## Exhaustiveness A match must not meet a value that no arm accepts. How strictly that is checked depends on the subject's type, and on whether the match is a statement or an expression: | Subject | Covered by | Statement must cover | Expression must cover | | ------------------------------------------------------------- | ---------------------------------------------------------- | -------------------- | --------------------- | | an [enum](https://rux-lang.dev/docs/lang/enums/overview) | an arm per member | yes | yes | | a [variant](https://rux-lang.dev/docs/lang/variants/matching) | an arm per case | yes | yes | | an optional, a fallible or a sum | every level: `none` and present, each channel, each member | yes | yes | | `bool` | a `true` arm and a `false` arm | no | yes | | a tuple | every combination of its elements | no | yes | | an integer, a floating-point number or a character | `else`, or an arm that binds every value | no | yes | | a structure | an arm whose field patterns are all irrefutable, or `else` | no | yes | A missing case is reported by name: ```text error: match on 'Color' is not exhaustive; missing Color::Blue error: match on 'bool8' is not exhaustive; missing false error: match on '(bool8, bool8)' is not exhaustive; missing (true, false) error: match on 'int32?' is not exhaustive; missing none error: match on 'int32' is not exhaustive; its arms do not cover every value ``` Two rules make coverage predictable: - **A guarded arm covers nothing**, because its guard might be `false`. `true => …, false if ready => …` still lacks an unguarded `false`. - **Ranges never replace `else`** for a number. A value-producing match on an integer ends with `else`, even when its ranges happen to reach every value. `else` is allowed on an enum or variant too, but it is a promise made on behalf of cases that do not exist yet: add a case later, and every match that names its cases one by one stops compiling at the spot that needs a decision, while one ending in `else` quietly gives the new case the default answer. A match expression on a character, a floating-point number or a structure is checked the same way: one with no `else` whose arms leave values out is `match on 'char32' is not exhaustive; its arms do not cover every value`, with `help: add an 'else' arm`. ## See also - [Patterns](https://rux-lang.dev/docs/lang/patterns/patterns) — every pattern an arm can use - [Variants](https://rux-lang.dev/docs/lang/variants/matching) — matching cases and their payloads - [Sums](https://rux-lang.dev/docs/lang/sums/patterns) — matching members of a sum - [Conditional](https://rux-lang.dev/docs/lang/expressions/conditional) — a two-way choice of value - Learn: [Match](https://rux-lang.dev/docs/learn/match), [Match expression](https://rux-lang.dev/docs/learn/match-expression), [Exhaustive](https://rux-lang.dev/docs/learn/exhaustive) # Patterns A *pattern* describes the shape of a value. Matched against a value, it either fits or does not, and when it fits it may bind names to parts of the value. Patterns appear in three places: | Place | Patterns allowed | | -------------------------------------------------------------- | --------------------------------------------------------------------------------------------------- | | a [`match`](https://rux-lang.dev/docs/lang/patterns/match) arm | every form on this page | | a `catch` arm | patterns over the error — see [Handling errors](https://rux-lang.dev/docs/lang/errors/handling) | | a `let` or `var` binding | irrefutable forms only — see [Destructuring](https://rux-lang.dev/docs/lang/bindings/destructuring) | A pattern is *irrefutable* when it fits every value of its type — a name, `_`, and tuples and structures built from them — and *refutable* otherwise. | Form | Example | Fits | | ------------ | ----------------------------------------------- | ------------------------------------------------------ | | literal | `0`, `-1`, `1.5`, `'A'`, `true`, `null`, `"go"` | a value equal to the literal | | range | `1..5`, `1..=9`, `1...9` | a number in the range | | binding | `n` | anything, and binds it to `n` | | wildcard | `_` | anything, and binds nothing | | tuple | `(0, y)` | a tuple whose elements fit | | structure | `Point { x: 0, y }` | a structure whose named fields fit | | enum member | `.Red`, `Color::Red` | that member | | variant case | `.Round(r)`, `.Gauge { level }` | that case, with a payload that fits | | typed | `c: Circle`, `_: Square` | a sum whose active member has that type | | absence | `none` | an absent optional | | presence | `n?`, `n??`, `.Some(n)` | a present optional whose value fits | | outcome | `.Success(v)`, `.Failure(e)` | that channel of a fallible | | guarded | `n if n > 100` | a value the pattern fits and for which the guard holds | Patterns nest: wherever a pattern appears inside another — a tuple element, a field, a payload — any form can be used. ## Literal patterns An integer, floating-point, character or `bool` literal fits a value equal to it. A negative integer is written with its sign, `-1`. The literal takes the subject's type, so `255` fits a `uint8` field and `'a'` a `char32`; a literal of another kind is refused: ```text error: pattern has type 'char32', but the matched value has type 'int32' ``` `null` fits a null [pointer](https://rux-lang.dev/docs/lang/pointers/overview): ```rux func Read(p: *int32) -> int32 { return match p { null => 0, else => *p }; } ``` A string literal fits a `char8[..]` holding the same characters: the lengths agree, then every byte does. This is how a word is matched, although `==` is not defined on slices: ```rux func Command(word: char8[..]) -> int { return match word { "start" => 1, "stop" => 2, else => 0 }; } ``` A negative floating-point literal cannot be written as a pattern; use a guard. ## Range patterns A range pattern fits a number between two literal bounds. `lo..hi` excludes the upper bound; `lo..=hi` and `lo...hi` include it: ```rux func Classify(n: int32) -> char8[..] { return match n { -1 => "minus one", 0 => "zero", 1..5 => "one to four", 5..=9 => "five to nine", else => "other" }; } ``` Both bounds are needed: `5..` is `error: expected a range pattern end after '..' before '=>'`. Ranges apply to integers, floating-point numbers and every character width. For example, `'a'..='z'` matches a lowercase ASCII scalar for a `char32` subject or any wider one; a `char8` or `char16` subject needs bounds of its own width, such as `c8'a'..=c8'z'`. ## Binding patterns A name fits any value and binds it, for the rest of the arm. A binding is immutable, like a `let`: ```rux let m = match pair { (a, b) if a > b => a, (_, b) => b }; ``` A bare name always binds; it never compares. A name that already names a constant, a type, a function or a case of the matched type cannot be used: ```text error: pattern 'Limit' cannot bind a new variable because 'Limit' already names a constant help: a pattern compares with literal values; write the value of 'Limit', or bind the value and compare it with 'Limit' in a guard such as 'value if value >= Limit' ``` ## The wildcard `_` fits anything and binds nothing. It skips a part inside a larger pattern, such as a tuple element or a payload: `.Round(_)` matches the case without naming its value. On its own, as a whole arm, it is not the default — write `else` (see [match](https://rux-lang.dev/docs/lang/patterns/match#arms)). ## Tuple patterns A tuple pattern has one pattern per element, in order, and fits when every element fits: ```rux func Classify(pair: (int32, int32)) -> int32 { return match pair { (0, 0) => 0, (x, 0) => 100 + x, (0, y) => 200 + y, (a, b) => a * 10 + b }; } ``` The number of elements must match the tuple's: `error: tuple pattern has 3 elements, but matched tuple has 2`. ## Structure patterns A structure pattern names the type and lists fields by name, in any order. `field: pattern` tests the field; `field` alone binds it to a variable of the same name. Fields left out are not tested: ```rux match point { Point { x: 0, y: 0 } => PrintLine("origin"), Point { x: 0, y } => PrintLine("on the y axis at {}", y), Point { y: 7 } => PrintLine("at height 7"), else => PrintLine("elsewhere") } ``` The literals in field patterns compare at the field's type. A field the type does not have is `error: struct 'Point' has no field 'z'`. ## Enum and variant patterns A member of an [enum](https://rux-lang.dev/docs/lang/enums/overview) is written in full, `Color::Red`, or with a leading dot, `.Red`, which takes the enum from the subject's type. A [variant](https://rux-lang.dev/docs/lang/variants/matching) case is written the same way, followed by patterns for its payload — in parentheses for a positional case, in braces for a case with named fields: ```rux variant Reading { Missing, Gauge { level: int32; unit: char32; }, Pair(int32, int32) } ``` ```rux func Level(r: Reading) -> int32 { return match r { .Missing => 0, .Gauge { level: 0 } => -1, .Gauge { level, unit: 'C' } => level, Reading::Gauge { level: l } => l * 10, .Pair(a, _) => a }; } ``` A payload pattern may itself be refutable — a literal or a range in a field is tested before the arm is taken. The shorthand needs a subject whose type is an enum or variant: on an `int32`, `.Red` is `error: cannot infer enum or variant type for shorthand pattern '.Red' from type 'int32'`. ## Typed patterns A typed pattern, `name: Type`, fits a [sum](https://rux-lang.dev/docs/lang/sums/overview) whose active member has that type, and binds the member, as that type, to the name. `_: Type` tests the member without binding it: ```rux func Area(shape: Circle | Square) -> float64 { return match shape { c: Circle => 3.0 * c.radius * c.radius, s: Square => s.side * s.side }; } ``` The type after `:` is a complete type, so `v: A | B` needs no grouping. See [Sum patterns](https://rux-lang.dev/docs/lang/sums/patterns) for matching groups of members. ## Absence and presence On an [optional](https://rux-lang.dev/docs/lang/optionals/overview), `none` fits the absent value and a *presence* pattern fits a present one. `p?` is shorthand for `.Some(p)`, and `p??` peels two levels at once: ```rux func Describe(value: int32?) -> int32 { return match value { 0? => -1, n? if n > 100 => 100, n? => n, none => 0 }; } ``` The `?` must touch its pattern — `n ?` is `error: a presence suffix must touch its pattern` — and a range bound or a typed pattern cannot take one; write `.Some(1..=9)` or `.Some(v: A)` instead. On a [fallible](https://rux-lang.dev/docs/lang/errors/overview), `.Success(p)` and `.Failure(p)` fit the two channels — see [Handling errors](https://rux-lang.dev/docs/lang/errors/handling). ## Guards `pattern if condition` fits when the pattern fits **and** the condition, a `bool`, is `true`. The condition is checked after the pattern, so it can read the pattern's bindings: ```rux func Bucket(value: int32, small: bool) -> int32 { return match value { 1..=9 if small => 1, 1..=9 => 2, else => 3 }; } ``` A guard applies to the whole pattern before it, a range included. It is usually written at the end of an arm, but may also follow a pattern nested inside a tuple. A guard that is not a `bool` is `error: pattern guard must have type 'bool', but found 'int32'`. A guarded arm does not count towards [exhaustiveness](https://rux-lang.dev/docs/lang/patterns/match#exhaustiveness). ## No alternatives A pattern describes one shape. There is no `|` between patterns in an arm, and no comma-separated list: `1 | 2 => …` does not parse. Write one arm per value, a range, or a guard. ## See also - [match](https://rux-lang.dev/docs/lang/patterns/match) — arms, `else`, and exhaustiveness - [Destructuring](https://rux-lang.dev/docs/lang/bindings/destructuring) — irrefutable patterns in `let` - [Sum patterns](https://rux-lang.dev/docs/lang/sums/patterns), [Variant matching](https://rux-lang.dev/docs/lang/variants/matching), [Optionals](https://rux-lang.dev/docs/lang/optionals/overview) - Learn: [Guard](https://rux-lang.dev/docs/learn/guard), [Range pattern](https://rux-lang.dev/docs/learn/range-pattern), [Tuple pattern](https://rux-lang.dev/docs/learn/tuple-pattern), [Struct pattern](https://rux-lang.dev/docs/learn/struct-pattern), [Typed pattern](https://rux-lang.dev/docs/learn/typed-pattern), [Presence](https://rux-lang.dev/docs/learn/presence) # Function declarations A function gives a block of statements a name, a list of typed parameters and, optionally, a result type. Calling it runs the block with the arguments bound to the parameters, and the call is worth the value the block returns. ```text function = [ attributes ] [ "pub" ] "func" name [ type-parameters ] "(" [ parameter { "," parameter } [ "," ] ] ")" [ "->" result ] block parameter = name ":" type [ "=" expression ] | name ":" type "..." result = type | type "!" type | "!" type ``` ```rux func Add(left: int, right: int) -> int { return left + right; } ``` | Part | In `Add` | Meaning | | ----------- | -------------------------- | ---------------------------------------------------------------------- | | Name | `Add` | An identifier; PascalCase by convention | | Parameters | `left: int, right: int` | `name: Type` each, separated by commas; a trailing comma is allowed | | Result type | `-> int` | The type of the value the function returns; omitted when there is none | | Body | `{ return left + right; }` | A block | Parameters, default values and variadic parameters are described in [Parameters](https://rux-lang.dev/docs/lang/functions/parameters). A name in angle brackets after the function name declares a type parameter, which makes the function [generic](https://rux-lang.dev/docs/lang/generics/overview). ## Where functions are declared | Place | Declares | | ------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- | | The top level of a file | A free function of the package's root module | | A `module A::B { }` block | A free function of that module — see [Modules](https://rux-lang.dev/docs/lang/modules/overview) | | An `extend T { }` block | A [method](https://rux-lang.dev/docs/lang/structs/methods), [constructor](https://rux-lang.dev/docs/lang/structs/constructors), operator or destructor of `T` | | An `extern { }` block | A foreign function, without a body — see [FFI](https://rux-lang.dev/docs/lang/ffi/overview) | | `asm func` | A function whose body is assembly — see [Assembly](https://rux-lang.dev/docs/lang/ffi/assembly) | Every other function needs a body. A signature ending in `;` is refused: ```text error: function 'Later' has no body ``` Declaration order does not matter: a function may call one declared further down the file, or in another file of the package. `pub` makes a function visible to other packages; see [Visibility](https://rux-lang.dev/docs/lang/modules/visibility). ## The result | Written | The function | | -------------------- | ----------------------------------------------------------------------------------------------------------------- | | no `->` | Returns nothing. A bare `return;` leaves early; reaching the closing brace returns | | `-> T` | Returns a `T`. Every path through the body must end in `return` with a value | | `-> ()` | Returns the [unit](https://rux-lang.dev/docs/lang/tuples/overview#the-unit-type) value `()` | | `-> T ! E`, `-> ! E` | Is [fallible](https://rux-lang.dev/docs/lang/errors/overview): it returns a `T` (or nothing) or fails with an `E` | Several values are returned as a [tuple](https://rux-lang.dev/docs/lang/tuples/overview), an absent result as an [optional](https://rux-lang.dev/docs/lang/optionals/overview). ```rux func Greet(name: char8[..]) { if name.length == 0 { return; } PrintLine("Hello, {}!", name); } func Divide(dividend: int, divisor: int) -> (int, int) { return (dividend / divisor, dividend % divisor); } ``` The compiler checks that a function with a result type returns on every path, and that a function without one never returns a value: ```text error: function 'Sign' must return a value of type 'int' on every control-flow path error: 'return' cannot have a value in a function with no return type ``` Leaving out the result type is not the same as writing `-> ()`. Only a unit-returning function produces a value of type `()` that can be stored or passed; a call to a function without a result is written as a statement on its own. See [`return`](https://rux-lang.dev/docs/lang/statements/return) for the statement itself. ## Calls A call is the function's name followed by one argument per parameter, in parentheses and in order. Arguments are evaluated from left to right, then bound to the parameters, and the body runs: ```rux func Note(label: char8[..], value: int) -> int { PrintLine("evaluating {}", label); return value; } func Main() -> int { // Prints "evaluating first", then "evaluating second", then 12. PrintLine("{}", Pair(Note("first", 1), Note("second", 2))); return 0; } func Pair(first: int, second: int) -> int { return first * 10 + second; } ``` A call is an expression of the result type and may appear wherever a value of that type fits — as an argument to another call, in an operator, on the right of a binding. Each argument must have its parameter's type. Nothing is converted to make a call fit, with one exception: an unsuffixed integer literal takes the integer type of its parameter, so `Half(9)` works for a `uint8` parameter. A function may call itself, directly or through others; each call has its own parameters and locals. ## Rules and errors | Mistake | Error | | ------------------------------------------------- | --------------------------------------------------------------------------------- | | An argument of another type | `argument 1 to 'Square' has type 'float64', but parameter 'value' requires 'int'` | | Too many or too few arguments | `call to 'Square' expects 1 argument, but 2 were provided` | | A name in the wrong case | `name 'square' is not defined in this scope`, with `did you mean 'Square'?` | | A missing `return` on some path | `function 'Sign' must return a value of type 'int' on every control-flow path` | | A value returned from a function without a result | `'return' cannot have a value in a function with no return type` | | A body-less signature outside `extern` | `function 'Later' has no body` | Names are case-sensitive. Several functions may share a name when their parameters differ; see [Overloading](https://rux-lang.dev/docs/lang/functions/overloading). ## See also - [Parameters](https://rux-lang.dev/docs/lang/functions/parameters) — by-value parameters, defaults and variadics - [Function types](https://rux-lang.dev/docs/lang/functions/function-types) — functions as values - [Main](https://rux-lang.dev/docs/lang/functions/main) — the entry point of a program - [Generics](https://rux-lang.dev/docs/lang/generics/overview) — functions over type parameters - Learn: [Function](https://rux-lang.dev/docs/learn/function), [Return](https://rux-lang.dev/docs/learn/return), [Recursion](https://rux-lang.dev/docs/learn/recursion) # Parameters A parameter is written `name: Type`. Each call binds the parameter to its argument for that one run of the body. A parameter is read-only: the body may read it but never assign to it, and what the caller can see changed depends only on the parameter's type. ```text parameter = name ":" type [ "=" expression ] // an ordinary parameter, optionally with a default | name ":" type "..." // a variadic parameter ``` ## Passing modes The parameter's type decides how the argument is passed. The call site writes nothing extra for any of them, except the arrow that moves a value which cannot be copied. | Parameter | The function receives | Can change the caller's value | The caller passes | | -------------- | ----------------------------------------- | ----------------------------- | ------------------------------------------------------- | | `x: T` | its own copy, read-only | no | any `T`; a move-only value as `<-value` | | `x: &T` | the caller's value, borrowed for reading | no | a named `T` | | `x: &var T` | the caller's value, borrowed for writing | yes | a `var` `T` | | `x: T[..]` | a read-only view of the caller's elements | no | a slice, or an array viewed as one | | `x: var T[..]` | a writable view of the caller's elements | the elements, yes | a writable slice, such as `buffer[..]` of a `var` array | References are described in [References](https://rux-lang.dev/docs/lang/references/overview), views in [Slices](https://rux-lang.dev/docs/lang/slices/overview), and moves in [Copy and move](https://rux-lang.dev/docs/lang/ownership/copy-and-move). ## Parameters are read-only Assigning to a parameter is an error, whatever its type: ```rux func Bump(n: int) -> int { n = n + 1; // error return n; } ``` ```text error: cannot modify parameter 'n' note: a parameter is immutable help: take 'n' as '&var int' to change the caller's value, or move it into a 'var' local ``` A function that needs a value it can change declares a local of its own and starts it from the parameter. A function that must change the caller's value takes `&var T`: ```rux func Countdown(from: int) { var remaining = from; while remaining > 0 { Print("{} ", remaining); remaining -= 1; } PrintLine("liftoff"); } func Tick(count: &var int) { count += 1; } ``` `var` is never written before a parameter name. `func Count(var n: int)` is refused with `mutable parameter syntax 'var n: T' has been removed`, and the help names the two forms above. ## Default values A parameter may give a default value after `=`. A call may then stop before it, and the default fills the gap: ```rux func Clamp(value: int, low: int = 0, high: int = 100) -> int { if value < low { return low; } if value > high { return high; } return value; } ``` | Call | `value` | `low` | `high` | Result | | -------------------- | ------- | ----- | ------ | ------ | | `Clamp(150)` | 150 | 0 | 100 | 100 | | `Clamp(42, 50)` | 42 | 50 | 100 | 50 | | `Clamp(150, 0, 255)` | 150 | 0 | 255 | 150 | The rules: - **Defaults come last.** A parameter without a default may not follow one with a default, because arguments always fill parameters from the left: `parameter 'second' without a default value cannot follow a parameter with a default value`. - **There are no named arguments.** A call cannot skip a parameter in the middle; to change `high`, it passes `low` too. `Clamp(150, high: 255)` is a syntax error. - **The default has the parameter's type**: `default value type 'float64' does not match parameter type 'int'`. - **A default is evaluated at each call that omits it**, in the caller's scope, as if the caller had written it. A default with an effect has it once per such call: ```rux func Tick() -> int { PrintLine("tick"); return 7; } func Show(value: int = Tick()) { PrintLine("value {}", value); } func Main() -> int { Show(); // tick, value 7 Show(1); // value 1 — Tick is not called Show(); // tick, value 7 return 0; } ``` - **A default cannot read another parameter**, `self` included, since it is evaluated where no parameter exists yet. Write an overload that passes the value instead: ```rux // func Repeat(text: char8[..], count: uint = text.length) is refused func Repeat(text: char8[..], count: uint) -> uint { return text.length * count; } func Repeat(text: char8[..]) -> uint { return Repeat(text, text.length); } ``` ```text error: a default value cannot refer to parameter 'text' help: add an overload without this parameter that passes the value it should default to ``` A [`#source`](https://rux-lang.dev/docs/lang/comptime/context) value written as a default, such as `line: uint = #source.line`, is expanded at each call that leaves the argument out, so every call sees its own line. ## Variadic parameters A last parameter written `name: T...` accepts any number of arguments of type `T`, zero included. Inside the function it is a read-only slice, `T[..]`: ```rux func Sum(values: int...) -> int { var total = 0; for value in values { total += value; } return total; } func Largest(first: int, rest: int...) -> int { var largest = first; for value in rest { if value > largest { largest = value; } } return largest; } ``` | Call | `values` inside `Sum` | Result | | -------------- | --------------------- | ------ | | `Sum()` | empty | 0 | | `Sum(1, 2, 3)` | 1, 2, 3 | 6 | | `Largest(4)` | `rest` is empty | 4 | Ordinary parameters may come before the variadic one, and each still needs its argument: `Largest()` is `call to 'Largest' expects at least 1 argument, but 0 were provided`. The elements are read-only — `values[0] = 1` is `cannot modify elements through read-only slice 'int[..]'`. The element type may be an [interface](https://rux-lang.dev/docs/lang/interfaces/overview), and then each argument may be a different type that implements it. That is how `PrintLine` is declared: `args: Display...` takes an `int`, a `float64` and a string in one call. ### Spread `expression...` as the argument for a variadic parameter passes the elements of a slice or array as the arguments: ```rux let more = [4, 5, 6]; Sum(more...); // 15 Sum(more[1..]...); // 11 ``` A spread must be the only argument for the variadic parameter. Mixing it with separate values is an error: ```text error: spread argument to 'Sum' must be the only argument for variadic parameter 'values' ``` A spread is how one variadic function hands everything it received to another: ```rux func Average(values: int...) -> int { if values.length == 0 { return 0; } return Sum(values...) / (values.length as int); } ``` Only the last parameter may be variadic, since it takes every argument after the fixed ones. `func Bad(args: int32..., last: int32)` is an error: ```text error: variadic parameter 'args' of 'Bad' must be its last parameter help: move 'args' to the end of the parameter list ``` A variadic parameter may also follow a format string marked [`#Format()`](https://rux-lang.dev/docs/lang/attributes/format), which lets the compiler count placeholders against arguments. ## See also - [Function declarations](https://rux-lang.dev/docs/lang/functions/declaration) — the shape of a function - [Overloading](https://rux-lang.dev/docs/lang/functions/overloading) — how a call chooses among functions with defaults and variadics - [References](https://rux-lang.dev/docs/lang/references/overview) — `&T` and `&var T` parameters - [Copy and move](https://rux-lang.dev/docs/lang/ownership/copy-and-move) — passing values that cannot be copied - Learn: [Default argument](https://rux-lang.dev/docs/learn/default-argument), [Variadic](https://rux-lang.dev/docs/learn/variadic), [Mutable reference](https://rux-lang.dev/docs/learn/mutable-reference) # Overloading Several functions in one scope may share a name when their parameter lists differ. Together they form an *overload set*, and each call picks one member by looking at its arguments. Methods and [constructors](https://rux-lang.dev/docs/lang/structs/constructors) overload the same way. ```rux func Describe(value: int) { PrintLine("an integer: {}", value); } func Describe(value: float64) { PrintLine("a number with a fraction: {}", value); } func Area(side: int) -> int { return side * side; } func Area(width: int, height: int) -> int { return width * height; } ``` `Describe(42)` and `Describe(2.5)` run different functions; `Area(4)` and `Area(4, 5)` likewise. ## What may differ Overloads must differ in their parameters — the number of them or their types. The result type takes no part: a call does not say what type it wants back, so two functions that differ only in their result could never be told apart, and the second is refused. ```rux func Half(value: int) -> int { return value / 2; } func Half(value: int) -> float64 { // error return 0.0; } ``` ```text error: function 'Half' has the same parameter signature as an earlier overload ``` Parameter names do not count either. When the difference really is in the result, give the functions different names. ## How a call is resolved Declaration order never decides a call. The compiler finds every overload that could accept the arguments and keeps the best, in these steps: 1. **Fixed parameter lists first.** Overloads without a variadic parameter are tried first; a variadic overload is chosen only when none of them accepts the call. 2. **Exact matches first.** Within that group, overloads whose parameter types are exactly the argument types are tried before overloads that need any conversion. 3. **The most specific overload.** Among the overloads that accept the call, one that is no worse for any argument and better for at least one wins. For each argument, from best to worst: | Rank | The argument's type is… | | ---- | --------------------------------------------------------------------------------------------------------------------- | | 1 | exactly the parameter's type | | 2 | the same type, differing only in a view's writability (`var int[..]` for `int[..]`) | | 3 | the same type reached through a borrow or a read through a reference (`int32` for `&int32`, `&var int32` for `int32`) | | 4 | any other type the argument converts to, such as an unsuffixed integer literal to another integer type | 4. **No default needed.** Among overloads still tied, one that the arguments fill without using a default value wins. 5. **Not generic.** Then a function without type parameters wins over a [generic](https://rux-lang.dev/docs/lang/generics/overview) one. Overloads still tied after that make the call ambiguous, which is an error. ```rux func G(x: int) -> int { return 1; } func G(x: int, y: int = 1) -> int { return 2; } func H<T>(x: T) -> int { return 3; } func H(x: int) -> int { return 4; } func V(args: int...) -> int { return 5; } func V(a: int, b: int) -> int { return 6; } func W(x: float64) -> int { return 7; } func W(x: int32) -> int { return 8; } ``` | Call | Calls | Because | | ------------ | ------------------- | --------------------------------------- | | `G(2)` | `G(x: int)` | step 4 — the other needs its default | | `G(2, 3)` | `G(x: int, y: int)` | only it takes two arguments | | `H(1)` | `H(x: int)` | step 5 — the generic one ties but loses | | `H(true)` | `H<T>(x: T)` | only it accepts a `bool` | | `V(1, 2)` | `V(a: int, b: int)` | step 1 — a fixed list is preferred | | `V(1, 2, 3)` | `V(args: int...)` | no fixed overload takes three arguments | | `W(small)` | `W(x: int32)` | step 2 — `small` is an `int32` | | `W(2.0)` | `W(x: float64)` | only it accepts a `float64` | A literal is not converted to suit an overload, except that an unsuffixed integer literal, or a constant integer expression, may become another integer type it fits. A variable never does: with `let a: int = 3`, `Midpoint(a, b)` reaches only the `int64` overload, since an `int` value converts to no other width, while `Midpoint(3, 8)` reaches every integer one. `Area(4, 2.0)` matches nothing when the overloads take `(int, int)` and `(float64, float64)`: ```text error: no matching overload for 'Area' with argument types (int, float64) ``` ## Ambiguous calls When two overloads remain after every step, the compiler names both: ```rux func F(x: int8) -> int { return 8; } func F(x: int64) -> int { return 64; } func Main() -> int { return F(5); // error } ``` ```text error: call to 'F' is ambiguous: 2 overloads accept argument types (int) note: candidate 'F(x: int8)' declared at … note: candidate 'F(x: int64)' declared at … help: rename one of the overloads, or remove a default value that makes them overlap ``` The literal `5` converts to both `int8` and `int64` at rank 4, and nothing else separates them. A suffix picks one — `F(5i8)` is an exact match. When every overload belongs to another package, renaming them is not the caller's to do, so the help says what is: `give an unsuffixed literal argument the width it means, as in '3i64', or convert an argument with 'as'`. ## See also - [Parameters](https://rux-lang.dev/docs/lang/functions/parameters) — default values and variadic parameters - [Generics](https://rux-lang.dev/docs/lang/generics/overview) — one generic function instead of a family of overloads - [Constructors](https://rux-lang.dev/docs/lang/structs/constructors) — overloaded constructors - Learn: [Overload](https://rux-lang.dev/docs/learn/overload) # Function types A function is also a value. Its type, a *function type*, records the parameter types and the result type and nothing else, so any function of the same shape fits wherever that type is expected. A function value can be passed as an argument, held in a local or a field, compared, and called. ```text function-type = "func" "(" [ parameter-type { "," parameter-type } ] ")" [ "->" result ] parameter-type = [ name ":" ] type ``` ## The type of a function A function's type is its declaration with the name, the parameter names and the body taken out: | Function | Its type | | -------------------------------------------- | ---------------------------- | | `func Double(value: int32) -> int32` | `func(int32) -> int32` | | `func Ascending(a: int32, b: int32) -> bool` | `func(int32, int32) -> bool` | | `func Report(label: char8[..])` | `func(char8[..])` | | `func Ready() -> bool` | `func() -> bool` | A function type without `->` describes a function with no result. Parameter names may be written inside a function type for readability, `func(a: int32, b: int32) -> bool`, but they are ignored: only the types count. Two function types are the same when their parameter types and result types are identical, in order. Nothing converts — a `func(int) -> int` does not fit a `func(int32) -> int32`, and a function returning `bool` does not fit one returning `int32`. ## Function values A function's name, written without parentheses, is a value of its function type. Writing parentheses calls the function instead. ```rux type Comparator = func(int32, int32) -> bool; struct Sorter { name: char8[..]; before: Comparator; } func Ascending(a: int32, b: int32) -> bool { return a < b; } func Descending(a: int32, b: int32) -> bool { return a > b; } func Sort(items: var int32[..], before: func(int32, int32) -> bool) { for i in 1..items.length { var j = i; while j > 0 && before(items[j], items[j - 1]) { let held = items[j]; items[j] = items[j - 1]; items[j - 1] = held; j -= 1; } } } func Main() -> int { var numbers: int32[5] = [3, 1, 4, 1, 5]; Sort(numbers[..], Ascending); // 1 1 3 4 5 let sorter = Sorter { name: "down", before: Descending }; Sort(numbers[..], sorter.before); // 5 4 3 1 1 var compare: func(int32, int32) -> bool = Ascending; PrintLine("{}", compare(1, 2)); // true compare = Descending; PrintLine("{}", compare(1, 2)); // false PrintLine("{}", compare == Descending); // true return 0; } ``` | Where | Written | Called as | | ----------- | ----------------------------------------- | --------------------- | | A parameter | `before: func(int32, int32) -> bool` | `before(x, y)` | | A local | `var compare: func(int32, int32) -> bool` | `compare(1, 2)` | | A field | `before: Comparator;` | `sorter.before(x, y)` | A local, parameter or field of function type is called exactly like a function, and the call runs whichever function the value holds at that moment. A `var` local or field can be reassigned to another function of the same type. `==` and `!=` compare two function values by identity: they are equal when they hold the same function. A [type alias](https://rux-lang.dev/docs/lang/types/aliases) gives a long function type a name. The alias is the same type, so `Comparator` and `func(int32, int32) -> bool` are interchangeable, as `Sort` and `Sorter` show. ## What a function value is not A function value refers to one declared function and carries no state of its own. - **There are no closures.** There is no lambda or anonymous function expression, and a function value cannot capture a local variable. Data a callback needs is passed to it as an argument, or kept in a struct beside the function field. - **A generic function is not a value on its own.** Its name has no single type until its type parameters are known, so it takes them from the function type it is given: `let pick: func(int, int) -> int = Larger;` is the `int` instance of `Larger`. With no function type to take them from, as in `let pick = Larger;`, it is refused with `generic function 'Larger' has no type arguments here`. - **A method is not a value.** `card.Area` without parentheses is read as a field and fails with `has no field 'Area'`. - **A function is not declared inside a block.** A `func` inside a function body is `function 'Helper' cannot be declared inside a function body`; declare it at the top level, in a module, or in an `extend` block. ## Overloaded names The name of an [overloaded](https://rux-lang.dev/docs/lang/functions/overloading) function, used as a value, is the overload whose function type its destination expects: an annotated binding, an assignment, a function-typed parameter of a callee with one declaration, or a `return` in a function with a function-typed result. A module path such as `Tools::Scale` is chosen the same way. ```rux func Scale(value: int32) -> int32 { return value * 2; } func Scale(value: float32) -> float32 { return value * 2.0f32; } func Main() -> int { let whole: func(int32) -> int32 = Scale; // the int32 overload let real: func(float32) -> float32 = Scale; // the float32 overload PrintLine("{} {}", whole(3), real(1.5f32)); // 6 3.0 return 0; } ``` With no function type to choose by, as in `let f = Scale;`, the name is refused, and so is a type that no overload has: ```text error: overloaded function 'Scale' has no function type here to choose an overload by note: overload 'Scale' has type 'func(int32) -> int32' note: overload 'Scale' has type 'func(float32) -> float32' help: give the value a function type, as in 'let f: func(int32) -> int32 = Scale;' error: no overload of 'Scale' has type 'func(float64) -> float64' ``` ## Rules and errors | Mistake | Error | | ---------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------- | | A function of another shape, `Sort(numbers[..], IsEven)` | `argument 2 to 'Sort' has type 'func(int32) -> bool8', but parameter 'before' requires 'func(int32, int32) -> bool8'` | | Calling instead of passing, `Sort(numbers[..], Ascending(1, 2))` | `argument 2 to 'Sort' has type 'bool8', but parameter 'before' requires 'func(int32, int32) -> bool8'` | | Calling a function value with the wrong arguments, `compare(1)` | `call to 'compare' expects 2 arguments, but 1 was provided` | | An overloaded name with no type to choose by, `let f = Scale;` | `overloaded function 'Scale' has no function type here to choose an overload by` | | A function type no overload has | `no overload of 'Scale' has type 'func(float64) -> float64'` | | A `func` inside a function body | `function 'Helper' cannot be declared inside a function body` | Error messages print `bool` by its full name, `bool8`. ## See also - [Function declarations](https://rux-lang.dev/docs/lang/functions/declaration) — declaring the functions that become values - [Type aliases](https://rux-lang.dev/docs/lang/types/aliases) — naming a function type - [Structs](https://rux-lang.dev/docs/lang/structs/overview) — fields of function type - Learn: [Callback](https://rux-lang.dev/docs/learn/callback), [Function field](https://rux-lang.dev/docs/learn/function-field) # The Main function An executable package starts at a function named `Main`, declared at the top level of the package — outside every `module` block — and taking no parameters. When `Main` returns, the program ends, and its result becomes the process's *exit status*: 0 for success, anything else for failure. ```rux func Main() -> int { PrintLine("Hello, Rux!"); return 0; } ``` A new executable package keeps `Main` in `Src/Main.rux`, but any file of the package may hold it. Library packages have no `Main`, and `rux run` refuses to run one. ## The forms | Declaration | Ends by | Exit status | | ------------------------ | ------------------------------ | ----------- | | `func Main()` | reaching its end, or `return;` | 0 | | `func Main() -> int` | `return n;` | `n` | | `func Main() -> ! E` | reaching its end, or `return;` | 0 | | `func Main() -> int ! E` | `return n;` | `n` | | `-> ! E` or `-> int ! E` | `fail`, or a failed `?` | 1 | `E` may be any error type. A fallible `Main` lets [`?`](https://rux-lang.dev/docs/lang/errors/propagation) propagate a failure out of the program: ```rux variant StartError { MissingConfig } func Load(present: bool) -> int ! StartError { if !present { fail StartError::MissingConfig; } return 3; } func Main() -> ! StartError { let count = Load(false)?; // fails: the program ends with status 1 PrintLine("loaded {}", count); } ``` On failure, `Main` runs its ordinary cleanup — deferred statements and destructors — and the process exits with status 1. **The error itself is not printed.** A program that wants the user to see why it stopped prints a message before it fails, for instance in a [`catch`](https://rux-lang.dev/docs/lang/errors/handling) arm that then fails with the same error. A [panic](https://rux-lang.dev/docs/lang/errors/panics) is different: it stops the program at once, without cleanup, whatever form `Main` has. Any other signature — parameters, or a result that is not an integer — is an error: ```rux func Main(count: int) -> bool { return true; } ``` ```text error: 'Main' must take no parameters and return nothing, an integer, '! E' or an integer '! E', but it takes parameters and returns 'bool8' note: the result of 'Main' is the process's exit status, which no other form defines help: declare it as 'func Main() -> int', 'func Main() -> ! E' or 'func Main() -> int ! E' ``` The message names only what is wrong: `func Main() -> float64` ends with `but it returns 'float64'`. ## DllMain A shared library built for Windows (`Type = "SharedLibrary"`) may declare a top-level function named `DllMain`. The Windows loader calls it when a process loads or unloads the library, and the library loads only if it returns a non-zero value. Its signature is the one Windows expects: ```rux func DllMain(instance: *opaque, reason: uint32, reserved: *opaque) -> int32 { return 1; } ``` Without a `DllMain`, the library loads as if one had returned 1. On other systems the name has no special meaning. ## See also - [Function declarations](https://rux-lang.dev/docs/lang/functions/declaration) — functions in general - [Errors](https://rux-lang.dev/docs/lang/errors/overview) — fallible results, `fail` and `?` - [Package types](https://rux-lang.dev/docs/packaging/types) — executables and libraries - Learn: [Fallible main](https://rux-lang.dev/docs/learn/fallible-main) # Structs A `struct` declares a named type made of named *fields*. A value of the type holds every field at once. Two structs are different types even when their fields are identical, so a function that asks for a `Point` cannot be handed something else that happens to have an `x` and a `y`. A struct declares only its data. Methods, constructors, operators and destructors are added in a separate [`extend`](https://rux-lang.dev/docs/lang/structs/methods) block. ```text struct = [ attributes ] [ "pub" ] "struct" name [ type-parameters ] "{" { field } "}" field = [ "pub" ] name ":" type ";" ``` ```rux struct Point { x: int; y: int; } struct Box { corner: Point; width: int; height: int; } struct Empty {} ``` Each field is `name: Type` and ends with a semicolon. A field may have any type that has a known size: a primitive, an array, a slice, a pointer, an optional, a tuple, another struct. By convention the type name is PascalCase and field names are camelCase. ## Struct literals A value is built with a *struct literal*: the type's name and a value for every field, in braces. The fields may come in any order, because each is named: ```rux let origin = Point { x: 0, y: 0 }; let corner = Point { y: 2, x: 5 }; let box = Box { corner: corner, width: 4, height: 3 }; ``` Every field must be given. A field has no default value — `x: int = 0;` in a declaration is a syntax error — so a literal that leaves one out is refused: ```text error: initializer for 'Point' is missing required field 'y' error: struct 'Point' has no field 'z' note: available fields are 'x' and 'y' ``` When building a value takes more than listing its fields, give the type a [constructor](https://rux-lang.dev/docs/lang/structs/constructors): `Point(1, 2)` is a constructor call, not a literal. A literal always remains available where every field is visible. ## Fields A field is read with `.`, and fields of nested structs by chaining: `box.corner.x`. A field is assigned like a variable, and the same rule applies: the value must be a `var`. Under `let` the whole struct is read-only, every field included. ```rux var cursor = Point { x: 1, y: 1 }; cursor.x = 10; cursor.y += 5; let fixed = Point { x: 1, y: 2 }; fixed.x = 5; // error: cannot modify immutable variable 'fixed' ``` A field can also be read through a [reference](https://rux-lang.dev/docs/lang/references/overview) or a [pointer](https://rux-lang.dev/docs/lang/pointers/overview) to the struct with the same `.`; writing needs a `&var T` or a `*var T`. ## Visibility A field is private to its package unless it is marked `pub`, separately from the struct itself: ```rux pub struct Point { pub x: int; y: int; } ``` Another package that imports `Point` can read and write `x` but not `y`. Because a literal must name every field, it cannot build a `Point` at all; it calls a public constructor instead: ```text error: struct field 'y' is private to package 'Shapes' error: struct 'Point' cannot be initialized outside its package because it has private fields help: use a public constructor instead ``` Within its own package every field is visible. See [Visibility](https://rux-lang.dev/docs/lang/modules/visibility). ## Values, not references A struct is a value. Assigning it, passing it to a by-value parameter and returning it copies every field, and the copy is independent of the original: ```rux var a = Point { x: 1, y: 2 }; var b = a; // a copy b.x = 9; // a.x is still 1 ``` A function that should read a large struct without copying it takes `&Point`; one that should change the caller's struct takes `&var Point`. A struct whose type declares that it cannot be copied is moved instead, with `<-`; see [Copy and move](https://rux-lang.dev/docs/lang/ownership/copy-and-move). ## Self-reference A struct cannot contain itself by value, since its size would be infinite. A linked structure holds a [pointer](https://rux-lang.dev/docs/lang/pointers/overview) to the next node instead, usually an optional one: ```rux struct Node { value: int; next: (*Node)?; } ``` A field such as `next: Node;`, or `next: Node?;`, which holds the value in place too, is an error. So is a cycle through other types, and the same rule covers variants and unions: ```text error: struct 'Node' contains itself by value through 'next' note: a value that holds itself in place would have no finite size help: hold it behind a pointer, as '*Node' or '(*Node)?' ``` ## Equality Two values of the same struct type compare with `==` and `!=` field by field, in declaration order. Every field must support `==` itself; a field such as a `char8[..]` slice, which has no `==`, makes the comparison unavailable: ```rux let same = origin == Point { x: 0, y: 0 }; // true ``` ```text error: structural equality for 'Named' is unavailable because element type 'char8[..]' has no '==' operator ``` A struct that declares its own `==` in an `extend` block uses that instead; see [Operators](https://rux-lang.dev/docs/lang/interfaces/operators). Structs have no built-in ordering: `<` needs a declared operator. ## Generic structs A struct may take type parameters, written after its name. Each use names the type arguments, in the type and in a literal: ```rux struct Pair<T> { first: T; second: T; } let pair = Pair<int> { first: 1, second: 2 }; ``` See [Generic types](https://rux-lang.dev/docs/lang/generics/types). ## See also - [Methods](https://rux-lang.dev/docs/lang/structs/methods) — functions that belong to a struct - [Constructors](https://rux-lang.dev/docs/lang/structs/constructors) — building values through a function - [Destructuring](https://rux-lang.dev/docs/lang/bindings/destructuring) and [patterns](https://rux-lang.dev/docs/lang/patterns/patterns) — taking a struct apart - [Memory layout](https://rux-lang.dev/docs/lang/memory/layout) — field order, alignment and padding - Learn: [Struct](https://rux-lang.dev/docs/learn/struct), [Structural equality](https://rux-lang.dev/docs/learn/structural-equality) # Methods An `extend` block adds functions to a type. A function in it whose first parameter is named `self` is a *method*, called on a value with `.`: `counter.Advance()`. A function without `self` is a *static function* of the type, called through its name with `::`: `Counter::Zero(5)`. ```text extension = "extend" type [ ":" interface ] "{" { function } "}" receiver = "self" ":" ( type | "&" type | "&" "var" type ) ``` ```rux struct Counter { count: int; step: int; } extend Counter { func Zero(step: int) -> Counter { return Counter { count: 0, step: step }; } func Value(self: &Counter) -> int { return self.count; } func Advance(self: &var Counter) { self.count += self.step; } func Advanced(self: Counter) -> Counter { var next = self; next.Advance(); return next; } } func Main() -> int { var counter = Counter::Zero(5); counter.Advance(); counter.Advance(); let ahead = counter.Advanced(); PrintLine("{} {}", counter.Value(), ahead.Value()); // 10 15 return 0; } ``` A type may have any number of `extend` blocks, in any file of its package. The type's fields stay in the `struct` declaration; an `extend` block holds only functions. `extend` works for every named type — structs, [enums](https://rux-lang.dev/docs/lang/enums/overview), [variants](https://rux-lang.dev/docs/lang/variants/overview), [unions](https://rux-lang.dev/docs/lang/unions/overview) — and for built-in types, as [Extensions](https://rux-lang.dev/docs/lang/structs/extensions) shows. ## Receivers The receiver is always named `self`, always comes first, and has its type written out like any other parameter. The type is the extended type, or a reference to it, and decides what the method may do: | Receiver | The method gets | May change the caller's value | Callable on | | -------------------- | ----------------------------- | ----------------------------- | ----------------- | | `self: &Counter` | the caller's value, to read | no | any `Counter` | | `self: &var Counter` | the caller's value, to change | yes | a `var` `Counter` | | `self: Counter` | a copy, read-only | no | any `Counter` | A `&T` receiver is the usual choice for a method that only reads; `&var T` for one that changes the value in place; `T` for small values such as numbers and enum cases, or for a method that wants its own copy to work on, as `Advanced` does. Inside a method, fields are always reached through `self`. There is no implicit scope: a bare `count` is an unknown name. A receiver is read-only like every parameter, and a `&T` receiver cannot be written through: ```text error: cannot modify immutable receiver 'self' help: take the receiver as 'self: &var Counter' to change the caller's value error: cannot modify data through immutable reference '&Counter' ``` ## Calling methods The value before the dot becomes `self`. It is borrowed when the receiver is a reference and copied when it is a value; the call site writes nothing extra in either case. The remaining arguments go in the parentheses. A method with a `&var T` receiver needs a value it can write to: ```rux let fixed = Counter::Zero(1); fixed.Value(); // fine fixed.Advance(); // error ``` ```text error: cannot call 'Advance' on immutable 'fixed' note: 'Advance' declares a writable receiver '&var Counter' help: declare 'fixed' with 'var' to make it mutable ``` A method that reads may also be called on a value that has no name, such as a literal: `Counter { count: 9, step: 1 }.Value()`. | Kind | Declared | Called as | | --------------- | ------------------------------------ | ------------------ | | Method | `func Value(self: &Counter) -> int` | `counter.Value()` | | Static function | `func Zero(step: int) -> Counter` | `Counter::Zero(5)` | | Constructor | `func Counter(step: int) -> Counter` | `Counter(5)` | A method is reached only through a value. It is not in scope as a free function, and it cannot be called through the type path: ```text error: name 'Value' is not defined in this scope error: call to 'Counter::Value' expects 0 arguments, but 1 was provided ``` Each type has its own methods, so `Rectangle` and `Circle` may both have an `Area` without clashing; the type of the value before the dot decides which runs. Methods of one type overload like functions, by their parameters after `self`; see [Overloading](https://rux-lang.dev/docs/lang/functions/overloading). ## Rules and errors | Mistake | Error | | --------------------------------------------------- | --------------------------------------------------------------------------------------------- | | The receiver given another name, `this: &Counter` | it is an ordinary parameter; `counter.Value()` then `expects 1 argument, but 0 were provided` | | `self` after another parameter | `receiver 'self' must be the first parameter of method 'Value'` | | `self` without a type, `Value(self)` | `expected ':' and the receiver type after 'self' before ')'` | | A receiver of another type | `receiver type '&Other' does not name the extended type 'Counter'` | | A method named without parentheses, `counter.Value` | `struct 'Counter' has no field 'Value'` | ## What else goes in extend | Declaration | Page | | -------------------------------------------------------- | ------------------------------------------------------------------- | | `func T(...) -> T` | [Constructors](https://rux-lang.dev/docs/lang/structs/constructors) | | `func ~T(self: &var T)` | [Destructors](https://rux-lang.dev/docs/lang/ownership/destructors) | | `func +(self: T, other: T) -> T` and the other operators | [Operators](https://rux-lang.dev/docs/lang/interfaces/operators) | | `func [](self: &T, index: uint) -> E` | [Indexers](https://rux-lang.dev/docs/lang/interfaces/indexers) | | `extend T : Interface { … }` | [Interfaces](https://rux-lang.dev/docs/lang/interfaces/overview) | A generic type's `extend` block names its type parameters, `extend Pair<T> { … }`, and a method may have type parameters of its own; see [Generic methods](https://rux-lang.dev/docs/lang/generics/methods). `pub` on each function makes it visible to other packages — `pub` on the struct does not reach its methods, and calling one that lacks it from another package is `method 'Secret' is private to package 'Shapes'`. ## See also - [Structs](https://rux-lang.dev/docs/lang/structs/overview) — the data a method works on - [Extensions](https://rux-lang.dev/docs/lang/structs/extensions) — methods on built-in types - [References](https://rux-lang.dev/docs/lang/references/overview) — what `&T` and `&var T` receivers borrow - Learn: [Method](https://rux-lang.dev/docs/learn/method), [Mutating method](https://rux-lang.dev/docs/learn/mutating-method) # Constructors A *constructor* is a function that builds a value of its type. It is declared in the type's `extend` block with the type's own name, takes no receiver, and returns exactly the type. It is called by the type's name, like a function: `Time(9, 30)`. ```text constructor = [ "pub" ] "func" TypeName "(" [ parameters ] ")" "->" TypeName block // inside extend TypeName ``` ```rux struct Time { hours: int; minutes: int; } extend Time { func Time() -> Time { return Time { hours: 0, minutes: 0 }; } func Time(totalMinutes: int) -> Time { let inDay = totalMinutes % (24 * 60); return Time { hours: inDay / 60, minutes: inDay % 60 }; } func Time(hours: int, minutes: int) -> Time { return Time(hours * 60 + minutes); } } func Main() -> int { let start = Time(7, 95); // 8:35 let later = Time(start.hours * 60 + start.minutes + 135); // 10:50 var midnight: Time; // Time() — 0:00 return 0; } ``` A constructor ends by building the value itself — usually with a [struct literal](https://rux-lang.dev/docs/lang/structs/overview#struct-literals) or by calling another constructor. It does not replace literals; it decides what goes into one, so a rule such as "minutes are below 60" is written once instead of at every literal. | Kind of function | Name | First parameter | Called as | | ---------------- | ------------------- | ------------------------------------ | ------------------ | | Method | anything | `self: &Time`, `&var Time` or `Time` | `start.Show()` | | Static function | anything but `Time` | not `self` | `Time::Midnight()` | | Constructor | `Time`, always | not `self` | `Time(9, 30)` | ## Overloads A type may have any number of constructors, told apart by their parameters like any [overload set](https://rux-lang.dev/docs/lang/functions/overloading). Above, the two-argument constructor converts to minutes and passes the total to the one-argument constructor, so the wrapping past midnight is written once. A call with arguments that no constructor takes is an error naming the candidates, such as `call to 'Time' expects 2 arguments, but 1 was provided` when only the two-argument constructor exists. ## Default construction `var value: T;` with no initializer calls `T()` when the type has a constructor that can be called without arguments: ```rux var midnight: Time; // runs Time() ``` With no such constructor the declaration is still allowed, but it leaves the storage uninitialized, and the compiler refuses to read it before it has been assigned: ```text error: variable 'q' is used before it is initialized ``` See [Initialization](https://rux-lang.dev/docs/lang/bindings/initialization) for how such a local becomes initialized, field by field or as a whole. If more than one constructor can be called with no arguments — `Time()` and `Time(hours: int = 0)` — the declaration is ambiguous: ```text error: default construction of 'Time' is ambiguous note: more than one constructor can be called without arguments help: remove defaults so exactly one constructor accepts no arguments ``` ## Generic types A generic type's constructor is declared in its generic `extend` block and called with the type arguments written out: ```rux struct Pair<T> { first: T; second: T; } extend Pair<T> { func Pair(both: T) -> Pair<T> { return Pair<T> { first: both, second: both }; } } let twins = Pair<int>(7); ``` ## A convenience, not a lock A type with constructors can still be built with a literal wherever its fields are visible, so a constructor's rules can be bypassed inside its package. Making the fields private to the package, and the constructor `pub`, leaves other packages only the constructor; see [Visibility](https://rux-lang.dev/docs/lang/modules/visibility). ## Rules and errors | Mistake | Error | | --------------------------------------------------------------- | ----------------------------------------------------------------------------------------- | | Calling a type that has no constructor | `type 'Point' cannot be called because it has no declared constructor` | | Declaring the constructor outside `extend` | `name 'Time' cannot be declared as a function because it is already a type in this scope` | | A result other than the type | `constructor 'Time' must return exactly 'Time'` | | Two constructors callable with no arguments, and `var t: Time;` | `default construction of 'Time' is ambiguous` | The first error's help names both ways out: `declare a receiverless constructor in its extend block or use explicit initialization`. A function that can fail to build its value — one returning `T?` or `T ! E` — is not a constructor; give it a descriptive name and declare it as a static function, called as `T::Parse(…)`. ## See also - [Structs](https://rux-lang.dev/docs/lang/structs/overview) — struct literals - [Methods](https://rux-lang.dev/docs/lang/structs/methods) — the `extend` block - [Destructors](https://rux-lang.dev/docs/lang/ownership/destructors) — the other end of a value's life - Learn: [Constructor](https://rux-lang.dev/docs/learn/constructor), [Initialization](https://rux-lang.dev/docs/learn/initialization) # Extensions `extend` is not limited to the types a package declares. It can add methods to a built-in type, and from then on every value of that exact type has them: `answer.IsEven()`, `scores[..].Sum()`. ```rux extend int32 { func IsEven(self: int32) -> bool { return self % 2 == 0; } } extend int[..] { func Sum(self: int[..]) -> int { var total = 0; for value in self { total += value; } return total; } } extend var int[..] { func Fill(self: var int[..], value: int) { for i in 0..self.length { self[i] = value; } } } extend char8[..] { func Initial(self: char8[..]) -> char8 { return self[0]; } } func Main() -> int { let n: int32 = 6; PrintLine("{} {}", n.IsEven(), 7i32.IsEven()); // true false let scores = [3, 4, 5]; PrintLine("{} {}", scores[..].Sum(), scores[1..].Sum()); // 12 9 var buffer: int[3] = [0, 0, 0]; buffer[..].Fill(2); PrintLine("{}", "rux".Initial()); // r return 0; } ``` The receiver follows the rules of [Methods](https://rux-lang.dev/docs/lang/structs/methods). Numbers and slices are usually taken by value — `self: int32`, `self: int[..]` — because copying them is as cheap as borrowing them. A slice is a view, so a by-value slice receiver still sees the caller's elements, and a `var T[..]` receiver can write them. ## What can be extended | Type | Extendable | Example | | ------------------------------------------------------------ | ---------------------------- | ---------------------------------------- | | A primitive: integer, float, `bool`, character | yes | `extend int32 { … }` | | A slice of one element type | yes | `extend int[..] { … }` | | A writable slice | yes | `extend var int[..] { … }` | | A struct, enum, variant or union | yes | `extend Point { … }` | | A [type alias](https://rux-lang.dev/docs/lang/types/aliases) | the aliased type is extended | `extend Celsius { … }` adds to `float64` | | An optional, fallible, sum or `()` | no | `cannot extend native type 'int32?'` | | A tuple | no | `extend (int, int)` is refused | | A slice of a type parameter | no | `extend T[..]` is refused | An alias names its type and hides nothing, so `extend Celsius` with `type Celsius = float64;` gives every `float64` in the package those methods. Methods meant for one kind of value belong on a type of its own, such as a struct with a single field. A native optional, fallible, sum or unit has no declaring package to own its methods: ```text error: cannot extend native type 'int32?' note: a sum, optional, fallible, or unit type has no declaring package to own methods or interface implementations help: write a generic function that takes the native type as a parameter ``` `extend T[..]` for every element type is not available; extend each slice type separately, or write a [generic function](https://rux-lang.dev/docs/lang/generics/overview) that takes a `T[..]`: ```text error: cannot extend slice type 'T[..]' because element type 'T' is not defined help: extend a slice of one concrete element type, for example 'extend int[..]' ``` A fixed-size array type can be extended too: the methods of `extend int[3] { … }` are called on an `int[3]` directly, `numbers.First()`. They reach no other length, and no slice. ## One exact type Methods belong to exactly the type that was extended. `extend int32` does not reach `int` or `int64`, `extend int[..]` does not reach `uint8[..]`, and an array is not a slice: ```text error: type 'int32' has no field 'Double' error: type 'int[3]' has no field 'Sum' ``` An array reaches slice methods through a view of itself: `scores[..].Sum()`, or `scores[2..].Sum()` for part of it. A writable view also finds the read-only methods. A view of a `var` array is a `var int[..]`, which finds the methods of both `extend var int[..]` and `extend int[..]`, so `buffer[..].Fill(2)` and `buffer[..].Sum()` both work. A read-only view finds only `extend int[..]`: ```text error: slice type 'int[..]' has no member 'Fill' note: available slice members are 'data' and 'length' ``` ## Interfaces An extension written `extend T : Interface { … }` makes the type implement an interface, and works for built-in types as for declared ones; see [Interfaces](https://rux-lang.dev/docs/lang/interfaces/overview). ## See also - [Methods](https://rux-lang.dev/docs/lang/structs/methods) — receivers and calls - [Slices](https://rux-lang.dev/docs/lang/slices/overview) — read-only and writable views - [Type aliases](https://rux-lang.dev/docs/lang/types/aliases) — what an alias does and does not create - Learn: [Extension](https://rux-lang.dev/docs/learn/extension) # Enums An `enum` declares a closed set of named values, its *cases*, stored as an integer. A `Direction` is `North`, `East`, `South` or `West` and nothing else, and the compiler knows every case, so a `match` can be checked for completeness. An enum case carries no data; cases with data belong to a [variant](https://rux-lang.dev/docs/lang/variants/overview). ```text enum = [ attributes ] [ "pub" ] "enum" name [ ":" integer-type ] "{" [ case { "," case } ] "}" case = name [ "=" constant-expression ] ``` ```rux enum Direction { North, East, South, West } enum Status: uint16 { Ok = 200, Created, NotFound = 404, ServerError = 500 } ``` Cases are separated by commas, with no comma after the last (`trailing comma is not allowed in enum declarations`). By convention the type and its cases are PascalCase. ## Backing type and values The integer type after the colon is the enum's *backing type*: every value of the enum is stored as one value of it, so `sizeof(Status)` is 2. It must be an integer type — `enum 'Wide' base type must be an integer type` otherwise. Without one, the backing type is `int`. Each case has an integer value. A case may give it with `=`; a case without one takes the previous case's value plus one, and the first case defaults to 0: | Case | Value | | ------------------ | ----- | | `Direction::North` | 0 | | `Direction::West` | 3 | | `Status::Ok` | 200 | | `Status::Created` | 201 | | `Status::NotFound` | 404 | Values may be negative when the backing type is signed: ```rux enum Ordering: int8 { Less = -1, Equal, Greater } ``` Once other programs read these numbers — a file format, a network protocol, a C library — they are part of the program's interface. Inserting an unnumbered case in the middle renumbers every unnumbered case after it, so give each case whose value matters an explicit `=`. Every value must fit the backing type, whether it is written with `=` or follows the previous case: ```text error: enumerator 'Size::Big' has the value 300, which the backing type 'uint8' cannot hold help: give it a value inside the backing type's range, or declare a wider backing type ``` A case without `=` after a `uint8` case of 255 has the value 256 and is refused the same way. ## Naming a case A case is named through its type: `Direction::North`. Inside a pattern whose subject is already known to be a `Direction`, the short form `.North` is allowed; everywhere else the case is written in full: ```rux var heading = Direction::North; let back = heading == Direction::North; // true ``` ```text error: '.North' must be written in full, as in 'Direction::North' ``` A case on its own, `North`, is an unknown name. ## Conversions `as` converts in both directions between an enum and any integer type: ```rux let code = Status::NotFound as uint16; // 404 let received: uint16 = 404; let status = received as Status; // Status::NotFound ``` No other conversion applies: an enum does not convert to a float, and a case is not its number, so `Status::Ok == 200` is `operator '==' cannot compare left operand 'Status' with right operand 'int'`. **`as` does not check.** Converting an integer that is no case's value gives an enum value that is none of the cases. Nothing goes wrong until a `match` meets it: a match without an `else` arm then stops the program with `Panic: no match arm matched value of 'Status'`. Check a number from outside the program before converting it. ## Comparison Enum values compare with `==`, `!=`, `<`, `<=`, `>` and `>=`, which order them by their values: ```rux let failed = status >= Status::NotFound; // true for 404 and 500 ``` ## Matching A `match` on an enum must cover every case, or end with an `else` arm. An arm names one case: ```rux func TurnRight(direction: Direction) -> Direction { return match direction { .North => Direction::East, .East => Direction::South, .South => Direction::West, .West => Direction::North }; } ``` ```text error: match on 'Direction' is not exhaustive; missing Direction::West ``` Leaving `else` out when every case matters means adding a case later makes every incomplete `match` stop compiling, at the place that needs the new arm. See [`match`](https://rux-lang.dev/docs/lang/patterns/match). ## Methods An enum can be extended with methods like any other type. A receiver taken by value, `self: Direction`, is natural for something as small as a number: ```rux extend Direction { func Opposite(self: Direction) -> Direction { return (((self as int) + 2) % 4) as Direction; } } ``` An enum value cannot be printed with `{}` directly; give it a method that returns its name. ## Rules and errors | Mistake | Error | | ---------------------------------------- | -------------------------------------------------------------------------------------------- | | A case with a payload, `Circle(float64)` | `enum 'Shape' cannot declare payloads`, with `help: use 'variant' for cases that carry data` | | Type parameters, `enum Gen<T>` | `enum 'Gen' cannot declare type parameters` | | A non-integer backing type | `enum 'Wide' base type must be an integer type` | | A case declared twice | `duplicate enumerator 'A' in enum 'Twice'` | | The short form outside a pattern | `'.North' must be written in full, as in 'Direction::North'` | | A missing case in a `match` | `match on 'Direction' is not exhaustive; missing Direction::West` | ## See also - [Variants](https://rux-lang.dev/docs/lang/variants/overview) — cases that carry data - [Casts](https://rux-lang.dev/docs/lang/expressions/casts) — `as` in general - [Patterns](https://rux-lang.dev/docs/lang/patterns/patterns) — case patterns - Learn: [Enum](https://rux-lang.dev/docs/learn/enum), [Enum value](https://rux-lang.dev/docs/learn/enum-value) # Variants A `variant` declares a type whose value is exactly one of a closed list of *cases*, and each case may carry data of its own. A thermometer reading is missing, or an exact temperature, or a range between two: three cases, two of them with numbers. A struct holds all of its fields at once; a variant holds one case at a time, and only that case's data. ```text variant = [ attributes ] [ "pub" ] "variant" name [ type-parameters ] "{" [ case { "," case } ] "}" case = name // unit | name "(" type { "," type } ")" // positional | name "{" { name ":" type ";" } "}" // named ``` ```rux variant Reading { Missing, Exact(float64), Between { low: float64; high: float64; } } ``` Cases are separated by commas, with no comma after the last. Named fields inside a case end with `;`, as struct fields do. | Case | Shape | Carries | Built as | | --------- | ------------------------------------- | ---------------- | -------------------------------------------- | | `Missing` | unit — a bare name, like an enum case | nothing | `Reading::Missing` | | `Exact` | positional — values by position | one `float64` | `Reading::Exact(21.5)` | | `Between` | named — fields by name | `low` and `high` | `Reading::Between { low: 20.0, high: 24.0 }` | A positional case may carry any number of values, `Jump(int, int)`. The three shapes may be mixed freely in one variant. ## Building a case A case is built through its type's name, with the syntax of its shape: nothing for a unit case, call syntax for a positional one, struct-literal syntax for a named one. The fields of a named case may come in any order, and every field must be given: ```rux func Measure(low: float64, high: float64) -> Reading { if low > high { return Reading::Missing; } if low == high { return Reading::Exact(low); } return Reading::Between { low: low, high: high }; } ``` A unit case may also be written with empty parentheses, `Reading::Missing()`. The payload is checked against the case's declaration like a call's arguments: ```text error: argument 1 to variant case 'Reading::Exact' has type 'int', but field 1 requires 'float64' error: initializer for 'Reading::Between' is missing required field 'high' ``` A named case takes its fields by name, both when it is built and when it is [matched](https://rux-lang.dev/docs/lang/variants/matching): `Reading::Between(20.0, 24.0)` and the pattern `.Between(low, high)` are refused. ```text error: variant case 'Reading::Between' has named fields, so it cannot be built with call syntax help: write 'Reading::Between { low: ..., high: ... }' error: pattern for 'Reading::Between' binds its fields by position, but the case names them help: match it by name, as '.Between { low, high }' ``` ## Reading the data A variant has no fields of its own to read: the data belongs to one case, and which case is held is known only at run time. `reading.0` is refused with `type 'Reading' has no field '0'`. The data is taken out with [`match`](https://rux-lang.dev/docs/lang/variants/matching), which tests the case and binds its payload in one step: ```rux func Describe(reading: Reading) -> float64 { return match reading { .Missing => 0.0, .Exact(value) => value, .Between { low, high } => (low + high) / 2.0 }; } ``` ## Equality Two variant values are equal when they hold the same case and that case's payloads are equal, compared in declaration order. Different cases are never equal, whatever they carry: ```rux let precise = Reading::Exact(21.5); let same = precise == Reading::Exact(21.5); // true let other = precise == Reading::Missing; // false ``` Every payload type of every case must support `==`. A variant with a case carrying a `char8[..]`, which has no `==`, cannot be compared at all: ```text error: variant equality for 'Token' is unavailable because payload type 'char8[..]' in case 'Token::Word' has no '==' operator ``` Variants have no built-in ordering. ## Generic variants A variant may take type parameters, used in its payloads: ```rux variant Lookup<T> { Found(T), Missing } ``` A case with a payload infers the type arguments from it: `Lookup::Found(5)` is a `Lookup<int>`. A case without one takes them from the type it is assigned, passed or returned as, or names them itself: ```rux let hit = Lookup::Found(5); // Lookup<int> let miss: Lookup<int> = Lookup::Missing; let empty = Lookup::Missing<int>(); ``` ```text error: variant case 'Lookup::Missing' requires 1 type argument, but 0 were provided help: annotate the destination, as in 'let value: Lookup<...> = Lookup::Missing;', or write 'Lookup::Missing<...>()' ``` An annotation wins over the payload: `let small: Lookup<uint8> = Lookup::Found(7);` makes the `7` a `uint8`. See [Generic types](https://rux-lang.dev/docs/lang/generics/types). ## The tag is private A variant value stores a *tag* that says which case it holds, followed by storage for the largest case. The tag belongs to the compiler: a variant has no backing type and no case values, and it does not convert to or from an integer. | Written | Error | | ------------------------------- | ----------------------------------------------------- | | `variant Code: uint8 { A, B }` | `variant 'Code' cannot specify a base type` | | `variant Numbered { A = 1, B }` | `variant 'Numbered' cannot assign case discriminants` | | `precise as int` | `cannot cast variant 'Reading' to scalar type 'int'` | The tag's numbers are not part of any contract and must never be written to a file or sent to another program. Data that crosses a program's boundary as numbers is encoded with an [enum](https://rux-lang.dev/docs/lang/enums/overview), whose values are chosen in the source, and translated to and from the variant. A variant is copyable when every payload is, and is moved otherwise; destroying one destroys only the active case's payload. See [Copy and move](https://rux-lang.dev/docs/lang/ownership/copy-and-move). ## Recursive variants A variant cannot contain itself by value, but a case may hold a pointer to another value of the same variant: ```rux variant Tree { Leaf(int), Node { left: *Tree; right: *Tree; } } ``` ## Variants, enums, structs and unions | Declaration | Holds | Data per alternative | Which one is held is… | | ----------- | ------------------- | -------------------- | --------------------------------------- | | `struct` | every field at once | — | not a question: all are | | `enum` | one case | none | its integer value, chosen in the source | | `variant` | one case | any | a private tag, checked by `match` | | `union` | one member's bytes | any | not recorded; the program must know | ## See also - [Matching variants](https://rux-lang.dev/docs/lang/variants/matching) — patterns, bindings and exhaustiveness - [Enums](https://rux-lang.dev/docs/lang/enums/overview) — cases without data, with integer values - [Sum types](https://rux-lang.dev/docs/lang/sums/overview) — a value of one of several types, without case names - [Unions](https://rux-lang.dev/docs/lang/unions/overview) — overlapping storage without a tag - Learn: [Variant](https://rux-lang.dev/docs/learn/variant), [Variant match](https://rux-lang.dev/docs/learn/variant-match), [Generic type](https://rux-lang.dev/docs/learn/generic-type) # Matching variants A variant's payload can only be read once it is known which case is held, and `match` does both in one step. A *case pattern* fits only values of its case, and when it fits, the names inside it are new bindings holding that case's data. No pattern can both fit a `Turn` and bind a `Forward`'s data, which is the guarantee a variant gives. ```rux variant Command { Forward(int), Turn, Jump(int, int), Stop } func Cost(command: Command) -> int { return match command { .Forward(steps) => steps, .Turn => 1, .Jump(across, _) => across * 2, .Stop => 0 }; } ``` This page covers what is particular to variants. The `match` expression and statement, arms, guards and every other kind of pattern are described in [`match`](https://rux-lang.dev/docs/lang/patterns/match) and [Patterns](https://rux-lang.dev/docs/lang/patterns/patterns). ## Case patterns ```text case-pattern = ( "." | VariantType "::" ) case-name [ payload-pattern ] payload-pattern = "(" pattern { "," pattern } ")" // positional case | "{" field-pattern { "," field-pattern } "}" // named case field-pattern = name [ ":" pattern ] ``` | Pattern | Fits | Binds | | ------------------------ | -------------------------------- | --------------------------------- | | `.Stop` | the unit case `Stop` | nothing | | `.Forward(steps)` | every `Forward` | `steps`, its one value | | `.Jump(across, _)` | every `Jump` | `across`; `_` ignores the second | | `.Jump(across, 0)` | a `Jump` whose second value is 0 | `across` | | `.Say { text }` | every `Say` | the field `text`, as `text` | | `.Say { text: message }` | every `Say` | the field `text`, as `message` | | `.Say { loud: true }` | a `Say` whose `loud` is `true` | nothing; other fields are ignored | | `Command::Stop` | the unit case `Stop` | nothing | - **The short form `.Case`** is allowed wherever the subject's type is known to be the variant. `Type::Case` names the type as well, and is needed where the subject is a [sum](https://rux-lang.dev/docs/lang/sums/overview) containing the variant. - **A positional payload lists every value**, each as a pattern: a name binds it, `_` ignores it, a literal or a nested pattern tests it. The count must match the case: `pattern for 'Command::Jump' expects 2 fields, but found 1`. - **A named payload may leave fields out**; an omitted field matches anything. A field written alone binds a variable of its own name, and `field: pattern` binds or tests it under another name. The fields may come in any order. - **A unit case is written without parentheses**, `.Stop`. Patterns nest. A payload pattern can be another case pattern, an [enum](https://rux-lang.dev/docs/lang/enums/overview) case, a tuple or a struct pattern: ```rux enum Direction { North, East, South, West } variant Command { Move(Direction, int), Jump(int, int), Say { text: char8[..]; loud: bool; }, Stop } func Describe(command: &Command) -> char8[..] { return match command { .Move(.North, 0) => "face north", .Move(_, steps) if steps > 10 => "a long walk", .Move(_, _) => "a walk", .Jump(across, 0) => across > 3 ? "a long flat jump" : "a flat jump", .Jump(_, _) => "a jump", .Say { loud: true } => "a shout", .Say { text } => text, Command::Stop => "stop" }; } ``` Arms are tried from top to bottom, and the first that fits runs, so a specific arm goes above the general one for the same case. An arm may add a guard, `if condition`, which is checked after the pattern fits and may use its bindings; when the guard is false the next arm is tried. ## Bindings A binding exists only inside its own arm: `steps` is unknown in the `.Turn` arm, and using it there is `name 'steps' is not defined in this scope`. When the subject is a value the `match` owns, the bindings take the payload over. When the subject is a reference, as `command: &Command` above, the case is matched in place and the bindings read the payload where it lies; nothing is copied out of the caller's value. A bare name in a pattern always binds a new variable. A name that is a case of the subject is refused rather than silently matching everything: ```text error: pattern 'Stop' cannot bind a new variable because 'Stop' is a case of variant 'Command' help: write 'Command::Stop' to select the case ``` ## Exhaustiveness A `match` on a variant — an expression or a statement — must cover every case. A missing case is named: ```text error: match on 'Command' is not exhaustive; missing Command::Stop ``` A case counts as covered by an arm that fits **every** value of it: a unit pattern, or a payload pattern made only of bindings and `_`, without a guard. An arm with a guard, or one that tests a payload value such as `.Move(_, 0)`, covers only part of the case, so the case still needs a general arm below it — unless the unguarded payload tests of its arms together match every value. Payload tests combine: `.Light(true)` and `.Light(false)` together cover `Light`, since together they match every value, just as the same two tests do on a [tuple](https://rux-lang.dev/docs/lang/tuples/overview). An `else` arm covers whatever the arms above it leave, and makes a match exhaustive. Prefer naming every case: with `else`, a case added to the variant later falls silently into the `else` arm, while without it every incomplete `match` stops compiling at the place that needs the new arm. The default arm is spelled `else`; `_ =>` is `use 'else' for the default match arm`. Two arms with the same pattern are `duplicate pattern in match`. ## See also - [Variants](https://rux-lang.dev/docs/lang/variants/overview) — declaring and building cases - [`match`](https://rux-lang.dev/docs/lang/patterns/match) — the expression and statement - [Patterns](https://rux-lang.dev/docs/lang/patterns/patterns) — every kind of pattern - Learn: [Variant match](https://rux-lang.dev/docs/learn/variant-match), [Guard](https://rux-lang.dev/docs/learn/guard), [Exhaustive](https://rux-lang.dev/docs/learn/exhaustive) # Unions A `union` declares a type whose *members* all share one piece of storage. A value holds the bytes of one member, and reading any member reads those same bytes as that member's type — nothing is converted and nothing is checked. A union records no tag, so the program, or the foreign interface it talks to, is responsible for knowing which member is meaningful. ```text union = [ attributes ] [ "pub" ] "union" name "{" [ member { "," member } [ "," ] ] "}" member = name ":" type ``` ```rux union Bits { asFloat: float32, asUnsigned: uint32, asBytes: uint8[4] } ``` Members are separated by commas, unlike struct fields; a `;` after a member is `expected ',' between union fields before ';'`. ## Building a union A union literal names exactly one member and gives its value: ```rux let one = Bits { asFloat: 1.0f32 }; ``` Naming none, or more than one, is an error: `union initializer for 'Bits' must select exactly one field, but 2 were provided`. `var bits: Bits;` declares a union without a value. Writing any one member initializes it, and from then on every member may be read. ## Reading and writing members Members are read and written with `.`, like struct fields. Every member starts at the same address, so a write through one member is seen through all the others, reinterpreted: ```rux let one = Bits { asFloat: 1.0f32 }; PrintLine("{:x}", one.asUnsigned); // 3f800000, the bit pattern of 1.0 PrintLine("{}", one.asBytes[3]); // 63, its high byte on a little-endian target var bits = Bits { asUnsigned: 0x40000000u32 }; PrintLine("{}", bits.asFloat); // 2.0 bits.asBytes[3] = 0x3Fu8; PrintLine("{}", bits.asFloat); // 0.5 ``` Reading a member other than the one last written is not an error; it is the reason a union exists. The result depends on the target's byte order and on the members' representations, so code that relies on it is code about a particular layout. A member narrower than the union leaves the rest of the storage as it was: writing a `uint8` member of a union that also holds a `uint64` changes only the low byte. ## Layout A union is as large as its largest member, rounded up to its alignment, and as aligned as its most-aligned member. `sizeof(Bits)` is 4. See [Memory layout](https://rux-lang.dev/docs/lang/memory/layout). A union is a value: assigning it copies its bytes, and the copy is independent of the original. ## No ownership A union does not know which member it holds, so it never runs a destructor for any member. A member whose type has a destructor is stored without it ever running; keep such values out of unions, or destroy them by hand. ## When to use a union | Use | Instead | | -------------------------------------------------- | ---------------------------------------------------------------------------------------------- | | A C `union` in a foreign interface | — | | Examining the bits of a value of another type | — | | One of several alternatives, known by the compiler | a [variant](https://rux-lang.dev/docs/lang/variants/overview), whose tag is checked by `match` | | A value of one of several types | a [sum type](https://rux-lang.dev/docs/lang/sums/overview) | ## See also - [Variants](https://rux-lang.dev/docs/lang/variants/overview) — alternatives with a tag - [FFI](https://rux-lang.dev/docs/lang/ffi/overview) — unions in foreign interfaces - [Memory layout](https://rux-lang.dev/docs/lang/memory/layout) — sizes and alignment - Learn: [Union](https://rux-lang.dev/docs/learn/union) # Tuples A tuple groups a fixed number of values, possibly of different types, into one value without declaring a type for it. The elements have positions but no names. The type is written like the value: a parenthesized, comma-separated list. ```text tuple-type = "(" ")" | "(" type "," ")" | "(" type "," type { "," type } [ "," ] ")" tuple-value = "(" ")" | "(" expression "," ")" | "(" expression "," expression { "," expression } [ "," ] ")" ``` ```rux let pair: (int, float64) = (1, 2.5); let triple = ("Rux", 3, true); // (char8[..], int, bool) let one = (5,); // a tuple of one element ``` A one-element tuple needs a trailing comma; `(5)` is just `5` in parentheses. ## Elements Elements are read by position, counting from zero: `.0`, `.1`, and so on. On a `var` tuple they can be assigned the same way. Tuples nest, and so do the accesses: ```rux var point = (0, 0); point.0 = 4; point = (point.0, 9); // (4, 9) let nested: (int, (char8[..], bool)) = (1, ("deep", true)); let word = nested.1.0; // "deep" ``` An index beyond the last element is a compile-time error: `tuple index 2 is out of range for a tuple with 2 elements`. ## Type identity A tuple type is its element types, in order. `(int, float64)` and `(float64, int)` are different types, and two tuples with the same element types are the same type wherever they were written — a tuple has no name to tell it apart: ```text error: cannot assign '(int, float64)' to '(float64, int)' ``` A tuple is a value. Assigning it, passing it and returning it copies every element, and the copy is independent of the original. A tuple is how a function returns several values: ```rux func Divide(dividend: int, divisor: int) -> (int, int) { return (dividend / divisor, dividend % divisor); } ``` The usual way to use such a result is to take it apart at once, `let (quotient, remainder) = Divide(17, 5);`; see [Destructuring](https://rux-lang.dev/docs/lang/bindings/destructuring). ## The unit type `()` is the tuple with no elements, the *unit* type, and its only value is also written `()`. It is the success type of a fallible function that produces nothing on success: `! E` is exactly `() ! E`. A function may return `()` explicitly, `func Reset() -> ()`, which is not the same as leaving out the result type; see [Function declarations](https://rux-lang.dev/docs/lang/functions/declaration#the-result). `sizeof(())` is 0. ## Equality Two tuples of the same type compare with `==` and `!=`, element by element from left to right, stopping at the first difference. Every element type must support `==`: ```rux let same = (1, 'a') == (1, 'a'); // true let differ = (1, 2) != (1, 3); // true ``` ```text error: structural equality for '(int, char8[..])' is unavailable because element type 'char8[..]' has no '==' operator ``` Tuples have no built-in ordering. `(1, 2) < (1, 3)` is `operator '<' is not defined for tuple '(int, int)'`, with the note `tuples have structural equality but no built-in ordering`. ## Matching A tuple pattern takes a tuple apart in a `match` arm and tests its elements at the same time. A `match` on a tuple is exhaustive when the combinations of its arms cover every value, so the four `(bool, bool)` combinations need no `else`: ```rux func Describe(flags: (bool, bool)) -> char8[..] { return match flags { (true, true) => "both", (true, false) => "first", (false, true) => "second", (false, false) => "neither" }; } ``` See [Patterns](https://rux-lang.dev/docs/lang/patterns/patterns). ## Tuples or structs Both group several values. A tuple's elements are anonymous, so nothing at the use says what `.1` means; a struct's are named, and the struct is a type of its own that cannot be mixed up with another of the same shape. | A tuple fits when… | A struct fits when… | | ------------------------------------------------------- | ------------------------------------------------- | | two or three values, their meaning obvious from context | more values, or meanings that need labels | | the grouping is local, such as a function's results | the type is used across the program | | no behaviour is attached | the type needs methods, constructors or operators | | any `(int, int)` will do | a `Point` must not be confused with a `Size` | Tuples cannot be extended with methods; see [Extensions](https://rux-lang.dev/docs/lang/structs/extensions). ## Layout A tuple's elements are stored in order, each at the next offset its alignment allows, like the fields of a struct: `sizeof((uint8, uint32))` is 8. See [Memory layout](https://rux-lang.dev/docs/lang/memory/layout). ## See also - [Destructuring](https://rux-lang.dev/docs/lang/bindings/destructuring) — unpacking a tuple into bindings - [Structs](https://rux-lang.dev/docs/lang/structs/overview) — named fields and named types - [Patterns](https://rux-lang.dev/docs/lang/patterns/patterns) — tuple patterns - Learn: [Tuple](https://rux-lang.dev/docs/learn/tuple), [Destructure](https://rux-lang.dev/docs/learn/destructure), [Tuple pattern](https://rux-lang.dev/docs/learn/tuple-pattern) # Arrays An *array* `T[N]` is a fixed number `N` of values of one type `T`, stored side by side. The count is part of the type, so `int32[3]` and `int32[4]` are different types, and an array never grows or shrinks. An array *is* its elements: it holds them inline, with no pointer, header or allocation, and it lives wherever its binding lives — in a local, inside a struct, inside another array. ```text array-type = type "[" constant-expression "]" array-literal = "[" [ expression { "," expression } [ "," ] ] "]" repeat-literal = "[" expression ";" constant-expression "]" ``` ```rux let primes: int32[4] = [2, 3, 5, 7]; let rgb: uint8[3] = [255, 128, 0]; let zeros: float64[8] = [0.0; 8]; ``` ## The type `N` must be a non-negative integer known at compile time: a literal or a [constant](https://rux-lang.dev/docs/lang/bindings/constants). A run-time value is rejected: ```rux const Limit: uint = 100; var flags: bool[Limit] = [false; Limit]; ``` ```text error: array length must be a non-negative compile-time integer ``` A range where the length goes, as in `int[0..4]`, gets the same error with the help line `write 'T[..]' for a slice` — `T[..]` is the [slice](https://rux-lang.dev/docs/lang/slices/overview) type, a view of some number of elements. The element type can be any type, including another array. Each `[N]` wraps everything written before it, so a nested array type reads inside out: `int32[4][3]` is three rows of four `int32` values. Indexing reads outside in: `grid[row]` is an `int32[4]`, and `grid[row][column]` is one `int32`. ```rux let grid: int32[4][3] = [ [1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12] ]; ``` ## Array literals `[a, b, c]` lists the elements in order. Its type is `T[N]`, where `N` is the number of elements and `T` comes from the context — an annotation, a parameter, a field — or, without one, from the first element: ```rux let inferred = [2, 3, 5, 7]; // int[4] let reals = [1.5, 2.5]; // float64[2] let bytes: uint8[3] = [1, 2, 255]; // the context types every element ``` Every element must convert to one element type, and the count must match the type exactly: ```text error: array element 2 has type 'bool8', but element 1 established element type 'int' error: cannot assign 'int[3]' to 'int32[4]' ``` ### Repeated literals `[value; count]` builds an array of `count` copies of one value. The value is evaluated **exactly once**, and the result is copied into every element, so `[Roll(); 4]` calls `Roll` once and its four elements are always equal. `count` follows the same rule as `N`: a non-negative compile-time integer. ```rux let zeros: int32[16] = [0; 16]; let rolls = [Roll(); 4]; // one call, four copies var board: int32[3][3] = [[0; 3]; 3]; // nests: three copies of a row ``` ```text error: array repeat count must be a non-negative compile-time integer ``` The element type must be copyable; move-only elements are listed, each handed over with `<-`, or written in a loop. A count of zero still evaluates the value once, and destroys it if its type needs destruction. A move into an array literal works with a type annotation or without one: with a move-only `k`, both `let b: Key[1] = [<-k];` and `let b = [<-k];` take `k`, and a later use of it is `value 'k' is used after it was moved`. ## Value semantics An array is a value, like a [struct](https://rux-lang.dev/docs/lang/structs/overview) or a [tuple](https://rux-lang.dev/docs/lang/tuples/overview). Assigning it, passing it by value and returning it copy **every element**, and the two arrays share nothing afterwards: ```rux var scores: int32[3] = [10, 20, 30]; var copy = scores; copy[0] = 99; // scores is still [10, 20, 30] ``` The binding decides mutability for the whole array: through a `let` binding no element can change, while a `var` binding allows both element writes and whole-array assignment. ```text error: cannot modify immutable variable 'primes' help: declare 'primes' with 'var' to make it mutable ``` To hand an array to a function without copying it, take a [reference](https://rux-lang.dev/docs/lang/references/overview) to it, `&T[N]` or `&var T[N]`, or pass a [slice](https://rux-lang.dev/#arrays-as-slices), which also accepts every length. ```rux func Bump(values: &var int32[4]) { values[0] += 100; } ``` Two arrays of the same type are equal when every element is: `==` and `!=` compare element by element, whatever the length, and either side may be an array literal, as in `a == [1, 2, 3, 4]`. Arrays have no ordering, so `<`, `<=`, `>` and `>=` on them are refused; compare the elements in the order you mean: ```text error: operator '<' is not defined for array 'int32[2]' ``` ## Length `.length` is the element count `N`, a `uint`. It is fixed by the type, so it never changes and costs nothing to read: ```rux let buffer: float64[8] = [0.0; 8]; let count = buffer.length; // 8 ``` `.length` is an array's only member. An array has no `.data`: its first element's address is `@a[0]`, and `a[..].data` is the data pointer of a view of it. ## Indexing `a[i]` is the element at position `i`, counting from zero, so valid indexes run from `0` to `a.length - 1`. The index may have any integer type. The result is a place: it can be read, written with `=`, `<-` or a compound assignment when the array is writable, borrowed, and have its address taken with `@`. ```rux var row: int32[3] = [10, 20, 30]; let first = row[0]; row[2] = 99; row[1] += 5; ``` Every index is checked, on every target and in every build profile: - A **constant** index into an array is checked when the program is compiled: ```text error: index 7 is out of range for an array of 4 elements help: valid indexes are 0 through 3 ``` - An index computed at run time is checked as the program runs. One that does not name an element — a negative index included — stops the program instead of reading the memory beyond the array, and the message names the function, file, line and column of the subscript: ```rux func At(values: int32[4], i: uint) -> int32 { return values[i]; } func Main() -> int { let primes: int32[4] = [2, 3, 5, 7]; return At(primes, 4) as int; } ``` ```text Panic: index out of range at At (Src/Main.rux:2:18) ``` :brSee [Panics](https://rux-lang.dev/docs/lang/errors/panics). A release build removes a check it can prove always passes. The index must be an integer or a [range](https://rux-lang.dev/docs/lang/ranges/overview); anything else is `index for type 'int[2]' must be an integer or range, but has type 'float64'`. Indexing with a range produces a slice — see [below](https://rux-lang.dev/#arrays-as-slices). ## Iteration `for` walks an array's elements in order, binding each one to the loop variable. To know the position as well, walk the indexes with a range: ```rux var sum: int32 = 0; for prime in primes { sum += prime; } for i in 0..primes.length { PrintLine("primes[{}] = {}", i, primes[i]); } ``` A nested array yields whole rows, each an ordinary array. See [Loops](https://rux-lang.dev/docs/lang/statements/loops). ## Arrays as slices An array is contiguous elements with a known count, so it can always be viewed as a [slice](https://rux-lang.dev/docs/lang/slices/overview) — a pointer to the first element and a length, with nothing copied. - **Implicitly, read-only.** A `T[N]` converts to a read-only `T[..]` wherever one is expected: an argument, a binding, a return. One function taking a slice therefore serves arrays of every length. - **Explicitly, with a range.** `a[..]` views the whole array, and `a[i..j]`, `a[i..]`, `a[..j]` and `a[..=j]` view part of it. The view is writable, `var T[..]`, when the array place is — a `var` local, or an array reached through `&var` — and read-only otherwise. ```rux func Total(values: int32[..]) -> int32 { var sum: int32 = 0; for value in values { sum += value; } return sum; } func Fill(values: var int32[..], value: int32) { for i in 0..values.length { values[i] = value; } } func Main() -> int { var storage: int32[5] = [1, 2, 3, 4, 5]; let whole = Total(storage); // the array, viewed read-only let tail = Total(storage[2..]); // 3 + 4 + 5 Fill(storage[..2], 0); // a writable view of the first two return 0; } ``` A writable parameter never takes the array itself, which only converts to a read-only view; hand it `storage[..]`: ```text error: no matching overload for 'Fill' with argument types (int32[5], int) ``` ## Flexible tails `T[]`, with no count, is a *flexible tail*. It is allowed in exactly one place — as the last field of a struct — and describes elements that follow the struct in memory, in storage allocated larger than the struct itself: ```rux struct Packet { length: uint32; bytes: uint8[]; } ``` The tail contributes its alignment to the struct but no storage, so `sizeof(Packet)` is 4. It has no length and no members of its own — the struct records the count, here in `length`. A tail is indexed like a pointer: `packet.bytes[i]` reads or writes element `i` with no bounds check, so keeping `i` below the allocated count is up to the program. Slicing it with that count, `packet.bytes[..count]`, gives a checked view: ```rux import Memory::{ Alloc, Free }; func Main() -> int { let count: uint = 3; let packet = Alloc(sizeof(Packet) + count) as *var Packet; if packet == null { return 1; } defer Free(packet); packet.length = 3; packet.bytes[0] = 7; let bytes = packet.bytes[..count]; bytes[1] = 8; return 0; } ``` A flexible tail anywhere else — a field that is not last, a union member, a local, a parameter, a return type, an operand of `sizeof` — is an error: ```text error: flexible array type is only allowed as the final field of a struct ``` Because a tail has no length, a range index on it needs an end bound, and a `for` loop cannot walk it; iterate the view instead, as in `for value in packet.bytes[..count]`: ```text error: cannot slice flexible array 'uint8[]' without an end bound error: cannot iterate over flexible array 'uint8[]' ``` ## See also - [Slices](https://rux-lang.dev/docs/lang/slices/overview) — the `T[..]` view an array is passed as - [Ranges](https://rux-lang.dev/docs/lang/ranges/overview) — the bounds used to slice an array and to walk its indexes - [Tuples](https://rux-lang.dev/docs/lang/tuples/overview) — a fixed sequence of values of different types - [Layout](https://rux-lang.dev/docs/lang/memory/layout) — the size and alignment of an array and of a struct with a flexible tail - Learn: [Array](https://rux-lang.dev/docs/learn/array), [Array repeat](https://rux-lang.dev/docs/learn/array-repeat), [Array nested](https://rux-lang.dev/docs/learn/array-nested) # Slices A *slice* is a view of a run of contiguous elements that belong to something else — an array, an allocation, the text of a string literal. It holds two things: where the first element is, and how many elements there are. It owns none of them, so copying a slice copies only those two words, whatever its length. There are two slice types: | Type | Name | Through the view you may | | ----------- | --------------- | --------------------------- | | `T[..]` | read-only slice | read the elements | | `var T[..]` | writable slice | read and write the elements | ```text slice-type = [ "var" ] type "[" ".." "]" slicing = expression "[" range-expression "]" ``` The `..` reads as "some number of": the element type is fixed, the count is carried in the value. One function taking an `int32[..]` therefore accepts every length. ```rux func Total(values: int32[..]) -> int32 { var sum: int32 = 0; for value in values { sum += value; } return sum; } ``` ## Making a slice | From | Written | Gives | | ------------------------------------------------------------------------ | ------------------------------- | ---------------------------------------------------------- | | an [array](https://rux-lang.dev/docs/lang/arrays/overview), implicitly | `Total(numbers)` | `T[..]` of the whole array | | an array, with a range | `numbers[..]`, `numbers[1..4]` | `var T[..]` from a writable array place, `T[..]` otherwise | | another slice, with a range | `view[1..]` | the same writability as `view` | | a [pointer](https://rux-lang.dev/docs/lang/pointers/slicing) and a count | `p[..n]`, `p[a..b]` | `var T[..]` from `*var T`, `T[..]` from `*T` | | a [string literal](https://rux-lang.dev/docs/lang/types/text) | `"hello"` | `char8[..]`, always read-only | | an array literal | `let v: int32[..] = [1, 2, 3];` | a view of the literal's elements | | the empty literal | `let e: var int32[..] = [];` | a view of nothing, with `null` data | A string literal is a `char8[..]` — or a `char16[..]` or `char32[..]` with a `c16` or `c32` prefix — over text stored in a read-only section of the program. Its `.length` counts code units, not characters. See [Text](https://rux-lang.dev/docs/lang/types/text). ## Slicing Indexing an array, a slice or a pointer with a [range](https://rux-lang.dev/docs/lang/ranges/overview) produces a slice of part of it. An omitted start means the first element, an omitted end the last: | Expression | Elements of `[10, 20, 30, 40, 50]` | Meaning | | ---------------- | ---------------------------------- | --------------------------------- | | `numbers[1..4]` | 20, 30, 40 | indexes 1 up to, not including, 4 | | `numbers[1..=3]` | 20, 30, 40 | indexes 1 to 3 inclusive | | `numbers[2..]` | 30, 40, 50 | from index 2 to the end | | `numbers[..2]` | 10, 20 | from the start up to 2 | | `numbers[..=1]` | 10, 20 | from the start to 1 inclusive | | `numbers[..]` | all five | the whole sequence | A range held in a variable slices the same way: with `let r: int..int = 1..4;`, `numbers[r]` is `numbers[1..4]`. A slice of a slice counts from the start of the **view**, not of the storage beneath it: ```rux let numbers: int32[5] = [10, 20, 30, 40, 50]; let middle = numbers[1..4]; // 20, 30, 40 let inner = middle[1..]; // 30, 40 ``` Nothing is copied: every one of these views points into `numbers`. A range subscript is checked like an index. `s[start..end]` needs `start <= end <= s.length`, and an inclusive end must be below the length. Bounds written as literals that run backwards are rejected while compiling, and so is a constant bound past the end of a fixed array, such as `numbers[1..9]` on an `int32[5]`; anything else that falls outside the sequence stops the program: ```text error: range start cannot be greater than its end error: slice end 9 is out of range for an array of 5 elements ``` ```text Panic: index out of range ``` ## Members | Member | Type | Meaning | | --------- | ------------------------------------------ | -------------------------------- | | `.length` | `uint64` | the number of elements | | `.data` | `*T` for `T[..]`, `*var T` for `var T[..]` | the address of the first element | `.data` is a raw [pointer](https://rux-lang.dev/docs/lang/pointers/overview), for code that has to leave the language's checks behind — handing a buffer to a [foreign function](https://rux-lang.dev/docs/lang/ffi/overview), for one. The data of an empty slice may be `null`. ## Indexing and iteration `s[i]` is the element at position `i` of the view, counting from zero, with an index of any integer type. It is checked against `.length` exactly as an [array index](https://rux-lang.dev/docs/lang/arrays/overview#indexing) is, and one past the end stops the program with `Panic: index out of range`. `for` walks the elements in order: ```rux func Largest(values: int32[..]) -> int32 { var best = values[0]; for value in values { if value > best { best = value; } } return best; } ``` A `for` loop visits exactly `.length` elements of the view it was given. Spreading a slice with `...` passes its elements one by one to a [variadic parameter](https://rux-lang.dev/docs/lang/functions/parameters): with `func Sum(args: int32...)`, the call `Sum(values...)` gives `Sum` every element of `values`. ## Writability belongs to the view Whether elements may be written depends on the **view's type**, never on the binding that holds it: ```rux func Fill(values: var int32[..], value: int32) { for i in 0..values.length { values[i] = value; } } func Main() -> int { var storage: int32[4] = [1, 2, 3, 4]; let writable = storage[..]; // var int32[..]: the array place is writable writable[0] = 10; // a 'let' binding, but a writable view var cursor: int32[..] = storage; cursor = storage[2..]; // a 'var' binding may be pointed elsewhere Fill(storage[1..3], 0); // a writable view of part of the array return 0; } ``` The binding decides whether the variable can be pointed at another view; the view decides whether the elements can change. So a `var` binding of a read-only view still cannot write an element, and a `let` binding of a writable view cannot be repointed: ```text error: cannot modify elements through read-only slice 'int32[..]' help: use a 'var T[..]' view to write through the sequence error: cannot modify immutable variable 'view' help: declare 'view' with 'var' to make it mutable ``` Writability flows in one direction: - A `var T[..]` converts implicitly to a `T[..]` of the same elements, wherever a read-only view is expected. The reverse is rejected: `cannot assign 'int32[..]' to 'var int32[..]'`. - A view of an array is writable only when the array place is. With `let fixed: int32[3] = [1, 2, 3];`, `fixed[..]` is an `int32[..]`, and `Fill(fixed[..], 0)` fails with `argument 1 to 'Fill' has type 'int32[..]', but parameter 'values' requires 'var int32[..]'`. - A sub-slice keeps its parent's writability, and a view of a pointer takes the pointer's. - A string literal's bytes are read-only, always: ```text error: cannot assign string literal to 'var char8[..]' because literal text is stored in a read-only section ``` A writable parameter is given an explicit view, `storage[..]`; an array passed on its own only becomes a read-only one. A method that takes a `var T[..]` must be given a view, too. An array passed on its own is reported at the call, with the candidate it missed: ```text error: no matching overload for method 'Fill' on type 'Filler' with argument types (int32[3]) note: candidate 'Fill(values: var int32[..])' declared at … ``` Pass `buffer[..]`. ## A view does not keep its storage alive A slice only points at storage, and the storage must outlive every view of it. A view of a local array is valid until that array goes out of scope; a view of an allocation, until the allocation is freed. String literals live for the whole program, so a view of one may be returned freely. ```rux func Platform() -> char8[..] { return "Windows"; // static storage: fine to return } ``` Returning a view of a local array would leave the caller holding a view of storage that no longer exists, so the compiler refuses it. It follows the view through everything a function does with it: a slice of the array, the array itself where a slice is expected, a local given such a view, a structure, array or tuple built from one, and the result of a call handed one. Storing such a view through a pointer or a reference is refused the same way. A by-value array parameter is the function's own copy, so it counts as a local: ```rux func First() -> char8[..] { let letters: char8[3] = ['a', 'b', 'c']; return letters[..2]; // error } ``` ```text error: returned value views local array 'letters', which is freed when 'First' returns note: 'letters' is declared at 2:5 note: a slice is a view of storage it does not own, and that storage must outlive it help: return an owned container such as a 'Vector', or take the storage as a parameter ``` ## Comparison `==` and the other comparison operators are not defined on slices. Comparing two views would compare where they point rather than what they contain: ```text error: operator '==' is not defined for slice type 'int32[..]' note: a slice is a view, so comparing the views would compare addresses rather than elements help: declare '==' on 'int32[..]', or compare the elements one at a time ``` ## Methods on a slice type An [extension](https://rux-lang.dev/docs/lang/structs/extensions) may add methods to a slice of one concrete element type, `extend int[..]` or `extend char8[..]`; each element type has its own method set. A generic slice extension is rejected — a reusable algorithm over slices is an ordinary [generic](https://rux-lang.dev/docs/lang/generics/overview) function: ```text error: cannot extend slice type 'T[..]' because element type 'T' is not defined help: extend a slice of one concrete element type, for example 'extend int[..]' ``` ## Layout A slice is 16 bytes, aligned to 8, on every supported target: `.data` at offset 0 and `.length` at offset 8. Both `T[..]` and `var T[..]` have this layout; the elements are not part of it. See [Layout](https://rux-lang.dev/docs/lang/memory/layout). ## See also - [Arrays](https://rux-lang.dev/docs/lang/arrays/overview) — the storage a slice most often views - [Ranges](https://rux-lang.dev/docs/lang/ranges/overview) — the bounds a slice is cut with - [Pointer slicing](https://rux-lang.dev/docs/lang/pointers/slicing) — a view of raw memory, built from a pointer and a count - [Text](https://rux-lang.dev/docs/lang/types/text) — string literals as `char8[..]` - Learn: [Slice](https://rux-lang.dev/docs/learn/slice), [Writable slice](https://rux-lang.dev/docs/learn/writable-slice), [Variadic](https://rux-lang.dev/docs/learn/variadic) # Ranges A *range* is an interval of numbers written with `..`, `..=` or `...`. It is an ordinary value with a type of its own, and it has three everyday jobs: driving a [`for`](https://rux-lang.dev/docs/lang/statements/loops) loop, cutting a [slice](https://rux-lang.dev/docs/lang/slices/overview) out of a sequence, and matching an interval in a [pattern](https://rux-lang.dev/docs/lang/patterns/patterns). ```rux for i in 0..5 { PrintLine("{}", i); // 0, 1, 2, 3, 4 } ``` ## The six forms The start, when there is one, is always included. The end is excluded by `..` and included by `..=`. Either bound may be left out: | Expression | Type | Contains | Members | | ---------- | ----------- | ------------------------------ | ---------------- | | `1..4` | `int..int` | 1, 2, 3 | `.start`, `.end` | | `1..=4` | `int..=int` | 1, 2, 3, 4 | `.start`, `.end` | | `1..` | `int..` | 1 and every value after it | `.start` | | `..4` | `..int` | every value before 4 | `.end` | | `..=4` | `..=int` | every value up to 4, inclusive | `.end` | | `..` | `..` | everything | none | ```text range-expression = expression ( ".." | "..=" | "..." ) expression | expression ".." | ( ".." | "..=" | "..." ) expression | ".." range-type = type ( ".." | "..=" ) type | type ".." | ( ".." | "..=" ) type | ".." ``` In expressions and patterns `...` is a second spelling of the inclusive `..=`: `1...4` is `1..=4`, and `...4` is `..=4`. Types use `..=` only. (After an argument, `values...` before `)` or `,` is a spread, not a range — see [Slices](https://rux-lang.dev/docs/lang/slices/overview#indexing-and-iteration).) A range type is written with the same punctuation as its values, so a range can be stored, passed and returned like any other value: ```rux func Width(span: int..=int) -> int { return span.end - span.start + 1; } func Main() -> int { let bounded: int..int = 2..4; let closed = 1...3; // int..=int let from: int.. = 5..; let upTo: ..=int = ..=4; let everything: .. = ..; return Width(closed) - 3; } ``` ## Bounds The bounds of a range are numbers — integers or floating-point values — and both bounds of a two-sided range have one type. An unsuffixed literal takes the type of the other bound, so with `n: uint`, `0..n` is a `uint..uint` and a loop over it counts in `uint`. A bound of any other type is an error: ```text error: range bounds must be numeric ``` Bounds of two different numeric types meet in a common type, the one a binary operator on them would use: with `a: int32` and `b: int64`, `a..b` is an `int64..int64`, and with `c: uint8`, `a..c` is an `int32..int32`. When neither type holds every value of the other, the range is refused; convert one bound with `as` to the type the range should use: ```text error: range bounds 'int32' and 'uint32' have no common type ``` A range counts upwards. When both bounds are literals the compiler checks their order: ```text error: range start cannot be greater than its end ``` With bounds computed while the program runs nothing is checked, and a range whose start is past its end is empty: a `for` over it runs zero times. ### Precedence The range operators bind more loosely than every other operator except assignment — more loosely even than `?:` and `??`. So `n + 1..n * 3` is `(n + 1)..(n * 3)` and `flag ? 1 : 2..5` is `(flag ? 1 : 2)..5`, while a range inside a comparison needs parentheses: `r == 0..5` parses as `(r == 0)..5`. Ranges do not chain — `1..2..3` is a syntax error. See [Expressions](https://rux-lang.dev/docs/lang/expressions/overview). ## Members A range that has a start exposes it as `.start`, and one that has an end exposes it as `.end`; both have the bound type. Asking a range for a bound it does not have is an error: ```text error: range type '..int' has no member 'start' note: range members are 'start' and 'end' when that bound is present ``` The members need no import. A range held in a `var` binding can have its bounds assigned, as fields can. ## In a `for` loop `for` walks a range from its start upwards in steps of one, binding each value to the loop variable, whose type is the bound type: ```rux for i in 1..=5 { PrintLine("{}", i); // 1, 2, 3, 4, 5 } ``` - `a..b` visits `a` up to `b - 1`, and `a..=b` visits `a` up to `b`. An inclusive range ending at its type's maximum visits that value last and stops, so `for v in start..=255` over `uint8` never wraps around. - `a..` has no end, so the loop runs until it leaves with [`break`](https://rux-lang.dev/docs/lang/statements/break-continue) or `return`. - A range with no start has no first value and cannot be walked: ```text error: range type '..int' has no initial value and is not iterable ``` The loop variable is immutable; a loop that must control its own stepping is a [`while`](https://rux-lang.dev/docs/lang/statements/loops). ## In slicing Indexing an array, a slice or a pointer with a range produces a [slice](https://rux-lang.dev/docs/lang/slices/overview#slicing). Every form is allowed on an array or a slice: an omitted start means 0 and an omitted end means `.length`. A pointer has no length, so slicing one requires an end — `p[..n]`, `p[a..b]` or `p[..=n]`; see [Pointer slicing](https://rux-lang.dev/docs/lang/pointers/slicing). ```rux let values: int[6] = [10, 20, 30, 40, 50, 60]; let middle = values[2..4]; // 30, 40 let head = values[...2]; // 10, 20, 30 let span: int..=int = 1..=3; let held = values[span]; // 20, 30, 40 ``` ## In patterns A range pattern matches every value from its low bound to its high bound. Both bounds are required, and both must be literals of the subject's type; the subject is a number or a character: ```rux func Grade(score: int) -> char8[..] { return match score { 0..50 => "fail", 50...69 => "pass", 70..=89 => "merit", 90..=100 => "distinction", else => "invalid" }; } ``` A pattern with one bound missing, such as `90.. =>`, is a syntax error. A character range such as `'a'..='z'` takes bounds of the subject's width, so a `char8` subject is matched with `c8'a'..=c8'z'`. See [Patterns](https://rux-lang.dev/docs/lang/patterns/patterns). A type can also accept a range in its own [indexer](https://rux-lang.dev/docs/lang/interfaces/indexers), such as `func [](self: &Vect, span: int..int) -> int[..]`. ## See also - [Loops](https://rux-lang.dev/docs/lang/statements/loops) — `for` over a range - [Slices](https://rux-lang.dev/docs/lang/slices/overview) — the views a range cuts - [Patterns](https://rux-lang.dev/docs/lang/patterns/patterns) — range patterns in `match` - Learn: [Range](https://rux-lang.dev/docs/learn/range), [For](https://rux-lang.dev/docs/learn/for), [Range pattern](https://rux-lang.dev/docs/learn/range-pattern) # References A *reference* lets code use a value that belongs to someone else, without copying it and without taking it over. `&T` is a **shared** reference: it can read the value. `&var T` is an **exclusive** reference: it can read and write it. A reference never owns its referent, is never null, and lives no longer than the call or the block that made it. ```text reference-type = "&" type | "&" "var" type ``` ```rux struct Account { owner: char8[..]; balance: int; } func Report(account: &Account) { PrintLine("{}: {}", account.owner, account.balance); } func Deposit(account: &var Account, amount: int) { account.balance += amount; } func Main() -> int { var alice = Account { owner: "alice", balance: 10 }; Deposit(alice, 5); // borrowed for writing: alice.balance is now 15 Report(alice); // borrowed for reading return 0; } ``` References are the safe way to share. A [raw pointer](https://rux-lang.dev/docs/lang/pointers/overview) is an address the program vouches for itself; a reference is one the compiler checks, under the rules on [Exclusivity](https://rux-lang.dev/docs/lang/references/exclusivity). ## Borrowing is implicit There is no borrow operator. A reference is made — the value is *borrowed* — when a place is given where a reference is expected: - **an argument** for a parameter of type `&T` or `&var T`; - **a receiver**: calling a method declared with `self: &T` or `self: &var T` borrows the value it is called on; - **a binding** annotated with a reference type: `let shared: &Account = alice;`. The call site looks the same as passing by value; the parameter's type decides. `&` is never an operator, and writing it before a value is an error that points to `@`, which takes a raw address: ```text error: '&' does not take an address; write '@' to take the address of a value ``` What is borrowed must be a place — a variable, a field, an element, or the referent of another reference. A literal or a freshly built value has nowhere to be borrowed from, so `Report(Account { owner: "x", balance: 1 })` and `Bump(5)` — `Bump` is defined [below](https://rux-lang.dev/#writing-through-var) — are rejected: ```text error: argument 1 to 'Report' has type 'Account', but parameter 'account' requires '&Account' error: argument 1 to 'Bump' has type 'int', but parameter 'count' requires '&var int' ``` An exclusive borrow also needs a place that may be written. With `let savings = Account { … };`, `Deposit(savings, 10)` is rejected: ```text error: argument 1 to 'Deposit' cannot borrow immutable 'savings' as '&var Account' help: declare 'savings' with 'var' to make it mutable ``` A `&var T` is accepted wherever a `&T` is expected: an exclusive reference can always lend reading. ## Using a reference A reference is used as if it were the value. Fields, methods, indexing and `.length` all reach through it with no `*` and no arrow: ```rux func First(values: &int[3]) -> int { return values[0] + values.length as int; } ``` A reference to a scalar — an integer, a float, a `bool`, a character — supplies the scalar's value wherever a value is expected: in arithmetic and comparisons, in a condition, in a cast, in an assignment or a typed binding, as a by-value argument: ```rux func Twice(value: &int) -> int { return value * 2; } ``` To copy a scalar out of a reference, give the binding its type: `let saved: int = value;`. `*` is a raw-pointer operator and never applies to a reference: ```text error: operator '*' requires a pointer operand, but found '&var int' note: a reference reads and writes its referent without '*' help: write 'r' in place of '*r', as in 'r += 1' ``` ## Writing through `&var` Through a `&var T` the referent can be written in three ways. **Fields and elements** are written as usual: `account.balance += 5`, `values[i] = 0`. **A scalar referent** is written by assigning to the reference itself. `=`, `<-`, the compound assignments and `++`/`--` all store into the caller's value: ```rux func Bump(count: &var int) { count += 1; } func Main() -> int { var total = 4; Bump(total); // total is now 5 let alias: &var int = total; alias = 20; alias++; // total is now 21 return 0; } ``` **Any other referent** — a struct, a tuple, an array, a value of a type parameter — is replaced whole with `=` or `<-`. This is how a method replaces the value it was called on: ```rux extend Account { func Reset(self: &var Account) { self = Account { owner: self.owner, balance: 0 }; } } ``` The write follows the [assignment rules](https://rux-lang.dev/docs/lang/ownership/copy-and-move) for `T` exactly as an assignment to a `var` local would: the new value is produced first, the old one is destroyed, and the new one is installed; a move-only value needs `<-`. Compound assignment and `++`/`--` apply to scalar referents only. Through a shared reference every write is an error: ```text error: cannot modify data through immutable reference '&Account' ``` ### Rebinding a reference A reference binding declared with `let` always writes through. One declared with `var` is different for plain `=`, which points it at other storage instead: ```rux var first = 1; var second = 2; var current: &int = first; current = second; // current now refers to second; first is unchanged ``` Assigning a value of the referent's type to such a binding is therefore an error. With `var counter: &var int = total;`, `counter = 5;` fails: ```text error: cannot assign 'int' to '&var int' note: '=' points the 'var' reference 'counter' at other storage help: declare 'counter' with 'let' to write through it ``` ## Where a reference may appear A reference is a non-owning alias for the length of a call or a block, so it may appear in exactly three places: a **parameter**, a **receiver**, and a **local binding**. It cannot be stored in a field, returned, or moved out of — a field `r: &int` in a `struct Holder`, a function returning `&Account`, and `let mine <- account;` on a reference parameter are rejected in turn: ```text error: field 'r' in struct 'Holder' cannot store reference type '&int' note: references are non-owning aliases and cannot escape into aggregate storage help: store the owned value or a raw pointer when an address must outlive the borrow error: function return type cannot store reference type '&Account' error: cannot move a non-owning reference note: references borrow storage but do not own the value they address ``` A reference is no [type argument](https://rux-lang.dev/docs/lang/generics/overview) either, written or deduced. A generic body is checked once for whatever its parameter stands for, so nothing there proves it does not store the value — `Thread::Spawn` keeps its context for the new thread — and `Hold<&Counter>(counter)` is refused, as is `Spawn(ByRef, counter)` with `func ByRef(counter: &Counter)`: ```text error: type argument '&Counter' of function 'Hold' cannot be or hold a reference note: type parameter 'T' may be stored by the generic code, and a reference cannot outlive the call that borrowed it help: pass an owned value, or a raw pointer when the address must be shared ``` A reference cannot destroy its referent either: replacing a value through `&var T` installs a new one in its place. When an address must be stored or must outlive the call, use a [raw pointer](https://rux-lang.dev/docs/lang/pointers/overview). ## References and pointers | | `&T`, `&var T` | `*T`, `*var T` | | --------------------------- | --------------------------------------------------------------------------------- | ---------------------------------------- | | Made by | an implicit borrow | `@place` | | Null | never | `null` is a value | | Read and write | as the value itself | `*p`; `p.field` and `p[i]` reach through | | Arithmetic | none | `p + n`, `p - n`, `p[i]` | | Stored in a field, returned | no | yes | | Checked | [exclusivity](https://rux-lang.dev/docs/lang/references/exclusivity), writability | writability only | A reference is 8 bytes, the size of the address it holds. ## See also - [Exclusivity](https://rux-lang.dev/docs/lang/references/exclusivity) — how many references may exist at once - [Parameters](https://rux-lang.dev/docs/lang/functions/parameters) — `&T` and `&var T` parameters - [Methods](https://rux-lang.dev/docs/lang/structs/methods) — receivers declared as `self: &T` and `self: &var T` - [Pointers](https://rux-lang.dev/docs/lang/pointers/overview) — raw addresses, for what a reference cannot do - Learn: [Reference](https://rux-lang.dev/docs/learn/reference), [Mutable reference](https://rux-lang.dev/docs/learn/mutable-reference), [Mutating method](https://rux-lang.dev/docs/learn/mutating-method) # Exclusivity At any moment a value may be borrowed by **any number of shared references**, `&T`, or by **one exclusive reference**, `&var T` — never both. While a `&var` borrow is in use, the value is reached only through it; while `&` borrows are in use, nothing changes the value under them. The compiler checks this for every [reference](https://rux-lang.dev/docs/lang/references/overview), so a reader never sees a value change mid-read and two writers never overlap. | While the value is borrowed by | Reading the value directly | Writing it directly | Another `&` borrow | Another `&var` borrow | | ------------------------------ | -------------------------- | ------------------- | ------------------ | --------------------- | | one or more `&T` | allowed | error | allowed | error | | one `&var T` | error | error | error | error | The rule covers everything that borrows: an argument passed to a reference parameter, a method call through a `self: &T` or `self: &var T` receiver, and a local binding of reference type. ## A borrow lasts until its last use A borrow made for a call lasts for that call. A borrow bound to a local lasts from the binding to the **last use** of that local — not to the end of the block. Once the reference is used for the last time the value is free again: ```rux struct Account { balance: int; } func Main() -> int { var alice = Account { balance: 10 }; let wallet: &var Account = alice; wallet.balance += 5; // last use of wallet: the borrow ends here alice.balance -= 1; // fine: alice is no longer borrowed return 0; } ``` ```mermaid flowchart LR b["`let wallet: &var Account = alice`"] --> u["`wallet.balance += 5`<br/>(last use)"] u --> f["`alice` is free again"] b -. "`alice` reachable only through `wallet`" .-> u ``` Moving the direct access before the borrow's last use is what makes the program wrong: ```rux let wallet: &var Account = alice; let before = alice.balance; // error: wallet is still to be used wallet.balance += 5; ``` ```text error: cannot read 'alice.balance' while 'wallet' holds an exclusive borrow help: read through 'wallet' or wait until its last use ``` Read through the reference instead, or move the read after the reference's last use. ## What overlaps Two accesses conflict only when they reach the same storage. The compiler compares the places as written: - A whole value overlaps each of its fields and elements, and they overlap it. - **Different fields** of one struct do not overlap, so one can be borrowed exclusively while another is read or borrowed. - Elements overlap when their indexes are the same constant or the same expression: `v[0]` and `v[0]`, `v[i]` and `v[i]`. ```rux struct Pair { x: int; y: int; } func Swap(a: &var int, b: &var int) { let saved: int = a; a = b; b = saved; } func Main() -> int { var pair = Pair { x: 1, y: 2 }; Swap(pair.x, pair.y); // two fields: no overlap var values = [1, 2, 3]; Swap(values[0], values[2]); // two different elements return 0; } ``` ## The errors Each conflict has its own message. All of them carry a note giving the line and column where the conflicting borrow began, and a help line naming the reference to use instead. **Reading a value while a `&var` borrow of it is in use.** ```text error: cannot read 'alice.balance' while 'wallet' holds an exclusive borrow help: read through 'wallet' or wait until its last use ``` **Writing a value while a borrow of it is in use.** A shared borrow forbids writes because a reader expects the value to hold still; an exclusive one forbids every direct access: ```text error: cannot modify 'alice.balance' while it is immutably borrowed error: cannot modify 'alice' while it is exclusively borrowed ``` **Borrowing for writing while a reader is in use**, including through a method with a `self: &var T` receiver: ```text error: cannot borrow exclusively 'alice' while it is immutably borrowed help: use 'view' for the access or wait until its last use ``` **Borrowing at all while a writer is in use**, including by calling a method with a `self: &T` receiver. Such a call is reported both as a read and as a borrow: ```text error: cannot read 'alice' while 'wallet' holds an exclusive borrow help: read through 'wallet' or wait until its last use error: cannot borrow 'alice' while it is exclusively borrowed help: use 'wallet' for the access or wait until its last use ``` **One value in two arguments** of the same call, when at least one of them is `&var`. Two `&T` arguments may share a value; an exclusive one must have it to itself: ```text error: call arguments create overlapping exclusive borrows of 'alice' help: split the accesses into non-overlapping calls ``` The same message names a field or an element when that is what is passed twice: `Swap(pair.x, pair.x)` reports `'pair.x'`, and `Swap(values[0], values[0])` reports `'values[0]'`. ## Outside the rule [Raw pointers](https://rux-lang.dev/docs/lang/pointers/overview) are not borrows. Taking an address with `@`, holding several `*var T` to one value, and writing through them are all accepted; keeping such accesses apart is the program's responsibility. A [slice](https://rux-lang.dev/docs/lang/slices/overview) is a view built on a pointer and is not tracked as a borrow either. ## See also - [References](https://rux-lang.dev/docs/lang/references/overview) — `&T` and `&var T` - [Ownership](https://rux-lang.dev/docs/lang/ownership/overview) — who owns a value, and when it is destroyed - [Methods](https://rux-lang.dev/docs/lang/structs/methods) — receivers that borrow the value they are called on - Learn: [Exclusivity](https://rux-lang.dev/docs/learn/exclusivity), [Reference](https://rux-lang.dev/docs/learn/reference), [Mutable reference](https://rux-lang.dev/docs/learn/mutable-reference) # Pointers A *raw pointer* holds the address of a value. `*T` is a **read-only** pointer: the value it points at can be read through it. `*var T` is a **writable** pointer: the value can also be written. A pointer may be `null`, may be stored in a field, returned, offset and compared, and may outlive what it points at — the compiler checks only what the pointer type allows, never whether the address is still good. That is the price of the things only a pointer can do: [foreign functions](https://rux-lang.dev/docs/lang/ffi/overview), manual allocation, stored links between values, and walking memory by address. ```text pointer-type = "*" type | "*" "var" type address-of = "@" place dereference = "*" expression ``` ```rux var score = 10; let writer = @score; // *var int: score is a var *writer += 5; // score is now 15 let reader: *int = @score; // a read-only view of the same int let current = *reader; // 15 ``` For safe, checked access to a value someone else owns, use a [reference](https://rux-lang.dev/docs/lang/references/overview) instead; a pointer is the deliberate step outside those checks. ## Taking an address The prefix `@` takes the address of a place: a variable, a field, an element, or the target of another pointer. `@x.field` and `@a[i]` address one part of a value. The pointer's writability comes from the place: | Place | `@place` has type | | --------------------------------------------- | ----------------- | | a `var` binding, or a part of one | `*var T` | | a `let` binding, or a part of one | `*T` | | an element of a `var T[..]` view | `*var T` | | an element of a `T[..]` view | `*T` | | a field or element reached through a `*var T` | `*var T` | ```text error: cannot assign '*int' to '*var int': '@limit' yields a read-only '*T'; declare 'limit' with 'var' for a '*var T' ``` `&` never takes an address in Rux: `&x` is rejected with `'&' does not take an address; write '@' to take the address of a value`. A pointer is made only from an address, so a plain value where a pointer is expected is the error `cannot assign 'int' to '*int'`. Taking the writable address of a variable declared without a value counts as initialising it, because the address exists to be filled through: `var info: SystemInfo; GetSystemInfo(@info);` leaves `info` usable. See [Initialisation](https://rux-lang.dev/docs/lang/bindings/initialization). ## Reading and writing through a pointer The prefix `*` *dereferences* a pointer: `*p` is the value it points at, a place that can be read, and written when `p` is a `*var T`: ```rux func Store(target: *var int, value: int) { *target = value; } ``` ```text error: cannot modify data through read-only pointer '*int' ``` The pointee type, not the variable it points at, decides what is allowed: a `*int` cannot write even when it points at a `var`. A write through a pointer **initialises** the storage it addresses and destroys nothing. The pointer cannot tell whether that storage holds a value yet, so `*p = value`, `*p <- value`, `p[i] = value` and a field write through a `*var T` never run a destructor for what was there before. Code that replaces a value through a pointer destroys or moves out the old one first: ```rux struct Noisy { id: int; } extend Noisy { func ~Noisy(self: &var Noisy) { PrintLine("destroy {}", self.id); } } func Main() -> int { var slot = Noisy { id: 1 }; slot = Noisy { id: 2 }; // assignment: destroys 1 let p = @slot; *p = Noisy { id: 3 }; // through a pointer: 2 is never destroyed return 0; // destroys 3 } ``` ```text destroy 1 destroy 3 ``` Moving a value out through a pointer is rejected, because the pointer does not own it: `let mine <- *p;` fails with `cannot move '*p' out of borrowed pointer storage`. ## Fields, elements and methods `.` reaches through a pointer to a struct, and `[i]` through a pointer to an element; there is no arrow operator. Reads and writes go straight to the pointed-at value: ```rux struct Point { x: int; y: int; } func Main() -> int { var point = Point { x: 1, y: 2 }; let p = @point; p.x = 7; // point.x is now 7 let sum = p.x + p.y; return 0; } ``` A method is not called through a raw pointer, because its receiver is a reference and a pointer proves nothing about the address it holds. Dereference first, `(*p).Shift(3)`, to vouch for it explicitly: ```text error: cannot create safe receiver '&var Point' from raw pointer '*var Point' note: raw pointers do not prove a valid non-null borrow help: call the method on an owning value ``` Pointers nest: `**T` is a pointer to a pointer, and each `*` removes one level, so with `pp: **var int`, `**pp = 1` writes the `int`. ## Conversions | From | To | How | | --------- | --------- | ---------------------------------------------- | | `*var T` | `*T` | implicitly | | `*T` | `*opaque` | implicitly; `*var T` likewise to `*var opaque` | | `*opaque` | `*T` | `as *T`; likewise `as *var T` | | `*T` | `*U` | `as *U` | | `*T` | `*var U` | never, for any `U` but `opaque` | | a pointer | `uint` | `as uint` — the address as a number | | `uint` | a pointer | `as *T` | Losing write access is always allowed; gaining it is not: `cannot assign '*int' to '*var int'`. A cast with `as` is the explicit, unchecked way to retype an address — see [Casts](https://rux-lang.dev/docs/lang/expressions/casts) — but it cannot add write access either, whatever pointee it names, so `@x as *var int` and `@x as *var uint64` on a `let x` are refused. Untyped memory is the one way through: writable memory reached through an `*opaque`, such as a fresh allocation, is retyped with `as *var T`, and a `*T` may become a `*var opaque` for a C function that takes a `void *` it only reads: ```text error: cannot cast '*int' to '*var uint64', which would give a read-only pointer write access ``` ## `null` `null` is the pointer that points at nothing. It converts to every pointer type, and it is the only value a pointer has that is not an address. Compare with `==` and `!=` before dereferencing a pointer that might be `null`: ```rux struct Node { value: int; next: *Node; } func Main() -> int { var tail = Node { value: 3, next: null }; var head = Node { value: 1, next: @tail }; var cursor: *Node = @head; while cursor != null { PrintLine("{}", cursor.value); cursor = cursor.next; } return 0; } ``` Reading or writing through `null` is not checked: it compiles, and crashes the program when it runs. `null` is a pointer value, not absence. It is not a value of an [optional](https://rux-lang.dev/docs/lang/optionals/overview) type, and where an optional of a pointer is expected it is a **present** null pointer: | Type | Meaning | | ------- | ----------------------------------------- | | `(*T)?` | an optional pointer: `none`, or a pointer | | `*T?` | a pointer to an optional, `*(T?)` | ```rux let present: (*int)? = null; // present, holding a null pointer let absent: (*int)? = none; // absent ``` ## `*opaque` `*opaque` and `*var opaque` point at bytes of no particular type, as C's `void *` does. Allocation functions return them, and foreign functions take and return them. Any typed pointer converts to one implicitly; to use the memory, cast it back to a typed pointer: ```rux import Memory::{ Alloc, Free }; func Main() -> int { let block = Alloc(4 * sizeof(int)) as *var int; if block == null { return 1; } defer Free(block); block[0] = 1; return 0; } ``` Arithmetic on an `*opaque` moves by single bytes. ## Comparison Two pointers compare with `==` and `!=`, which compare addresses, and with `<`, `<=`, `>` and `>=`, which order them — useful when walking a buffer up to an end pointer. See [Pointer arithmetic](https://rux-lang.dev/docs/lang/pointers/arithmetic). ## What a pointer does not have A pointer has no length: `p.length` is `type '*var int' has no field 'length'`. It cannot be iterated with `for`, and slicing it needs an explicit end. To treat raw memory as a sequence, build a [view](https://rux-lang.dev/docs/lang/pointers/slicing) of it with a count, `p[..n]`, and iterate that, `for value in p[..n]`: ```text error: cannot iterate over pointer '*int32' help: iterate a slice of the memory it points at, as in 'for value in p[..count]' ``` A pointer is 8 bytes on every supported target, whatever it points at. ## See also - [Pointer arithmetic](https://rux-lang.dev/docs/lang/pointers/arithmetic) — moving a pointer by whole elements - [Pointer slicing](https://rux-lang.dev/docs/lang/pointers/slicing) — a bounded view of the memory a pointer addresses - [References](https://rux-lang.dev/docs/lang/references/overview) — checked, non-null access to a value - [Foreign functions](https://rux-lang.dev/docs/lang/ffi/overview) — how pointers cross into C - [Layout](https://rux-lang.dev/docs/lang/memory/layout) — the size and alignment of what a pointer addresses - Learn: [Pointer](https://rux-lang.dev/docs/learn/pointer), [Out parameter](https://rux-lang.dev/docs/learn/out-parameter), [Raw memory](https://rux-lang.dev/docs/learn/raw-memory), [Optional pointer](https://rux-lang.dev/docs/learn/optional-pointer) # Pointer arithmetic Adding an integer to a pointer moves it by whole **elements**, not bytes. If `p` is a `*T`, then `p + 1` is the address of the next `T` — `sizeof(T)` bytes further on — whatever `T` is. This is how a program walks memory that has no length attached: an allocation, a buffer from a foreign function, the elements behind a view's `.data`. | Expression | Type | Meaning | | ---------- | -------------------- | ------------------------------------------------ | | `p + n` | the type of `p` | `n` elements after `p` | | `n + p` | the type of `p` | the same as `p + n` | | `p - n` | the type of `p` | `n` elements before `p` | | `p += n` | | moves the `var` pointer `p` forward `n` elements | | `p -= n` | | moves it back `n` elements | | `p[i]` | the pointee, a place | the element `i` elements after `p`: `*(p + i)` | `n` may have any integer type. The result keeps the pointer's writability: an offset `*var T` is still a `*var T`. ```rux var values: int64[4] = [10, 20, 30, 40]; let first = @values[0]; let third = first + 2; // 16 bytes on: sizeof(int64) is 8 let a = *third; // 30 let b = *(third - 1); // 20 let c = first[3]; // 40 let d = third[-1]; // 20: an index may be negative first[1] = 25; // values[1] is now 25 ``` Indexing and arithmetic agree — `@p[i]` is the same address as `p + i` — and both scale by the pointee's size, including a struct's size with its padding. See [Layout](https://rux-lang.dev/docs/lang/memory/layout). `*` binds more tightly than `+`, so the parentheses in `*(p + 2)` matter: `*p + 2` reads the first element and adds 2 to it. `p[2]` says the same as `*(p + 2)` with no parentheses. ## Nothing is checked A pointer carries no length, so neither arithmetic nor `p[i]` is bounds-checked. An offset past the end of the memory a pointer addresses produces an address that is not one, and reading or writing through it is undefined: the program may crash, or may silently read or overwrite something else. The caller vouches for every offset. When the count is known, build a [view](https://rux-lang.dev/docs/lang/pointers/slicing), `p[..n]`, whose indexing **is** checked. ## Walking a buffer Pointers order with `<`, `<=`, `>` and `>=`, so a loop can walk from a start pointer to an end pointer one past the last element. `+=` steps the cursor; there is no `++` or `--` on a pointer: ```rux func Main() -> int { var values: int64[4] = [10, 20, 30, 40]; let start = @values[0]; let end = start + values.length; // one past the last element: never read var cursor = start; var sum: int64 = 0; while cursor < end { sum += *cursor; cursor += 1; } PrintLine("{}", sum); // 100 return 0; } ``` Compare with `<`, not `<=`: the end pointer marks where to stop, and reading it reads past the array. ## Pointer subtraction Subtracting one pointer from another is not defined: ```text error: operator '-' cannot combine left operand '*var int64' with right operand '*var int64' ``` To count the elements between two pointers into the same block, convert both to addresses and divide the distance in bytes by the element size: ```rux let count = ((end as uint) - (start as uint)) / sizeof(int64); // 4 ``` ## `*opaque` A `*opaque` has no element type, so arithmetic on it moves by single bytes: `block + 8` is eight bytes on. To step by elements, cast it to a typed pointer first. Indexing an `*opaque` yields no usable value; cast it before reading or writing. ## See also - [Pointers](https://rux-lang.dev/docs/lang/pointers/overview) — `*T`, `*var T`, `@` and `null` - [Pointer slicing](https://rux-lang.dev/docs/lang/pointers/slicing) — a checked view built from a pointer and a count - [Layout](https://rux-lang.dev/docs/lang/memory/layout) — the element sizes that arithmetic scales by - Learn: [Pointer arithmetic](https://rux-lang.dev/docs/learn/pointer-arithmetic), [Raw memory](https://rux-lang.dev/docs/learn/raw-memory) # Pointer slicing Indexing a pointer with a range turns raw memory into a [slice](https://rux-lang.dev/docs/lang/slices/overview): a view with a length, whose indexing and iteration are checked from then on. Because a pointer has no length of its own, the range must say where the view ends. | Expression | Elements, counting from `p` | Length | | ---------- | ----------------------------- | ----------- | | `p[..n]` | 0 up to, not including, `n` | `n` | | `p[..=n]` | 0 to `n` inclusive | `n + 1` | | `p[a..b]` | `a` up to, not including, `b` | `b - a` | | `p[a..=b]` | `a` to `b` inclusive | `b - a + 1` | The view's type follows the pointer's writability: a `*var T` gives a `var T[..]`, and a `*T` gives a `T[..]`. A view of a `null` pointer with a length of zero is an empty view. ```rux import Memory::{ Alloc, Free }; func Fill(values: var int[..], start: int) { for i in 0..values.length { values[i] = start + i as int; } } func Total(values: int[..]) -> int { var sum = 0; for value in values { sum += value; } return sum; } func Main() -> int { let count: uint = 4; let block = Alloc(count * sizeof(int)) as *var int; if block == null { return 1; } defer Free(block); let all = block[..count]; // var int[..], four elements Fill(all, 10); // 10, 11, 12, 13 let total = Total(block[1..3]); // 11 + 12 return 0; } ``` ## The end is required A pointer does not know how far its memory extends, so a range with no end — `p[..]` or `p[a..]` — is rejected: ```text error: cannot slice pointer '*var int' without an end bound help: write 'p[..n]' or 'p[a..b]' to give the slice a length ``` Once built, the view checks every index against the length it was given. That length is the program's promise, and nothing checks it against the memory: `block[..100]` over a four-element block compiles, and its indexes are then checked against 100, not 4. Build every view from the count the memory was allocated with. ## Precedence `@` is a prefix operator and indexing is postfix, so postfix binds first: `@a[0][..2]` means `@(a[0][..2])` — a slice of the element `a[0]`, which is not a sequence: ```text error: cannot slice value of type 'int' help: declare 'func []' taking a range on 'int' ``` Parenthesise the address to slice the memory it points at: ```rux var numbers: int[6] = [1, 2, 3, 4, 5, 6]; let window = (@numbers[2])[..3]; // var int[..]: 3, 4, 5 ``` A view of an array is more simply `numbers[2..5]`; slicing a pointer is for memory that arrives as an address, such as an allocation, a buffer from a [foreign function](https://rux-lang.dev/docs/lang/ffi/overview), or a [flexible tail](https://rux-lang.dev/docs/lang/arrays/overview#flexible-tails). ## Views of literal text The `.data` of a string literal is a `*char8`, and slicing it gives back a read-only view, as any read-only pointer does: `"abc".data[..2]` is a `char8[..]` of `a` and `b`. ## See also - [Pointers](https://rux-lang.dev/docs/lang/pointers/overview) — `*T`, `*var T` and `@` - [Pointer arithmetic](https://rux-lang.dev/docs/lang/pointers/arithmetic) — unchecked offsets and indexing - [Slices](https://rux-lang.dev/docs/lang/slices/overview) — what a view can do once it has a length - Learn: [Pointer slice](https://rux-lang.dev/docs/learn/pointer-slice), [Fixed buffer](https://rux-lang.dev/docs/learn/fixed-buffer) # Optionals An *optional* `T?` holds either a present value of type `T` or nothing — *absence*, written `none`. It is a compiler-owned type: no package declares it, it has no methods, and the compiler makes sure absence is dealt with before the value inside is used. ```text optional-type = type "?" ``` ## The type `?` is a postfix type suffix. Like `[]`, `[N]` and `[..]`, it binds tighter than every other type operator, so it applies to the type immediately before it. Group with parentheses to put it anywhere else: | Type | Meaning | | ----------------- | ---------------------------------------------------------------------- | | `int32?` | an optional `int32` | | `int32??` | an optional of an optional `int32` — two levels | | `int32?[..]` | a slice of optional `int32` values | | `int32[..]?` | an optional slice | | `*int32?` | a pointer to an optional, `*(int32?)` | | `(*int32)?` | an optional pointer | | `(int32 | bool)?` | an optional [sum](https://rux-lang.dev/docs/lang/sums/overview) | | `int32 | (bool?)` | a sum with an optional member | | `(T ! E)?` | an optional [fallible](https://rux-lang.dev/docs/lang/errors/overview) | | `T ! (E?)` | a fallible whose error is optional | A `?` never reaches across `|` or `!`, so the last two pairs must be grouped. Without the parentheses the compiler stops: ```text error: an optional sum member must be grouped help: write 'A | (B?)' for an optional member, or '(A | B)?' for an optional sum error: an optional error type must be grouped help: write 'T ! (E?)' for an optional error, or '(T ! E)?' for an optional result ``` Any type can be the payload: a struct, a slice, a pointer, a fallible, the unit `()` (a `()?` is just "present or not"), and another optional. ## Levels never collapse `T??` is not `T?`. Each level has its own absence, so an `int32??` has three distinct values: | Value | Meaning | | --------------------------- | ----------------------------------- | | `none` | absent | | `.Some(none)` | present, holding an absent `int32?` | | `.Some(.Some(20))`, or `20` | present, holding a present `20` | This is what lets a lookup tell "there is no such key" from "the key is there, and its value is absent", and an iterator tell "there are no more items" from "the next item is an absent value". ## Writing an optional value There are three ways to produce an optional, and every nested state can be written directly, without a temporary: ```rux let count: int32? = 4; // a plain value where an optional is expected is present let same: int32? = .Some(4); // presence written out let missing: int32? = none; // absence let inferred = .Some(4i32); // .Some alone takes its payload's type: int32? let wrapped: int32?? = count; // present, holding count: .Some(.Some(4)) ``` - **A plain value.** Where an optional is expected — an annotated `let`, an assignment, an argument, a `return` in a function returning `T?` — a value of type `T` is made present. The same happens one level up: an `int32?` placed where an `int32??` is expected becomes `.Some` of it. - **`.Some(value)`** selects presence explicitly. It is required where a plain value would be ambiguous, and it is how a present absence, `.Some(none)`, is written. - **`none`** is the absence of the *outer* level of the optional the context expects, never of a level inside it. In a function returning `int32? ! E` (a fallible whose success is optional), `return none;` succeeds with an absent value. `none` carries no type of its own, so it needs a context: ```text error: cannot infer the type of 'absent' from 'none' help: annotate the optional type, as in 'let value: int32? = none;' ``` An optional payload can also widen: an `A?` converts to `(A | B)?`, keeping absence absent. The [sum](https://rux-lang.dev/docs/lang/sums/overview) rules apply to the payload. An annotation gives its type to every arm of a `match` expression, so `none` and a plain value can stand in different arms: in `let r: int32? = match n { 0 => none, else => n };` the first arm is absent and the second is present. ### `null` is not absence `null` is the null raw [pointer](https://rux-lang.dev/docs/lang/pointers/overview), and it is not a value of any optional type: ```text error: 'null' is not a value of type 'int32?' help: write 'none' for an absent optional ``` A raw pointer may be the payload of an optional, `(*T)?`, when a pointer that might not be there should be checked like any other optional. See [Optional pointer](https://rux-lang.dev/docs/learn/optional-pointer). ## Matching An optional is opened with an ordinary [`match`](https://rux-lang.dev/docs/lang/patterns/match). Its patterns select one level at a time: | Pattern | Matches | | ---------- | ---------------------------------------------------------------------- | | `v?` | a present value, binding its payload to `v` — shorthand for `.Some(v)` | | `.Some(p)` | a present value whose payload matches the pattern `p` | | `none` | absence of the level being matched | | `0?` | a present value equal to `0` — any pattern can carry the `?` suffix | | `v??` | two present levels, binding the inner payload — `.Some(.Some(v))` | | `none?` | a present absence — `.Some(none)` | | `v: T` | a present value whose payload has type `T`, binding it (one level) | ```rux func Find(values: int32[..], wanted: int32) -> uint? { for i in 0..values.length { if values[i] == wanted { return i; } } return none; } func Describe(found: uint?) -> char8[..] { return match found { 0? => "at the front", index? => "further in", none => "missing" }; } ``` Every level must be covered. A nested optional needs an arm for each of its states: ```rux func Lookup(key: int32) -> int32?? { if key == 0 { return none; } if key == 1 { return .Some(none); } return .Some(.Some(key * 10)); } func Classify(found: int32??) -> char8[..] { return match found { value?? => "a value", none? => "a present absence", none => "absent" }; } ``` A typed presence pattern takes exactly one level and leaves the rest to the arm: ```rux func Typed(found: int32??) -> int32 { return match found { stored: int32? => stored ?? -1, none => -2 }; } ``` A match that leaves a state out names it: ```text error: match on 'int32?' is not exhaustive; missing none error: match on 'int32?' is not exhaustive; missing .Some(_) error: match on 'int32??' is not exhaustive; missing .Some(none) ``` ## Using the value An optional is not its payload. It has no arithmetic, no fields, and no `Display`, so `known * 2` with `known: int32?` is `error: operator '*' cannot combine left operand 'int32?' with right operand 'int'`. The value inside is reached in one of four ways: | Tool | Use it when | | ----------------------------------------------------------- | ------------------------------------------------------------------ | | `match` | each state needs its own code | | [`??`](https://rux-lang.dev/docs/lang/optionals/coalescing) | absence has a stand-in value, or should leave the loop or function | | [`?`](https://rux-lang.dev/docs/lang/optionals/propagation) | absence should make the whole function's result absent | | [`is`](https://rux-lang.dev/docs/lang/sums/type-tests) | only presence matters: `reading is int32` is `true` when present | ## Equality `==` and `!=` compare optionals level by level: absent equals absent, and two present values are equal when their payloads are. Both operands must have the same optional type. `none`, `.Some(…)` and an unsuffixed literal take the other operand's type, but a value with a type of its own is never wrapped for a comparison: ```rux let known: int32? = 5; let a = known == 5; // true: the literal is made present let b = known == .Some(5); // true let c = known == none; // false ``` `known == 5i32` is rejected: ```text error: operator '==' cannot compare 'int32?' with 'int32' note: both operands of a native comparison have the same type; a comparison never injects, widens, or wraps an operand help: write '.Some(...)' or another constructor, bind the member with a typed pattern, or match the value ``` ## Iteration The iterator convention is built on optionals: an iterator's `Next` returns `Item?`, and a `for` loop ends at the first outer absence. Because levels never collapse, an iterator whose items are themselves optional returns `Item??`, and an absent item does not end the loop. See [Iteration](https://rux-lang.dev/docs/lang/interfaces/iteration). ## No methods An optional is a compiler-owned form with no declaring package, so it cannot be extended and implements no interface — an `int32?` is not `Display`, even though `int32` is: ```text error: cannot extend native type 'int32?' note: a sum, optional, fallible, or unit type has no declaring package to own methods or interface implementations help: write a generic function that takes the native type as a parameter ``` A reusable operation on optionals is a generic free function, such as `func OrZero<T>(value: T?, zero: T) -> T`. Inference reaches through `T?` as it does through any generic type. ## Layout An optional is stored as an 8-byte tag followed by its payload, aligned for the payload; a zero-sized payload takes no room. `sizeof(int32?)` and `sizeof(int64?)` are 16, `sizeof(int32??)` is 24 and `sizeof(()?)` is 8. The tag values are not a stable ABI. See [Layout](https://rux-lang.dev/docs/lang/memory/layout). ## See also - [Coalescing](https://rux-lang.dev/docs/lang/optionals/coalescing) — `??`, a fallback for absence - [Optional propagation](https://rux-lang.dev/docs/lang/optionals/propagation) — `?`, passing absence to the caller - [Sum types](https://rux-lang.dev/docs/lang/sums/overview) and [Errors](https://rux-lang.dev/docs/lang/errors/overview) — the other native outcome forms - [Patterns](https://rux-lang.dev/docs/lang/patterns/patterns) — the full pattern grammar - Learn: [Optional](https://rux-lang.dev/docs/learn/optional), [Presence](https://rux-lang.dev/docs/learn/presence), [Nested optional](https://rux-lang.dev/docs/learn/nested-optional) # Coalescing The *coalescing operator* `??` opens one level of an [optional](https://rux-lang.dev/docs/lang/optionals/overview). When the optional is present, the result is its payload; when it is absent, the result is the fallback. ```text coalesce-expr = expr "??" fallback fallback = expr | "return" [ expr ] | "break" [ label ] | "continue" [ label ] | "fail" expr ``` ## Semantics ```rux func Lookup(key: int32) -> int32? { return key % 2 == 0 ? .Some(key * 10) : none; } func Slow() -> int32 { PrintLine(" (computing the fallback)"); return -1; } ``` ```rux PrintLine("{}", Lookup(4) ?? Slow()); // 40 PrintLine("{}", Lookup(3) ?? Slow()); // (computing the fallback), then -1 ``` - The left operand is evaluated exactly once, and must be a native optional `T?`. - The result has the payload type `T` — not `T?`. - The fallback is checked at compile time but **evaluated only when the optional is absent**. A slow or visible fallback, such as `Slow()` above, costs nothing when a value is present. - The fallback must convert to `T`, or leave (below). `a ?? b` is shorthand for a match: | With `??` | Means | | ---------------- | ---------------------------------------- | | `Lookup(k) ?? 0` | `match Lookup(k) { v? => v, none => 0 }` | ### One level at a time `??` opens only the outer level. On an `int32??`, the result is an `int32?`, and a present absence is a present value, not absence: ```rux let nested: int32?? = .Some(none); let once = nested ?? .Some(1i32); // none: the outer level was present ``` To open both levels, coalesce twice with explicit grouping: `(nested ?? none) ?? 0`, or two `let`s. ## Chaining `??` is right-associative, so a chain tries each optional from the left, and the first present one wins: ```rux PrintLine("{}", Lookup(3) ?? Lookup(5) ?? Lookup(6) ?? 0); // 60 ``` This is `Lookup(3) ?? (Lookup(5) ?? (Lookup(6) ?? 0))`: every operand but the last is an optional, and each later one runs only if everything before it was absent. ## A fallback that leaves Instead of a value, the fallback may leave: `return`, `break`, `continue`, `fail error`, a call to [`Panic`](https://rux-lang.dev/docs/lang/errors/panics), or a call to any [`#NoReturn()`](https://rux-lang.dev/docs/lang/attributes/noreturn) function. A leaving fallback is the whole right operand, and it never decides the result type — the result is still the payload: ```rux // Skip an absent value and try the next key. func FirstEven(keys: int32[..]) -> int32 { for key in keys { let value = Lookup(key) ?? continue; return value; } return 0; } // Leave the function early. func OrZero(key: int32) -> int32 { let value = Lookup(key) ?? return 0; return value + 1; } // Turn absence into a failure. func Required(key: int32) -> int32 ! NotFound { return Lookup(key) ?? fail NotFound { key: key }; } // Absence here is a bug. func Trusted(key: int32) -> int32 { return Lookup(key) ?? Panic("the key is always even"); } ``` | Fallback | On absence | Requires | | --------------- | ------------------------------------- | --------------------------------------------------------------------- | | `?? value` | the expression's result is `value` | `value` converts to the payload type | | `?? return e` | the function returns `e` | `e` fits the function's return type | | `?? break` | the innermost (or labelled) loop ends | an enclosing loop | | `?? continue` | the next iteration starts | an enclosing loop | | `?? fail e` | the function fails with `e` | a [fallible](https://rux-lang.dev/docs/lang/errors/overview) function | | `?? Panic(msg)` | the program stops | — | Each leaving form follows its own rules, so `?? continue` outside a loop is `error: 'continue' can only be used inside 'while', 'for', or 'loop'`, and `?? fail` in a function that cannot fail is `error: 'fail' needs an enclosing fallible function, but this function returns 'int'`. `?? return none` needs a function that returns an optional. `?? fail` is the standard way to turn absence into an error; see [Error propagation](https://rux-lang.dev/docs/lang/errors/propagation). ## Precedence `??` sits between the conditional operator and `||` in the [precedence table](https://rux-lang.dev/docs/lang/expressions/overview): | Tighter than `??` | Looser than `??` | | -------------------------------------------------------------- | ------------------------------- | | `||`, `&&`, comparison, arithmetic, `as`, `is`, unary, postfix | `c ? a : b`, assignment, ranges | So every comparison and arithmetic operator next to a `??` belongs to the fallback: ```rux let mild = (Lookup(3) ?? 0) == 0; ``` Without the parentheses, `Lookup(3) ?? 0 == 0` means `Lookup(3) ?? (0 == 0)`, a `bool` fallback for an `int32` payload: ```text error: coalescing fallback has type 'bool8', but the optional payload is 'int32' ``` Likewise `flag ?? false || true` is `flag ?? (false || true)`. ## Restrictions - **The left operand must be a native optional.** A plain value is never absent: `count ?? 0` is `error: operator '??' requires an optional left operand, but found 'int32'`. A raw pointer is rejected the same way, even though it may be null; make it an optional pointer `(*T)?` first. - **A fallible is rejected**, because coalescing would silently throw its error away: ```text error: operator '??' cannot take 'int32 ! E' note: coalescing tests one optional level and would silently discard an error help: recover the error with 'catch', or propagate it with '?' ``` :brThe fallible counterpart of `??` is `catch { else => fallback }`; see [Handling failures](https://rux-lang.dev/docs/lang/errors/handling). - **There is no `??=`.** `cached ??= 5;` does not parse; write `cached = cached ?? 5;`. - `??` is compiler-owned control flow. It cannot be declared in an `extend` block or overloaded. ## Ownership `??` consumes the optional it is given. A named optional of a copyable type is copied and stays usable. A named optional of a move-only type must be moved explicitly, and so must a move-only fallback: ```rux let h = (<-maybe) ?? <-fallback; ``` Without the `<-` the compiler stops with `error: move-only value 'h' requires an explicit '<-' in coalescing operand`. The fallback is moved only when it is used, so after this line `fallback` is *possibly* moved, and is destroyed at the end of its scope if it was not. A borrowed optional — a `&T?` — is never an operand; match it instead. See [Copy and move](https://rux-lang.dev/docs/lang/ownership/copy-and-move). ## See also - [Optionals](https://rux-lang.dev/docs/lang/optionals/overview) — the type `T?` and its patterns - [Optional propagation](https://rux-lang.dev/docs/lang/optionals/propagation) — `?`, when absence should reach the caller - [Handling failures](https://rux-lang.dev/docs/lang/errors/handling) — `catch`, the fallback for a fallible - Learn: [Coalesce](https://rux-lang.dev/docs/learn/coalesce), [Coalesce exit](https://rux-lang.dev/docs/learn/coalesce-exit), [Absence to error](https://rux-lang.dev/docs/learn/absence-to-error) # Optional Propagation Postfix `?` on an [optional](https://rux-lang.dev/docs/lang/optionals/overview) removes one level of it. When the optional is present, `value?` is its payload and evaluation carries on. When it is absent, the enclosing function returns absence at once, and nothing after the `?` runs. ```text propagate-expr = postfix-expr "?" ``` The `?` is written tight against its operand. With whitespace on both sides, `?` is the conditional operator `c ? a : b` instead; see [Conditional](https://rux-lang.dev/docs/lang/expressions/conditional). ## Semantics ```rux func Parse(text: char8[..]) -> int32? { if text.length == 0 { return none; } var value = 0i32; for c in text { if c < c8'0' || c > c8'9' { return none; } value = value * 10 + ((c - c8'0') as int32); } return value; } func Sum(left: char8[..], right: char8[..]) -> int32? { return Parse(left)? + Parse(right)?; } ``` `Sum("12", "30")` is `42`. `Sum("12", "x")` is `none`: the second `?` finds absence and returns it. Each `?` operand is evaluated exactly once, from left to right, so in `Sum("x", "30")` the second `Parse` never runs. `value?` means the same as this match, with the absent arm leaving the function: ```rux match value { v? => v, none => return none } ``` Leaving through `?` is an ordinary `return`: [deferred statements](https://rux-lang.dev/docs/lang/ownership/defer) run and live locals are destroyed. ## The enclosing function Absence has to go somewhere, so the function containing the `?` must be able to return it. Two return types qualify: | The function returns | Absence leaves as | | -------------------- | ------------------------------------------------------------ | | `U?` | `none` | | `U? ! F` | a *successful* `none` — a fallible whose success is optional | `U` need not be the payload type of the operand; only the absence is passed on. The second form lets one function propagate both absence and failure: ```rux func ReadLine(ok: bool) -> char8[..]? ! IoError { if !ok { fail IoError { code: 5 }; } return "42"; } func FirstNumber(ok: bool) -> int32? ! IoError { let line = ReadLine(ok)?; // a failure leaves as a failure let text = line?; // absence leaves as a successful none return Parse(text); } ``` Absence never becomes an error. In a function returning a plain `int32 ! NotFound`, `?` on an optional is rejected, because there is no absent value to return and `?` will not invent an error: ```text error: '?' propagates the absence of 'int32?', but the enclosing function returns 'int32 ! NotFound' note: absence leaves as an optional's 'none', or as the successful 'none' of 'U? ! F'; '?' never invents an error for it help: declare an optional result, as in '-> T?', or supply a fallback with '??' ``` To turn absence into a failure, say which failure: `value ?? fail NotFound {}`. See [Coalescing](https://rux-lang.dev/docs/lang/optionals/coalescing#a-fallback-that-leaves). The same message, with `'int'` at the end, is what `Main` gets when it returns a plain `int`. ## One level at a time `?` removes exactly one level. On an `int32??` the result is an `int32?`: a present absence is present, so it continues as `none` instead of leaving. ```rux func Inner(present: bool) -> int32?? { return present ? .Some(none) : none; } func Peel(present: bool) -> int32? { let once: int32? = Inner(present)?; return once; } ``` Two levels need two propagations, and they must be grouped. `??` is a single token — the [coalescing operator](https://rux-lang.dev/docs/lang/optionals/coalescing) — so `Inner(present)??` is a `??` missing its right operand (`error: expected an expression after '??' before ';'`). Write: ```rux func PeelBoth(present: bool) -> int32? { return (Inner(present)?)?; } ``` `?` and `??` compose: `Inner(present)? ?? 17` returns absence for an outer `none`, and uses `17` for a present absence. ## Restrictions - The operand must be a native optional or a native [fallible](https://rux-lang.dev/docs/lang/errors/propagation). Anything else is `error: 'int32' cannot be propagated with '?' because it is neither a native fallible nor an optional`. - A borrowed optional is never an operand — `?` moves the payload onward, and a reference owns nothing to move: ```text error: '?' cannot consume the borrowed value '&(int32?)' help: match the borrowed value to inspect it, or propagate an owned value ``` - `?` consumes its operand. A named copyable optional is copied; a named move-only one is written `(<-value)?`. See [Copy and move](https://rux-lang.dev/docs/lang/ownership/copy-and-move). ## See also - [Optionals](https://rux-lang.dev/docs/lang/optionals/overview) — the type and its patterns - [Coalescing](https://rux-lang.dev/docs/lang/optionals/coalescing) — `??` when absence has a stand-in - [Error propagation](https://rux-lang.dev/docs/lang/errors/propagation) — the same `?` on a fallible - Learn: [Optional propagate](https://rux-lang.dev/docs/learn/optional-propagate), [Absence to error](https://rux-lang.dev/docs/learn/absence-to-error) # Errors Rux has no exceptions. A function that can fail says so in its return type with a *fallible* `T ! E`: a successful `T` or a failed `E`. The caller receives the failure as an ordinary value and has to deal with it — the compiler rejects code that drops it on the floor. ```text fallible-type = [ type ] "!" type ``` | Form | Meaning | | ------- | ------------------------------------------------------------------- | | `T ! E` | a success holding a `T`, or a failure holding an `E` | | `! E` | exactly `() ! E`: successful completion with no value, or a failure | The two sides are called *channels*. They stay distinct even when `T` and `E` are the same type: an `int32 ! int32` is either a successful `5` or a failed `5`, never just `5`. Conditions that no caller could recover from — a broken invariant, a bug — are not errors in this sense. They stop the program with a [panic](https://rux-lang.dev/docs/lang/errors/panics). ## The type `!` is the loosest type operator. The postfix suffixes `?`, `[]`, `[N]` and `[..]` bind first, then `|` (a [sum](https://rux-lang.dev/docs/lang/sums/overview)), then `!`: | Type | Means | | -------------------------------- | ---------------------------------------------------------- | | `int32 | bool ! IoError` | `(int32 | bool) ! IoError` | | `int32 ! ParseError | IoError` | `int32 ! (ParseError | IoError)` — an error sum | | `int32? ! IoError` | a fallible whose success is optional | | `int32 ! (IoError?)` | a fallible whose error is optional — the group is required | | `(int32 ! IoError)?` | an optional fallible | | `(int32 ! ParseError) ! IoError` | a nested fallible — the group is required | A type holds at most one unparenthesized `!`: ```text error: a type contains at most one unparenthesized '!' help: group the nested fallible, as in '(T ! E) ! F' or 'T ! (E ! F)' ``` ## Producing a result Inside a function that returns `T ! E`: | Write | Produces | | ------------------- | -------------------------------------------------- | | `return value;` | a success holding `value` | | `fail error;` | a failure holding `error`, and leaves the function | | `return;` | a success, when the success type is exactly `()` | | falling off the end | a success, when the success type is exactly `()` | ```rux variant DivideError { ByZero, Inexact(int) } func ExactDivide(a: int, b: int) -> int ! DivideError { if b == 0 { fail DivideError::ByZero; } if a % b != 0 { fail DivideError::Inexact(a % b); } return a / b; } func Save(ok: bool) -> ! IoError { if !ok { fail IoError { code: 28 }; } PrintLine("saved"); } ``` `return` is the success channel and `fail` the failure channel, and each checks its own operand: `return DivideError::ByZero;` is `error: 'return' value must have type 'int ! DivideError', but found 'DivideError'`, and `fail 30;` is `error: 'fail' value must have type 'DivideError', but found 'int'`. In a `! E` function there is no value to return, so `return 0;` is `error: 'return' value must have type '! IoError', but found 'int'`. `fail` is a statement, and it is only allowed in a function with an error channel: ```text error: 'fail' needs an enclosing fallible function, but this function returns 'int' help: declare the function's error channel, as in '-> T ! E' or '-> ! E' ``` `fail` leaves like `return`: the error is evaluated first, then [deferred statements](https://rux-lang.dev/docs/lang/ownership/defer) run and live locals are destroyed. Only a success type of exactly `()` completes without a value. A function with no return type is a void function, not a unit-returning one, and a type that merely contains the unit, such as `()?`, still needs a value: `return;` there is `error: 'return' requires a value of type '()?'`. ## Constructing either channel `.Success(value)` and `.Failure(error)` build a fallible as a value, without leaving the function. They can be stored, passed, compared and returned like anything else: ```rux let accepted: int ! DivideError = .Success(3); let rejected: int ! DivideError = .Failure(DivideError::ByZero); let plain: int ! DivideError = 3; // a plain value is a success let unit: ! IoError = .Success(()); // the unit success let same: int32 ! int32 = .Failure(5); ``` A plain value of the success type becomes a success wherever a fallible is expected, as `plain` shows; a failure always needs `.Failure` or `fail`. A constructor needs an expected type for whatever it does not fix itself: ```text error: cannot infer the type of 'promised' from a native constructor with an unknown channel ``` `return .Failure(error);` and `fail error;` produce the same result; `fail` is the usual spelling, and `.Failure` is for a failure that is stored rather than returned. ## Error types An error is an ordinary value of an ordinary type. There is no base error type, no error interface, and no implicit conversion between error types. Common choices: | Error type | Use it when | | --------------------------------------------------------------- | ------------------------------------------------------------------------- | | a `struct` | one kind of failure, with details: `IoError { code: 28 }` | | a [`variant`](https://rux-lang.dev/docs/lang/variants/overview) | several named kinds, each with its own payload: `DivideError::Inexact(1)` | | an [`enum`](https://rux-lang.dev/docs/lang/enums/overview) | several kinds with no payload | | a [sum](https://rux-lang.dev/docs/lang/sums/overview), `A | B` | the failures of several steps, each kept with its own type | | `()` | only the fact of failure matters: `int32 ! ()`, `fail ();` | An error sum widens implicitly: a `fail` or `?` with any member — or with a smaller sum of members — fits. A public function usually names a [`variant`](https://rux-lang.dev/docs/lang/variants/overview) instead, so that its error does not change every time an internal step gains a failure; a [type alias](https://rux-lang.dev/docs/lang/types/aliases) of a sum hides none of its members. ## Reading the result A fallible is not its success value: `ExactDivide(12, 2) / 2` is `error: operator '/' cannot combine left operand 'int ! DivideError' with right operand 'int'`. The value inside is reached by one of these: | Tool | Who decides what a failure means | | --------------------------------------------------------------------------------------------- | ---------------------------------------- | | [`match`](https://rux-lang.dev/docs/lang/errors/handling#matching) on `.Success` / `.Failure` | this function, case by case | | [`catch { … }`](https://rux-lang.dev/docs/lang/errors/handling#catch) | this function, with a recovery value | | [`?`](https://rux-lang.dev/docs/lang/errors/propagation) | the caller — the failure is passed on | | [`? else (e => …)`](https://rux-lang.dev/docs/lang/errors/propagation#error-mapping) | the caller, after the error is converted | ```rux func Show(outcome: int ! DivideError) { match outcome { .Success(value) => PrintLine("= {}", value), .Failure(DivideError::ByZero) => PrintLine("division by zero"), .Failure(DivideError::Inexact(rest)) => PrintLine("remainder {}", rest) } } ``` A fallible cannot be ignored. Calling `ExactDivide(12, 4);` as a statement is an error; see [Discarding a result](https://rux-lang.dev/docs/lang/errors/handling#discarding-a-result). ## Nesting Levels never collapse. In a `(int32 ! ParseError) ! IoError`, a failed inner result held as a success is *data* — the outer operation worked, and what it produced is a failure — not a failure of the outer level: ```rux func Layered(depth: int32) -> (int32 ! ParseError) ! IoError { if depth == 0 { return .Success(.Success(1)); } if depth == 1 { return .Success(.Failure(ParseError { position: 2 })); } fail IoError { code: 3 }; } ``` `?`, `catch` and a `.Success`/`.Failure` pattern each handle exactly one level. Where a value could become either a success or a failure of the outer level, the compiler refuses to guess: with `type R = int32 ! ParseError;`, `return value;` in a function returning `(int32 | R) ! ParseError` could store `value` as successful data or forward its failure. ```text error: conversion from 'int32 ! ParseError' to '(int32 | (int32 ! ParseError)) ! ParseError' is ambiguous; write '.Success(...)', '.Some(...)', or '?' to choose one, or annotate an intermediate type ``` `return .Success(value);` stores it, and `return value?;` forwards it. ## Equality `==` and `!=` compare the channel first, then the active payload with the payload's own `==`. A success and a failure holding equal values are different, and two unit successes are equal. ## A fallible Main [`Main`](https://rux-lang.dev/docs/lang/functions/main) may return `! E` or `int ! E`, so the top level of a program can use `?`: | `Main` returns | Exit status on success | On failure | | -------------- | ---------------------- | ---------- | | `! E` | `0` | `1` | | `int ! E` | the returned `int` | `1` | A failure runs the ordinary cleanup — defers and destructors — and exits with status 1 **without printing anything**. Report what the user needs to know before failing. ## No methods A fallible is a compiler-owned form. It cannot be extended and implements no interface; operations on fallibles are generic free functions, such as [`Core::Succeeded` and `Core::Failed`](https://rux-lang.dev/docs/lang/errors/handling#asking-without-handling). ## Layout A fallible is stored as an 8-byte tag (success or failure) followed by the payload of the active channel, so `sizeof(int32 ! int64)` is 16. A zero-sized payload takes no room: a `! E` is the tag and an `E`, and `sizeof(! ())` is 8. The tag values are not a stable ABI. See [Layout](https://rux-lang.dev/docs/lang/memory/layout). ## See also - [Handling failures](https://rux-lang.dev/docs/lang/errors/handling) — `match`, `catch`, and the discard rules - [Error propagation](https://rux-lang.dev/docs/lang/errors/propagation) — `?`, `? else`, and `?? fail` - [Panics](https://rux-lang.dev/docs/lang/errors/panics) — failures that stop the program - [Optionals](https://rux-lang.dev/docs/lang/optionals/overview) — absence, which is not an error - Learn: [Fallible](https://rux-lang.dev/docs/learn/fallible), [Fail](https://rux-lang.dev/docs/learn/fail), [Unit fallible](https://rux-lang.dev/docs/learn/unit-fallible), [Outcome](https://rux-lang.dev/docs/learn/outcome), [Error variant](https://rux-lang.dev/docs/learn/error-variant), [Error sum](https://rux-lang.dev/docs/learn/error-sum), [Nested fallible](https://rux-lang.dev/docs/learn/nested-fallible), [Fallible main](https://rux-lang.dev/docs/learn/fallible-main) # Handling Failures A function that receives a [fallible](https://rux-lang.dev/docs/lang/errors/overview) `T ! E` either handles the failure itself or passes it on. This page covers handling it: a `match` over both channels, postfix `catch`, and deliberately discarding a result. Passing it on is [Error propagation](https://rux-lang.dev/docs/lang/errors/propagation). ## Matching An ordinary [`match`](https://rux-lang.dev/docs/lang/patterns/match) selects a channel with the patterns `.Success(p)` and `.Failure(p)`. The inner pattern can be anything that matches the payload — a binding, a literal, a variant case, a typed pattern for an error sum, or another channel pattern for a nested fallible: ```rux func Percent(text: char8[..]) -> int { return match ParsePercent(text) { .Success(value) => value, .Failure(_: DigitError) => -1, .Failure(error: RangeError) => -error.value }; } ``` | Pattern | Matches | | ----------------------- | ------------------------------------------------------- | | `.Success(p)` | a success whose value matches `p` | | `.Success(())` | the success of a `! E` | | `.Failure(p)` | a failure whose error matches `p` | | `.Failure(e: A)` | a failure whose error is the member `A` of an error sum | | `.Failure(E::Case(x))` | a failure holding one case of a variant error | | `.Success(.Failure(e))` | an inner failure held as the outer success | Coverage is checked across both channels and every level, and the diagnostic names what is missing: ```text error: match on 'int ! NobodyToShare' is not exhaustive; missing .Failure(_) error: match on 'int ! (DigitError | RangeError)' is not exhaustive; missing .Failure(_: RangeError) error: match on 'int? ! SensorError' is not exhaustive; missing .Success(none) ``` A `.Success` pattern always has one field. For a `! E` it is the unit: `.Success => …` is `error: pattern '.Success' expects 1 field, but found 0`; write `.Success(())` or `.Success(_)`. ## catch `catch` recovers from the failure of one fallible. It is postfix, written right after the fallible expression, and its arms match the **error** only: ```text catch-expr = postfix-expr "catch" "{" match-arm { "," match-arm } [ "," ] "}" ``` ```rux variant DigitError { Blank, Letter(char) } func Lenient(c: char) -> int { return ReadDigit(c) catch { DigitError::Blank => 0, DigitError::Letter('O') => 0, DigitError::Letter(_) => -1 }; } ``` - The subject is evaluated once. A success passes through unchanged and no arm runs; the expression's value is the success value. - A failure is matched against the arms, which use ordinary match-arm grammar — guards and an `else` arm included — and must cover every error value: `error: match on 'DigitError' is not exhaustive; missing DigitError::Blank`. - Each arm either produces a value of the **success type** or leaves the function. `DigitError::Blank => "blank"` in the example is `error: 'catch' arm produces 'char8[..]', but the recovered value has type 'int'`. - The result of `catch` is a plain `T` — the fallible is fully handled. An arm leaves with `fail`, `return`, `break`, `continue`, a call to [`Panic`](https://rux-lang.dev/docs/lang/errors/panics) or a [`#NoReturn()`](https://rux-lang.dev/docs/lang/attributes/noreturn) function. A leaving arm does not decide the result type, and its `fail` or `?` is an ordinary exit from the enclosing function — the same `catch` never sees it again: ```rux func Strict(c: char) -> int ! IoError { let digit = ReadDigit(c) catch { e => fail IoError { code: 22 } }; return digit * 2; } let trusted = ReadDigit('8') catch { e => Panic("a literal digit always reads") }; ``` `catch` applies only to a native fallible. On an optional or a plain value it is `error: 'catch' recovers a native fallible, but the subject has type 'int?'`; the optional counterpart is [`??`](https://rux-lang.dev/docs/lang/optionals/coalescing). ### A fallback for every failure `catch { else => fallback }` is the fallible counterpart of `??`: the success value, or `fallback` for any failure. ```rux let digit = ReadDigit(c) catch { else => 0 }; ``` Unlike `??`, `catch` has no brace-less form; the braces are always written. ### Block arms An arm whose body is a block `{ … }` completes with `()`. It is therefore valid only where the success type is `()` — a `! E` — unless the block ends by leaving: ```rux Close(false) catch { e => { PrintLine("close failed with {}", e.code); } }; ``` On a fallible with a value, an empty block is rejected rather than inventing one: ```text error: a block arm completes with '()', but 'catch' must recover a value of type 'int32' help: give the arm a value, or leave it with 'fail', 'return', or a call to 'Panic' ``` An expression arm has to have the success type too. `e => PrintLine("…")` in a `! E` catch is an error, because `PrintLine` returns `IoError?`, not `()`; put the call in a block. ### Binding `catch` binds tighter than every binary operator, to the postfix expression right before it, and a postfix chain continues after the closing brace: ```rux PrintLine("{}", 1 + ReadDigit('x') catch { else => 10 }); // 11: only ReadDigit is recovered PrintLine("{}", ReadDigit('4') catch { else => 0 } * 10); // 40 ``` A `match` expression may be the subject: `let picked = match key { … } catch { else => -1 };`. A match statement takes no postfix operator. `catch` handles one level. On a `(int32 ! ParseError) ! IoError`, only the outer `IoError` reaches the arms; an inner failure is part of the success and passes through. `catch` consumes its subject. A named copyable fallible is copied; a named move-only one is written `(<-outcome) catch { … }`. An arm that binds the error owns it, and an error no arm binds is destroyed when its arm is chosen. ## Discarding a result A failure that nothing looks at is lost, so the compiler rejects the ways a fallible can be silently thrown away: | Code | Result | | ---------------------------------------------------------- | --------------------------------------- | | `Save(true);` — an expression statement | error | | `let _ = Save(true);` | error | | a match statement arm whose bare expression is a fallible | error | | `let r = Save(true);` and `r` is never read | warning | | `Save(true) catch { else => {} };` | a deliberate discard — only for a `! E` | | a `match` with `.Success(_) => {}` and `.Failure(_) => {}` | a deliberate discard of any fallible | ```text error: fallible result of type '! IoError' is discarded note: a failure that nothing handles is lost help: propagate it with '?', recover with 'catch', or match both '.Success' and '.Failure' ``` For `let _`, the note reads `binding a fallible to '_' does not handle its failure`. The unread local is `warning: fallible local 'r' is never read; its failure is never handled`. Deliberate discards, for cleanup whose outcome does not matter: ```rux Close(false) catch { else => {} }; // a ! E match ReadDigit('5') { // a fallible with a value .Success(_) => {}, .Failure(_) => {} } ``` These checks are practical, not a proof that every error is handled. Reading, passing, returning, storing or overwriting a fallible counts as a use, and nothing is followed further — through fields, containers or later writes. ::note **PrintLine is not fallible.**:br`Io::PrintLine` returns `IoError?` — an optional that reports a console write problem. An optional may be ignored, which is why `PrintLine(…);` is a valid statement while a bare call to a fallible function is not. :: ## Asking without handling `Core` provides two generic functions for code that needs only the answer, such as a branch or an assertion: ```rux import Core::{ Failed, Succeeded }; ``` | Function | Returns | | ----------------------------------------- | --------------------------------- | | `Succeeded<T, E>(outcome: T ! E) -> bool` | whether `outcome` holds a success | | `Failed<T, E>(outcome: T ! E) -> bool` | whether `outcome` holds a failure | Both consume their argument; the payload is destroyed after the question is answered. `is` does not test channels — `outcome is int32` on a fallible is `error: 'is' cannot test the channel of fallible 'int32 ! IoError'`. ## Idioms | Wanted | Write | | ------------------------------------------- | --------------------------------------------------------------------------------------------------------------------- | | a fallback value for any failure | `outcome catch { else => fallback }` | | a fallback per kind of failure | `outcome catch { Kind::A => …, Kind::B => … }` | | an expected success, where failure is a bug | `outcome catch { e => Panic("why it cannot fail") }` | | translate the failure and keep failing | `outcome catch { e => fail Wrap(e) }`, or [`? else`](https://rux-lang.dev/docs/lang/errors/propagation#error-mapping) | | pass the failure on unchanged | [`outcome?`](https://rux-lang.dev/docs/lang/errors/propagation) | | ignore a unit fallible | `outcome catch { else => {} };` | `??` is not one of them: `ReadDigit('7') ?? 5` is `error: operator '??' cannot take 'int ! DigitError'`, because coalescing would discard the error. ## See also - [Errors](https://rux-lang.dev/docs/lang/errors/overview) — the fallible type and how failures are produced - [Error propagation](https://rux-lang.dev/docs/lang/errors/propagation) — handing a failure to the caller - [Match](https://rux-lang.dev/docs/lang/patterns/match) and [Patterns](https://rux-lang.dev/docs/lang/patterns/patterns) - Learn: [Outcome](https://rux-lang.dev/docs/learn/outcome), [Discard](https://rux-lang.dev/docs/learn/discard), [Catch](https://rux-lang.dev/docs/learn/catch), [Catch fallback](https://rux-lang.dev/docs/learn/catch-fallback) # Error Propagation Often the function that receives a failure is not the one that should decide what it means. Postfix `?` hands it to the caller: on success, `outcome?` is the success value and evaluation carries on; on failure, the enclosing function fails at once with the same error. ```text propagate-expr = postfix-expr "?" map-expr = postfix-expr "?" "else" "(" binder "=>" expr ")" binder = identifier | "_" ``` ## `?` on a fallible ```rux func ParseNumber(text: char8[..]) -> int ! DigitError { var value = 0; for i in 0..text.length { let c = text[i]; if c < c8'0' || c > c8'9' { fail DigitError { position: i }; } value = value * 10 + ((c - c8'0') as int); } return value; } func Area(width: char8[..], height: char8[..]) -> int ! DigitError { return ParseNumber(width)? * ParseNumber(height)?; } ``` `outcome?` is shorthand for this match, with the failure arm leaving the function: ```rux match outcome { .Success(value) => value, .Failure(error) => fail error } ``` ```mermaid flowchart LR step["`ParseNumber(width)?`"] --> q{"Which channel?"} q -- "`.Success(value)`" --> go["the expression is `value`;<br/>`Area` carries on"] q -- "`.Failure(error)`" --> out["`Area` fails at once<br/>with the same `error`"] ``` - The operand is evaluated exactly once. Several `?` in one expression run from left to right, and the first failure leaves before the rest are evaluated. - Leaving through `?` is an ordinary return: the error is captured first, then [deferred statements](https://rux-lang.dev/docs/lang/ownership/defer) run in reverse order and live locals are [destroyed](https://rux-lang.dev/docs/lang/ownership/destructors) — including the completed fields of an aggregate whose construction the `?` interrupted. - `?` removes one level. The success value continues as it is, even when it is itself a fallible: in a `(int32 ! ParseError) ! IoError`, `?` forwards only the outer `IoError`, and an inner failure continues as data. ## Requirements ### The function must be fallible The failure leaves through the enclosing function's own failure channel, so that function must return `U ! F` (or `! F`): ```text error: '?' propagates native fallible 'int ! DigitError', but the enclosing function returns 'int' note: '?' leaves through the outer failure channel of a fallible function help: declare the function's error channel, as in '-> T ! E', or handle the failure with 'match' ``` The success types need not match — only the error is passed on. An optional return type is not a target for a failure, and a [fallible `Main`](https://rux-lang.dev/docs/lang/errors/overview#a-fallible-main) lets the top level of a program use `?`. ### The error must fit `?` never converts an error. An error of type `E` leaves a function that fails with `F` only when: | `E` and `F` | Example | | ----------------------------------------- | ------------------------------------------------------------------ | | the same type | `DigitError` into `DigitError` | | `E` is a member of the sum `F` | `DigitError` into `DigitError | RangeError` | | `E` is a sum whose members are all in `F` | `DigitError | RangeError` into `DigitError | IoError | RangeError` | ```rux func ParsePercent(text: char8[..]) -> int ! (DigitError | RangeError) { let value = ParseNumber(text)?; if value > 100 { fail RangeError { value: value }; } return value; } ``` Any other pair is rejected: ```text error: '?' propagates error type 'DigitError', but the enclosing function fails with 'SettingError' note: '?' moves an error into the outer failure only by identity, sum member injection, or subset widening; it never converts an error help: map the error to 'SettingError' with '? else (e => ...)', or match the value ``` ## Error mapping `value? else (e => mapper)` propagates like `value?`, but converts the error first. On success the mapper never runs. On failure, `e` is bound to the complete error, the mapper runs once, and the function fails with its result: ```rux func ParseWidth(text: char8[..]) -> int ! SettingError { let width = ParseNumber(text)? else (e => SettingError { name: "width", column: e.position + 1 }); return width; } ``` The mapper is the place to add context the error does not carry — here, the name of the setting and a 1-based column. - The parentheses hold one binder and one expression. The binder may be `_` when the error is not needed and is copyable. A move-only error must be bound and moved, `(e => Wrap(<-e))`; `_` there is `error: the error 'Owned' cannot be discarded with '_' because it is move-only`. - The mapped value must convert to the enclosing function's error type: `ParseNumber(width)? else (e => 5)` is `error: the mapped error has type 'int', but the enclosing function fails with 'SettingError'`. - A mapped value is never propagated again, so a mapper that returns a fallible is a type error, not a second `?`. - The mapper may leave on its own with `fail`, `return` or a call to `Panic`. A `return` there takes the normal exit instead of failing. - The mapper is not a closure. It reads and moves the surrounding locals under the ordinary rules, on a path that always leaves the function; a local moved only inside the mapper is still owned on the continuing path. - `? else` applies only to a native fallible, in a fallible function. On an optional it is `error: '? else' maps the error of a native fallible, but the operand has type 'int?'` — absence has no error to map. A mapper that converts different members differently is a `match`, usually in a helper function: ```rux func ToConfig(error: ParseError | IoError, line: int32) -> ConfigError { return match error { parse: ParseError => ConfigError { kind: 1, detail: parse.position * 100 + line }, io: IoError => ConfigError { kind: 2, detail: io.code * 100 + line } }; } func Load(text: int32, line: int32) -> int32 ! ConfigError { let value = Read(text)? else (e => ToConfig(e, line)); return value + 1; } ``` ## From absence to failure `?` on an [optional](https://rux-lang.dev/docs/lang/optionals/propagation) passes on absence, never an error; in a function that fails with `F`, it is rejected. When absence should be a failure, the [coalescing](https://rux-lang.dev/docs/lang/optionals/coalescing) fallback says which one: ```rux func PriceOf(code: int) -> int? { return code == 1 ? .Some(250) : none; } func Total(code: int, count: int) -> int ! UnknownProduct { let price = PriceOf(code) ?? fail UnknownProduct { code: code }; return price * count; } ``` A function that returns `U? ! F` can pass on both: `?` on a fallible forwards the failure, and `?` on an optional returns a successful `none`. ## Ownership `?` and `? else` consume their operand. A named copyable fallible is copied and stays usable; a named move-only one must be moved explicitly: ```text error: move-only value 'h' requires an explicit '<-' in propagation operand help: prefix the outcome with '<-', as in '(<-h)?' ``` A borrowed fallible is never an operand; match it instead. The continuing value and the outgoing error are moved with their move operations. ## See also - [Errors](https://rux-lang.dev/docs/lang/errors/overview) — the fallible type - [Handling failures](https://rux-lang.dev/docs/lang/errors/handling) — deciding here instead of passing on - [Optional propagation](https://rux-lang.dev/docs/lang/optionals/propagation) — the same `?` on an optional - Learn: [Propagate](https://rux-lang.dev/docs/learn/propagate), [Error mapping](https://rux-lang.dev/docs/learn/error-mapping), [Error sum](https://rux-lang.dev/docs/learn/error-sum), [Absence to error](https://rux-lang.dev/docs/learn/absence-to-error), [Fallible main](https://rux-lang.dev/docs/learn/fallible-main) # Panics A *panic* stops the program at once. It is for conditions that cannot happen in a correct program — a broken invariant, an impossible case — where no caller could sensibly recover. A failure that a working program can meet, such as bad input or a missing file, is an [error](https://rux-lang.dev/docs/lang/errors/overview) instead: a fallible the caller handles. | | A fallible `T ! E` | A panic | | ----------- | ----------------------------------------------------- | --------------------------- | | Is for | something the world can do: bad input, a missing file | something only a bug can do | | The caller | must handle it, and can recover | never sees it | | The program | carries on | stops | | Cleanup | defers and destructors run | nothing runs | ## Panic `Core::Panic` stops the program with a message: ```rux import Core::Panic; import Io::PrintLine; func Main() -> int { defer PrintLine("deferred"); PrintLine("before"); Panic("gave up"); return 0; } ``` ```text before Panic: gave up at Main (Src/Main.rux:7:5) ``` The report goes to the standard error stream: `Panic: `, the message, and the function, file, line and column of the call. The message is a `char8[..]`; to include a value in it, print the value first. `Panic` never returns, so it may stand wherever a value is expected — as a match or `catch` arm, a `??` fallback, or a `? else` mapper — without affecting the type of the result: ```rux let trusted = ReadDigit('8') catch { e => Panic("a literal digit always reads") }; let value = Lookup(key) ?? Panic("the key is always present"); ``` ## Assert and DebugAssert An assertion is a panic with a condition attached. When the condition holds nothing happens; when it does not, the program stops: ```rux import Core::Assert; import Io::PrintLine; func Median(scores: int[..]) -> int { Assert(scores.length > 0, "a median needs at least one score"); return scores[scores.length / 2]; } func Main() -> int { let scores = [3, 5, 8]; PrintLine("{}", Median(scores)); PrintLine("{}", Median(scores[0..0])); return 0; } ``` ```text 5 Assertion failed: a median needs at least one score at Median (Src/Main.rux:5:5) ``` The condition must be a `bool`: `Assert(scores.length, "…")` is `error: argument 1 to 'Assert' has type 'uint64', but parameter 'condition' requires 'bool8'`. Write the message as what was expected — the failing value is not printed. `DebugAssert`, also imported from `Core`, is the same check, kept only in builds with debug assertions: | | `Assert` | `DebugAssert` | | ----------------------------------- | -------- | --------------------------------------------- | | Debug build (`rux run`) | checked | checked | | Release build (`rux run --release`) | checked | removed — **its arguments are not evaluated** | A `DebugAssert` in a release build is gone entirely: a condition that calls a function does not call it, so any side effect of the condition disappears too. Keep the work outside the assertion and assert on its result. Whether debug assertions are on is the compile-time value `#build.debugAssertions`; see [Context values](https://rux-lang.dev/docs/lang/comptime/context). ## Functions that never return A function of your own can promise never to return with the [`#NoReturn()`](https://rux-lang.dev/docs/lang/attributes/noreturn) attribute. Like `Panic`, a call to it may then stand where a value is expected: ```rux #NoReturn() func Unreachable(what: char8[..]) { PrintLine("reached {}", what); Panic("unreachable code was reached"); } func Days(month: int) -> int { return match month { 2 => 28, 4 => 30, 6 => 30, 9 => 30, 11 => 30, 1..=12 => 31, else => Unreachable("a month outside 1 to 12") }; } ``` A `#NoReturn()` function declares no return type (`error: '#NoReturn' function cannot declare a return type`) and may not contain `return` (`error: return is not allowed in a '#NoReturn' function`). Without the attribute, the `else` arm above would be an ordinary call that completes with `()`, and the match would be `error: match arm type mismatch: expected 'int', found '()'`. Every path through a `#NoReturn()` function's body must end by panicking, by calling another function that never returns, or in an endless `loop`. A body that can reach its end is an error: ```text error: '#NoReturn' function 'Stop' can reach the end of its body help: end every path with 'Panic', a call to another '#NoReturn' function, or an endless 'loop' ``` ## Run-time checks Some operations check their operands while the program runs, on every target and in every build profile, and panic when the check fails. Each report names the function, file, line and column of the operation: | Report | Raised by | | ------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------- | | `Panic: division by zero` | integer `/`, `%`, `/=` or `%=` with a zero divisor | | `Panic: division overflow` | signed `/` or `%` of the type's minimum by `-1`, whose quotient does not fit | | `Panic: index out of range` | `a[i]` on an array or slice with `i` not below the length; `a[start..end]` unless `start <= end <= a.length` | | `Panic: no match arm matched value of 'T'` | a `match` that the compiler accepted as exhaustive meets a value outside it, such as an enum value made with `as` from an integer that names no case | ```rux import Io::PrintLine; func At(values: int[..], i: uint) -> int { return values[i]; } func Main() -> int { let values = [1, 2, 3]; PrintLine("{}", At(values, 3)); return 0; } ``` ```text Panic: index out of range at At (Src/Main.rux:4:18) ``` A check the compiler can decide is decided at compile time instead. A constant index into a fixed array is checked when the program is compiled — `fixed[7]` on an `int32[4]` is `error: index 7 is out of range for an array of 4 elements` — and a division by a nonzero literal needs no check at all, and a release build removes checks it proves always pass. Raw-pointer indexing is never checked. Integer `+`, `-` and `*` wrap rather than panic; see [Arithmetic](https://rux-lang.dev/docs/lang/expressions/arithmetic). ## What a panic does not do A panic does not unwind. After the report the program stops on the spot: - no [deferred statement](https://rux-lang.dev/docs/lang/ownership/defer) runs — the `deferred` line in the first example is never printed; - no [destructor](https://rux-lang.dev/docs/lang/ownership/destructors) runs, for any value in any function; - no caller observes the panic, and nothing can catch it. That is deliberate: once a case that "cannot happen" has happened, the program's invariants no longer hold, and running cleanup code written on the assumption that they do can turn one failure into several. Anything that must be released on a failing path belongs on a fallible path, where the caller sees the failure and cleanup runs. ## Exit status A panic ends the process with an illegal-instruction trap, not through a normal exit. On Windows the exit status is `0xC000001D` (`STATUS_ILLEGAL_INSTRUCTION`); on Linux, macOS and FreeBSD the process is killed by `SIGILL`, which a POSIX shell reports as status `132`. Either way the status is non-zero, so a script or test runner sees the program as failed. A [fallible `Main`](https://rux-lang.dev/docs/lang/errors/overview#a-fallible-main) that fails is different: it is an ordinary exit with status `1`, after cleanup. ## See also - [Errors](https://rux-lang.dev/docs/lang/errors/overview) — failures the caller can handle - [`#NoReturn`](https://rux-lang.dev/docs/lang/attributes/noreturn) — the attribute for functions that never return - API: [`Panic`](https://rux-lang.dev/docs/api/core/diagnostics#panic), [`Assert`](https://rux-lang.dev/docs/api/core/diagnostics#assert) - Learn: [Panic](https://rux-lang.dev/docs/learn/panic), [Assert](https://rux-lang.dev/docs/learn/assert) # Sum Types A *sum type* `A | B` holds one value whose type is one of a set of distinct types, its *members*. A value of `int32 | bool` is either an `int32` or a `bool`, and it remembers which. Like optionals and fallibles, sums are compiler-owned: they need no declaration, and the members can be any types — primitives, structs, variants, slices, other native forms. ```text sum-type = type "|" type { "|" type } ``` ```rux struct Circle { radius: float64; } struct Square { side: float64; } struct Rectangle { width: float64; height: float64; } type Box = Square | Rectangle; type Shape = Circle | Box; func Area(shape: Shape) -> float64 { return match shape { c: Circle => 3.14159 * c.radius * c.radius, s: Square => s.side * s.side, r: Rectangle => r.width * r.height }; } ``` A sum is taken apart only by a [pattern](https://rux-lang.dev/docs/lang/sums/patterns), and tested with [`is`](https://rux-lang.dev/docs/lang/sums/type-tests). ## Sums, variants and unions Rux has three ways to say "one of several": | Form | Alternatives are told apart by | Tag | | --------------------------------------------------------------- | ------------------------------ | ----------- | | a sum `A | B` | their types | yes, hidden | | a [`variant`](https://rux-lang.dev/docs/lang/variants/overview) | case names, declared once | yes, hidden | | a [`union`](https://rux-lang.dev/docs/lang/unions/overview) | nothing — fields overlap | none | Use a sum when the alternatives are already types and their types say everything — `ParseError | IoError`, `Options | Defaults`. Use a `variant` when two alternatives could have the same payload type, or when the set needs a name of its own that callers depend on. ## The type is a set A sum is a set of resolved types, not a list. The compiler normalizes every sum it sees: | Rule | So | | -------------------------------------- | ---------------------------------------------- | | aliases are resolved | `bool | int32` is `bool8 | int32` | | order does not matter | `int32 | bool` and `bool | int32` are one type | | duplicates are removed | `bool | int32 | bool` is `bool8 | int32` | | nested sums are flattened | `int32 | (bool | int32)` is `bool8 | int32` | | a single remaining member is that type | `int32 | int32` is `int32` | | flattening stops at `?` and `!` | `int32 | ((bool | int32)?)` has two members | Members are kept in a canonical order derived from their fully qualified names, which is why diagnostics print `bool8 | int32` whichever order the source used. `|` binds looser than the postfix suffixes and tighter than `!`: `int32 | bool?` is rejected until it is grouped as `int32 | (bool?)` or `(int32 | bool)?`, and `Options | Defaults ! IoError` is `(Options | Defaults) ! IoError`. ## Making a sum value A value enters a sum in one of two ways, where a sum is expected — an annotated `let`, an assignment, an argument, a return value: - **Injection.** A value whose type is exactly one of the members becomes that member. - **Widening.** A value of a smaller sum whose members are all members of the target keeps its active member. ```rux func Tile(side: float64) -> Box { return Square { side: side }; // injection: Square is a member of Box } let shape: Shape = Tile(3.0); // widening: Square | Rectangle into Circle | Rectangle | Square ``` No other conversion is searched. A member is never converted to make it fit, so `let s: int32 | bool = 2.5;` is `error: cannot assign 'float64' to 'bool8 | int32'`, and a wider sum never narrows: ```text error: cannot assign 'A | B | C' to 'A | B' ``` Knowing the value is an `A` right now is not enough; take it out with a [subset pattern](https://rux-lang.dev/docs/lang/sums/patterns#subset-patterns) instead. An unsuffixed integer or float literal targets the one member of its kind, whatever its value. With two integer members it is ambiguous: ```text error: integer literal is ambiguous for 'int32 | int64', which has several integer members; add a suffix or a cast ``` Write `5i64` or `5 as int32`. Every other literal is injected only when its own type is a member. ## Using a sum A sum has none of its members' operations — not even those they all share. Arithmetic, field access, method calls and `Display` all need the member first: ```text error: operator '+' cannot combine left operand 'bool8 | int32' with right operand 'int' error: no matching overload for 'PrintLine' with argument types (char8[..], bool8 | int32) ``` What a sum does have: | Operation | Meaning | | --------------------------------------------------------- | --------------------------------------------------------------- | | a [`match`](https://rux-lang.dev/docs/lang/sums/patterns) | selects the member and binds it | | [`is`](https://rux-lang.dev/docs/lang/sums/type-tests) | tests which member is active, without taking it out | | `==`, `!=` | equal when the same member is active and the payloads are equal | | assignment, passing, returning | moves or copies the whole value, as for any type | `==` needs two operands of the same sum type. An unsuffixed literal adopts the sum's type, so `port == 8080` works for `port: int32 | bool`, but a value with a type of its own is never injected for a comparison: ```text error: operator '==' cannot compare 'bool8 | int32' with 'bool8' note: both operands of a native comparison have the same type; a comparison never injects, widens, or wraps an operand ``` Give the value the sum type first — `let off: int32 | bool = false;` — and compare two sums. Two values holding different members are unequal even when the values look alike: `7i8` and `7i64` in an `int8 | int64 | bool` differ. Like the other native forms, a sum cannot be extended and implements no interface, even when every member implements it. A [type alias](https://rux-lang.dev/docs/lang/types/aliases) of a sum names exactly its members and hides none of them. ## Generic sums A sum may be written over [type parameters](https://rux-lang.dev/docs/lang/generics/overview), `T | U`, and is normalized again for every instantiation. When the arguments coincide, the sum collapses: ```rux func Choose<T, U>(left: bool, a: T, b: U) -> T | U { if left { return a; } return b; } let same: int32 = Choose<int32, int32>(false, 1, 2); // T | U is int32 let mixed = Choose<int32, bool>(false, 1, true); // bool8 | int32 ``` A `match` over `T | U` stays valid at every instantiation by ending in `else`; see [Sum patterns](https://rux-lang.dev/docs/lang/sums/patterns#generic-sums). ## Layout A sum is stored as an 8-byte tag naming the active member, followed by that member's payload: `sizeof(int32 | bool)` is 16, and `sizeof(Circle | Rectangle)` is 24. The tag values are not a stable ABI. See [Layout](https://rux-lang.dev/docs/lang/memory/layout). ## See also - [Sum patterns](https://rux-lang.dev/docs/lang/sums/patterns) — taking a member out - [Type tests](https://rux-lang.dev/docs/lang/sums/type-tests) — `is` - [Variants](https://rux-lang.dev/docs/lang/variants/overview) and [Unions](https://rux-lang.dev/docs/lang/unions/overview) — the named and the untagged alternatives - [Errors](https://rux-lang.dev/docs/lang/errors/overview) — error sums `T ! (A | B)` - Learn: [Sum type](https://rux-lang.dev/docs/learn/sum-type), [Sum widening](https://rux-lang.dev/docs/learn/sum-widening), [Generic sum](https://rux-lang.dev/docs/learn/generic-sum) # Sum Patterns The only way to take a value out of a [sum](https://rux-lang.dev/docs/lang/sums/overview) is a pattern in a [`match`](https://rux-lang.dev/docs/lang/patterns/match) (or a [`catch`](https://rux-lang.dev/docs/lang/errors/handling#catch) arm, for an error sum). A sum pattern selects members by their type. ```text typed-pattern = ( identifier | "_" ) ":" type ``` | Pattern | Matches | Binds | | --------------- | ----------------------------------------- | ------------------------------ | | `v: T` | the member `T` | `v` as a `T` | | `_: T` | the member `T` | nothing | | `v: A | B` | any of the members `A`, `B` | `v` as the smaller sum `A | B` | | `Type::Case(p)` | the variant member `Type`, holding `Case` | whatever `p` binds | | `else` | everything left | nothing | Guards, `else` and every other match feature work as usual. See [Patterns](https://rux-lang.dev/docs/lang/patterns/patterns) for the full grammar. ## Typed patterns `v: T` selects the member `T` and binds it at the member's type, so the arm can use everything a `T` has: ```rux func Describe(shape: Circle | Square | Rectangle) -> char8[..] { return match shape { c: Circle if c.radius == 0.0 => "a point", _: Circle => "a circle", box: Square | Rectangle => match box { _: Square => "a square box", _: Rectangle => "a rectangular box" } }; } ``` The type must name a member exactly — an `int32` member is not matched by `n: int64`: ```text error: type 'int64' is not a member or subset of sum 'bool8 | int32' ``` A bare type name is not a pattern. An identifier in a pattern binds a new name, and a name that already means something else is rejected rather than silently binding the whole subject: ```text error: pattern 'int32' cannot bind a new variable because 'int32' already names a type help: write 'int32Value: int32' to select the member, 'int32 { ... }' to destructure it, or 'Type::Case' to select a case ``` ## Subset patterns `v: A | B` selects several members at once and binds them as the smaller sum `A | B`. The binding is still a sum: to reach a member's fields, match it again, as `box` is matched above. `box.side` in that arm is an error, because a `Rectangle` has no `side`: ```text error: type 'Rectangle | Square' has no field 'side' ``` A subset pattern is how a value narrows. A plain assignment from a wider sum to a smaller one is rejected; an arm that binds the subset produces a value of the smaller type that can be passed on. ## Variant members When a member is a [`variant`](https://rux-lang.dev/docs/lang/variants/overview), a qualified case pattern selects the member and its case in one step: ```rux variant Token { Number(int32), Name(char8[..]) } func Kind(value: Token | bool | int32) -> int32 { return match value { Token::Number(n) => n, Token::Name(_) => -1, flag: bool => flag ? 1 : 0, else => 99 }; } ``` The qualification is required. An unqualified `.Case` pattern works on a variant subject, but on a sum it is ambiguous by construction: ```text error: case pattern '.Missing' cannot select from sum 'DecodeError | IoError' help: write 'DecodeError::Missing' to select the member and its case ``` A qualified case is ambiguous, too, when two members are instantiations of the same generic variant: ```text error: case pattern on 'Slot' is ambiguous in 'Slot<bool8> | Slot<int32>': more than one member is that variant help: select one instantiation with a typed pattern, as in 'v: Slot<bool8>', and match it separately ``` ## Coverage A match on a sum must cover every member. The diagnostic names the first one missing: ```text error: match on 'bool8 | char8[..] | int32' is not exhaustive; missing _: char8[..] ``` An arm whose members are all covered by earlier unguarded arms is unreachable, and so is an error: ```rux func Pick(v: A | B | C) -> int32 { return match v { ab: A | B => 1, a: A => 2, // error: every A went to the first arm _: C => 3 }; } ``` ```text error: match arm is unreachable because earlier arms already match every value it matches ``` An `else` arm is the one exception: it is never reported as unreachable, even when the arms before it already cover every member. That keeps generic code valid (below). ## Borrowed subjects A match on a borrowed sum inspects it in place, and the subject stays with its owner. Through an exclusive borrow `&var`, a typed pattern binding one member writes through to the original: ```rux func Grow(shape: &var (Circle | Square)) { match shape { c: Circle => { c.radius = c.radius * 2.0; }, else => {} } } ``` A subset binding of a borrowed subject can be read and matched, but not borrowed again, stored or moved. A match on an owned sum consumes it: arms that bind a member own it, and an arm that binds nothing destroys it. See [Ownership](https://rux-lang.dev/docs/lang/ownership/overview). ## Generic sums A pattern over `T | U` is checked again at every instantiation. When `T` and `U` are the same type, the sum collapses to it, so `_: T` already covers everything — the closing `else` covers nothing, which is allowed: ```rux func Left<T, U>(value: T | U) -> bool { return match value { _: T => true, else => false }; } ``` `Left<int32, bool>(true)` is `false`; `Left<int32, int32>(5)` is `true`. A typed pattern may also name a concrete type, such as `n: int32 =>` on a `T | U` subject. It selects that member once the type parameters are substituted: in `Which<int32, bool>` and `Which<bool, int32>` it takes the `int32` values, and in `Which<int32, int32>` it takes every value. An instantiation where neither `T` nor `U` is `int32` is an error, reported at the pattern with a note naming the call that made it: ```rux func Which<T, U>(value: T | U) -> int32 { return match value { n: int32 => n, else => -1 }; } ``` ```text error: type 'int32' is not a member or subset of sum 'bool8 | uint8' note: in 'Which' instantiated with T = bool8, U = uint8 by the call at ... ``` ## Arms that build a sum An annotation gives its type to every arm of a `match` expression, and each arm is injected into the sum on its own: in `let r: int32 | bool = match n { 0 => false, else => n };` the first arm holds a `bool` and the second an `int32`. ## See also - [Sum types](https://rux-lang.dev/docs/lang/sums/overview) — the type and how values enter it - [Type tests](https://rux-lang.dev/docs/lang/sums/type-tests) — `is`, when only the member matters - [Match](https://rux-lang.dev/docs/lang/patterns/match) and [Patterns](https://rux-lang.dev/docs/lang/patterns/patterns) - Learn: [Typed pattern](https://rux-lang.dev/docs/learn/typed-pattern), [Subset pattern](https://rux-lang.dev/docs/learn/subset-pattern), [Generic sum](https://rux-lang.dev/docs/learn/generic-sum) # Type Tests `value is Type` answers a question about the type of `value` and produces a `bool`. What the question is depends on the operand: on a [sum](https://rux-lang.dev/docs/lang/sums/overview) it asks which member is active, on an [optional](https://rux-lang.dev/docs/lang/optionals/overview) whether a value is present, and on anything else it compares exact types at compile time. ```text type-test = expr "is" postfix-type ``` ```rux struct Plus {} struct Minus {} struct Number { value: int32; } type Token = Plus | Minus | Number; func IsOperator(token: Token) -> bool { return token is (Plus | Minus); } func Count(tokens: Token[..]) -> uint { var numbers: uint = 0; for token in tokens { if token is Number { numbers += 1; } } return numbers; } ``` ## What is tested The tested type is resolved first; together with the operand's type it selects the meaning: | Operand | `value is T` is `true` when | | ------------------ | --------------------------------------------------------------------------------------------- | | a sum `A | B | C` | the active member is `T`, or one of the members of a tested subset `(A | B)` | | an optional `P?` | the value is present and its payload is `T` — or, for a sum payload, a member or subset of it | | a fallible `T ! E` | — rejected; match `.Success(…)` or `.Failure(…)` instead | | any other type | the operand's type is exactly `T`, after aliases are resolved — decided at compile time | ```rux let reading: int32? = 7; let missing: int32? = none; let a = reading is int32; // true: present let b = missing is int32; // false: absent let nested: int32?? = .Some(none); let c = nested is int32?; // true: one level is present let maybe: (int32 | bool)? = true; let d = maybe is bool; // true: present, and the payload's member is bool let count: int32 = 7; let e = count is int32; // true, known before the program runs ``` A test inspects one optional level only. On an `int32??`, the payload is an `int32?`, so `nested is int32` is rejected: ```text error: type 'int32' is neither the payload of optional 'int32??' nor a member of it help: 'is' tests one presence level; match '.Some(...)' to inspect deeper levels ``` ## A test that cannot be true is an error A test whose answer is known to be `false` is a mistake, so the compiler rejects it rather than folding it to a constant: ```text error: type 'bool8' is not a member or subset of sum 'Minus | Number | Plus' error: 'is int64' can never be true for a value of type 'int32' help: an 'is' test on a value that is not a sum or an optional compares its exact type ``` On a value that is neither a sum nor an optional, `is` compares types by name and identity, never by layout: a struct with the same fields under another name is a different type. An `is` test on such a value can only be `true`, which makes it useful mostly in generic code. A fallible has no type to test — its question is which channel, which is a match: ```text error: 'is' cannot test the channel of fallible 'int32 ! E' help: match '.Success(...)' or '.Failure(...)' instead ``` ## `is` never narrows A test does not change the static type of its operand. After `token is Number` succeeds, `token` is still the whole sum, and its member's fields are still out of reach: ```rux if token is Number { PrintLine("{}", token.value); // error } ``` ```text error: type 'Minus | Number | Plus' has no field 'value' ``` To use the member, take it out with a [pattern](https://rux-lang.dev/docs/lang/sums/patterns): ```rux match token { n: Number => PrintLine("{}", n.value), else => {} } ``` `is` also never consumes, moves or binds anything. A borrowed operand is tested through the borrow. ## Grouping The right operand is a postfix type, so a sum or fallible type must be grouped: ```text error: a sum type after 'is' must be grouped help: write 'value is (Plus | Minus)' ``` `is` shares its [precedence](https://rux-lang.dev/docs/lang/expressions/overview) with `as`: it binds tighter than every binary operator, so `count is int32 && count > 0` needs no parentheses. Group it when it is the operand of a prefix operator: `!(missing is int32)`. ## Generic code A test whose operand or tested type mentions a type parameter is checked again for every instantiation. `value is T` on a `T | U` stays valid when `T` and `U` are the same type and the sum collapses — it is then a plain type comparison, and `true`: ```rux func IsLeft<T, U>(value: T | U) -> bool { return value is T; } ``` `IsLeft<int32, bool>(true)` is `false`, and `IsLeft<int32, int32>(5)` is `true`. ## Interfaces `is` does not test whether a value implements an [interface](https://rux-lang.dev/docs/lang/interfaces/overview). That would be a run-time question about the value's type, and it is reported as unavailable rather than answered wrongly: ```text error: type test 'is Shape' is unavailable: interface checks are not implemented ``` Membership is not interface implementation either: knowing that every member of a sum implements an interface, or that a test succeeded, makes no method available on the sum. ## See also - [Sum patterns](https://rux-lang.dev/docs/lang/sums/patterns) — taking the member out - [Optionals](https://rux-lang.dev/docs/lang/optionals/overview) — presence and absence - [Casts](https://rux-lang.dev/docs/lang/expressions/casts) — `as`, which shares the precedence of `is` - Learn: [Is](https://rux-lang.dev/docs/learn/is) # Ownership Every value in Rux has exactly one **owner**: a binding, a parameter, a field or element of a larger value, or a temporary that nothing has named yet. The owner decides when the value's life ends, and at that point the compiler [destroys](https://rux-lang.dev/docs/lang/ownership/destructors) it — once. A value passes from one owner to another in one of two ways. A **copy**, written `=`, makes a second, independent value and leaves the source as it was. A **move**, written `<-`, hands the value itself over and leaves the source empty. A [reference](https://rux-lang.dev/docs/lang/references/overview) is the third way to reach a value — it borrows without owning, so nothing changes hands. ## Syntax ```text let name = source; // bind a copy let name <- source; // bind by moving target = source; // copy assignment target <- source; // move assignment F(source) // pass a copy F(<-source) // move into the parameter return source; // return a copy return <-source; // move out of the function Type { field: <-source } // move into an aggregate ``` `<-` is the move operator in every position: as an assignment operator between two places, and as a prefix on an argument, a return value, a field or element value, a conditional arm, or a `match` subject. ## Copy or move A named source is **copied** unless it is written with `<-`. Copying never touches the source: both values exist afterwards, and changing one never shows in the other. Moving invalidates the source, suppresses its destruction — the new owner destroys the value instead — and makes every later read of it an error. ```rux struct Token { id: int32; } extend Token { // No copies: a Token can only be moved. func =(self: &var Token, other: &Token); } func Consume(token: Token) { PrintLine("consumed {}", token.id); } func Main() -> int { let first = Token { id: 1 }; let second <- first; // first is now empty Consume(<-second); // second is now empty return 0; } ``` ```mermaid flowchart LR a(["`a`: a value<br/>with a name"]) a -- "`let b = a`<br/>copy" --> c["two values<br/>`a` and `b` both usable"] a -- "`let b <- a`<br/>move" --> m["one value, now `b`'s<br/>`a` is empty"] a -- "`let b: &T = a`<br/>borrow" --> r["one value, still `a`'s<br/>`b` refers to it"] ``` | | Copy `=` | Move `<-` | Borrow `&T` / `&var T` | | ------------ | -------------------- | ------------------ | ---------------------- | | Values after | two | one | one | | The source | unchanged and usable | empty; reads fail | still the owner | | Destroyed by | each owner, its own | the new owner only | the original owner | Whether a type can be copied or moved at all, and what a copy does, is up to the type: see [Copy and move](https://rux-lang.dev/docs/lang/ownership/copy-and-move). Moving works for every type that does not prohibit it, a copyable one included — `let m <- n;` with an `int` `n` leaves `n` empty too. ## Fresh temporaries A value nobody has named — the result of a call, a literal, a constructor call, or the value a conditional or `match` produces — has no other owner, so it transfers directly. It needs no `<-`, and no copy runs: ```rux func Make(id: int32) -> Token { return Token { id: id }; // a literal: no '<-' } func Main() -> int { let token = Make(7); // a call result: no '<-' Consume(Make(8)); return 0; } ``` The arrow is for values that have a name. It marks, on the line where it happens, which names stop working. ## After a move Reading a moved-from name is a compile-time error. The note points at the move: ```text error: value 'first' is used after it was moved note: 'first' was moved at … help: clone 'first' before moving it if both uses are required ``` A moved-from `var` is empty, not ruined. Assigning it a whole new value makes it usable again: ```rux var token = Token { id: 1 }; let held <- token; token <- Token { id: 2 }; PrintLine("token is {} again", token.id); ``` ## Moves on some paths The compiler tracks moves through branches and loops. A value moved on one path of an `if` is unavailable after the `if`, because the compiler cannot know which path ran: ```text error: value 'token' may have been moved on some control-flow paths note: one unavailable path for 'token' originates at … help: initialize or preserve 'token' on every path before this use ``` A loop body runs again from where its last pass ended, so a value one pass moves out is not there for the next. Moving an outer local inside a loop body is an error unless the same pass gives it a new value before the loop repeats, or leaves the loop with `break`, `return` or `fail` after the move. The loop's own `for` variable and the locals declared inside the body are fresh on every pass. ```rux var slot = Token { id: 3 }; for pass in 0..2 { let taken <- slot; PrintLine("pass {} took {}", pass, taken.id); slot <- Token { id: 10 + pass as int32 }; // refilled before the next pass } ``` At run time a value moved on only some paths is tracked by a drop flag, so it is still destroyed exactly once — see [Destructors](https://rux-lang.dev/docs/lang/ownership/destructors#drop-flags). ## What cannot be moved | Written | Error | | ----------------------- | ---------------------------------------------------------- | | `return <-reference;` | `cannot move a non-owning reference` | | `let a <- value.field;` | `cannot move field 'field' out of droppable value 'value'` | | `value <- value;` | `cannot move 'value' into itself` | | `let b <- pinned;` | `moving type 'Pinned' is prohibited` | A reference owns nothing, so there is nothing to hand over. A single part cannot leave a value on its own; the value is moved whole or [taken apart](https://rux-lang.dev/docs/lang/ownership/copy-and-move#partial-moves). A type can [prohibit moving](https://rux-lang.dev/docs/lang/ownership/copy-and-move#prohibiting-moves) altogether. ## See also - [Copy and move](https://rux-lang.dev/docs/lang/ownership/copy-and-move) — how a type copies, and how it forbids copying or moving - [Destructors](https://rux-lang.dev/docs/lang/ownership/destructors) — what happens when an owner lets go - [Defer](https://rux-lang.dev/docs/lang/ownership/defer) — cleanup that belongs to a scope rather than a value - [References](https://rux-lang.dev/docs/lang/references/overview) — reaching a value without owning it - Learn: [Ownership](https://rux-lang.dev/docs/learn/ownership), [Copy](https://rux-lang.dev/docs/learn/copy), [Move](https://rux-lang.dev/docs/learn/move) # Copy and Move Copying and moving are operations a type has or does not have. By default the compiler **generates** both, structurally: a structure is copied or moved field by field, an array element by element, a tuple, variant or optional part by part. A type changes that by declaring the operation in an `extend` block — with a body to supply its own, or without one to prohibit it. ## The two special operations ```text extend T { func =(self: &var T, other: &T) { … } // custom copy func =(self: &var T, other: &T); // copying prohibited func <-(self: &var T, other: T) { … } // custom move func <-(self: &var T, other: T); // moving prohibited } ``` | Declared in `extend T` | A copy of `T` | A move of `T` | | --------------------------------------- | --------------------------- | --------------- | | nothing | copies each part | moves each part | | `func =(self: &var T, other: &T) { … }` | runs the body | unchanged | | `func =(self: &var T, other: &T);` | an error — `T` is move-only | unchanged | | `func <-(self: &var T, other: T) { … }` | unchanged | runs the body | | `func <-(self: &var T, other: T);` | unchanged | an error | A generated operation exists only when every part supports it. A structure with a move-only field is move-only itself, because copying it would copy the field: ```text error: move-only value 'booking' requires an explicit '<-' in initialization note: plain by-value use copies its source, but 'Booking' prohibits copying help: write 'let destination <- booking' to transfer ownership ``` ### Signatures The signatures are fixed, and each is checked where it is declared: | Mistake | Error | | ------------------------------------------- | -------------------------------------------------------------------------------------------------------- | | `func =(self: &var Sheet, other: Sheet)` | `copy special operation for type 'Sheet' must have signature 'func =(self: &var Sheet, other: &Source)'` | | `func <-(self: &var Sheet, other: &Sheet);` | `move special operation for type 'Sheet' must have signature 'func <-(self: &var Sheet, other: Sheet)'` | | `func =(…);` outside `extend` | `special operation '=' may only be declared in an extend block` | The parameters must be named `self` and `other`, and neither operation takes type parameters, default values or a result. A bodyless declaration in an `extend` block is a prohibition; a bodyless function in an [interface](https://rux-lang.dev/docs/lang/interfaces/overview) is an ordinary requirement. ## Custom copy A copy with a body runs for every copy of the type. `self` is the new value, in storage the compiler provides; `other` is the source, borrowed read-only, so the copy can neither change nor consume it. Once the body exists, nothing is copied field by field any more: every field the copy should have, the body sets. ```rux struct Sheet { text: char8[..]; generation: int32; } extend Sheet { func =(self: &var Sheet, other: &Sheet) { self.text = other.text; self.generation = other.generation + 1; } } func Main() -> int { let original = Sheet { text: "Minutes", generation: 1 }; let copy = original; // runs '=': generation 2 var board = Sheet { text: "Agenda", generation: 1 }; board = copy; // runs '=': generation 3 PrintLine("{} {} {}", original.generation, copy.generation, board.generation); return 0; } ``` A copy runs only when the source **keeps** its value afterwards — a named place, borrowed storage, or a reference. A fresh temporary and a source handed over with `<-` are not copied: they transfer exactly as they would initialize a binding, and the custom `=` is not called. | Written | Runs `=`? | | ----------------------- | ---------------------- | | `let copy = original;` | yes | | `Show(copy)` (by value) | yes | | `board = copy;` | yes | | `board = Sheet { … };` | no — a fresh temporary | | `board = Make();` | no — a fresh temporary | | `Show(<-copy)` | no — a move | Assigning over a live value is a replacement. The new value is produced first — by the custom `=` when it copies — then the old value is [destroyed](https://rux-lang.dev/docs/lang/ownership/destructors), and then the new one is installed. A structure whose field has a custom `=` copies that field with it, as part of its generated copy. ### Copying from another type A copy with a body may take a different source type: `func =(self: &var Celsius, other: &int32) { … }`. It is used by an assignment to an existing `Celsius`, `reading = degrees;`. It is not a conversion: `let reading: Celsius = degrees;` is still `cannot assign 'int32' to 'Celsius'`. Only the exact `T`-from-`T` form has a bodyless, prohibiting meaning. ## Prohibiting copies A bodyless `=` makes a type **move-only**. That is the right choice for any type that owns a resource — memory, a file, a handle — and does not implement a real independent copy, since two copies would each release the same resource. ```rux struct RoomKey { room: int32; } extend RoomKey { func =(self: &var RoomKey, other: &RoomKey); } ``` Every by-value use of a named move-only value then needs `<-`, and the error names the position and the spelling to use: | Where | Refused | Written with a move | Error ends with | | ------------- | ---------------------- | ------------------------ | ------------------- | | A binding | `let spare = key;` | `let spare <- key;` | `in initialization` | | An argument | `CheckOut(key)` | `CheckOut(<-key)` | `in argument` | | A return | `return key;` | `return <-key;` | `in return` | | A field value | `Booking { key: key }` | `Booking { key: <-key }` | `in aggregate` | ```text error: move-only value 'key' requires an explicit '<-' in argument note: plain by-value use copies its source, but 'RoomKey' prohibits copying help: prefix the argument with '<-', as in 'Take(<-key)' ``` Assignment to a move-only `var` always uses `<-`, even from a fresh temporary — `key = other;` and `key = RoomKey { room: 4 };` both fail with `copying type 'RoomKey' is prohibited`. Write `key <- other;` or `key <- RoomKey { room: 4 };`. Initialization from a temporary needs no arrow: `let key = RoomKey { room: 4 };` is fine. ## Prohibiting moves A bodyless `<-` prohibits moving. A value of such a type stays in the storage it was created in. Every `<-` on it is an error: ```text error: moving type 'Stay' is prohibited note: the type declares its canonical move operation without a body help: borrow the value or construct a distinct replacement instead ``` A type that keeps its copy can still be copied with `=`. A type that prohibits **both** cannot receive a value from any expression, a literal included — `let pinned = Pinned { id: 1 };` is the same error — so it is built where it lives, one part at a time: ```rux struct Pinned { id: int32; } extend Pinned { func =(self: &var Pinned, other: &Pinned); func <-(self: &var Pinned, other: Pinned); } func Peek(pinned: &Pinned) -> int32 { return pinned.id; } func Main() -> int { var pinned: Pinned; pinned.id = 4; PrintLine("{}", Peek(pinned)); return 0; } ``` ## Custom move A move with a body runs for every move of the type. `other` is the source, taken **by value**: the operation owns it, and like any by-value parameter it is destroyed when the body ends. The body therefore writes the new state into `self` from `other`, and whatever `other` still holds is released with it. ```rux struct Cell { id: int32; } extend Cell { func <-(self: &var Cell, other: Cell) { self.id = other.id; PrintLine("moved {}", other.id); } } ``` ## Partial moves A field, a tuple element or an array element cannot be moved out of a value on its own. A value that is partly there would leave nothing able to say what to destroy when its owner's scope ends, so a value is moved whole or not at all: ```text error: cannot move field 'gift' out of droppable value 'parcel' note: partial moves would leave the aggregate with only some fields initialized help: move the complete aggregate or borrow or clone the component explicitly ``` The same error names a tuple element (`field '0'`) and an array element (`indexed element [0]`). What works instead is taking the **whole** value apart with a moving [destructuring pattern](https://rux-lang.dev/docs/lang/bindings/destructuring), so that every part gets exactly one new owner: ```rux struct Item { name: char8[..]; } extend Item { func =(self: &var Item, other: &Item); func ~Item(self: &var Item) { PrintLine("{} destroyed", self.name); } } struct Parcel { wrapping: Item; gift: Item; } func Unwrap(parcel: Parcel) -> Item { let Parcel { wrapping: _, gift: gift } <- parcel; return <-gift; } ``` - A part bound to a name belongs to that binding and is destroyed with it. - A part bound to `_`, or a structure field the pattern leaves out, has no owner left, so it is destroyed on the spot — at the `let`, or at the top of a `match` arm — in the order the parts appear in the pattern. A destructuring `let` owns what it takes apart, so a move-only value is handed to it with `<-`; `= parcel` fails with `move-only value 'parcel' requires an explicit '<-' in initialization`. Tuples may always be split this way. A structure may be split only when it declares no destructor of its own, because a destructor runs on the whole value: ```text error: cannot split 'Sealed' with a moving pattern, because it declares destructor '~Sealed' note: '~Sealed' runs on the whole value, so no part of it can be taken out on its own help: bind the whole value and read its fields, or match a value that stays with its owner ``` | You want | Write | Allowed when | | ----------------------------- | --------------------------------------------------- | ------------------------------- | | one field, moved out | `<-parcel.gift` | never | | every part, each to one owner | `let Parcel { wrapping: _, gift: gift } <- parcel;` | the structure has no destructor | | to read a field | `parcel.gift.name` | always — reading moves nothing | ## Matching and ownership A `match` that binds parts of its subject takes them, the same way a destructuring `let` does. `match <-value { … }` hands the subject over; a temporary subject is taken directly. A match that binds from a named copyable value without `<-` matches a **copy** of it, which its arms own; the original stays with its owner. A match that binds nothing, or matches through a reference, takes nothing. A move-only named subject has no copy to match, so an arm that binds from it needs the subject handed over; `match box { .Full(item) => … }` fails with `move-only value 'box' requires an explicit '<-' in match subject`, and the help says `transfer the subject with 'match <-box'`. ## See also - [Ownership](https://rux-lang.dev/docs/lang/ownership/overview) — `=`, `<-` and fresh temporaries - [Destructors](https://rux-lang.dev/docs/lang/ownership/destructors) — what replacement and splitting destroy - [Destructuring](https://rux-lang.dev/docs/lang/bindings/destructuring) — the patterns a `let` takes apart - [Constructors](https://rux-lang.dev/docs/lang/structs/constructors) — making a value, as opposed to copying one - Learn: [Non-copyable types](https://rux-lang.dev/docs/learn/no-copy), [Custom copy](https://rux-lang.dev/docs/learn/custom-copy), [Partial move](https://rux-lang.dev/docs/learn/partial-move) # Destructors A **destructor** is code the compiler runs when a value's life ends. It is declared in an `extend` block, named after its type with a leading `~`, and it borrows the dying value mutably. Nothing calls it by name: the compiler invokes it exactly once for each initialized value that still owns its state, and never for a value that was moved away or never initialized. ## Syntax ```text extend T { func ~T(self: &var T) { … } } ``` ```rux struct Guest { name: char8[..]; } extend Guest { func ~Guest(self: &var Guest) { PrintLine("{} leaves", self.name); } } ``` The shape is fixed: one receiver, `self: &var T`, no other parameters, no result, no type parameters, and a body. For a generic type the name carries no type arguments: `func ~Store(self: &var Store<T>)` inside `extend Store<T>`. | Mistake | Error | | -------------------------------- | --------------------------------------------------------------------------------- | | `func ~Guest(self: &Guest)` | `destructor for type 'Guest' must have signature 'func ~Guest(self: &var Guest)'` | | `func ~Visitor(self: &var Host)` | `destructor '~Visitor' must be named '~Host' for type 'Host'` | | `func ~Ghost(self: &var Ghost);` | `destructor '~Ghost' must have a body` | | a destructor outside `extend` | `destructor '~Item' may only be declared in an extend block` | | `seat.~Guest();` | `expected a field name or tuple index after '.' before '~'` | A destructor cannot be called. To end a value's life early, replace it or move it into a function that lets it go. ## When destruction runs | Event | What is destroyed | | --------------------------------------------------------------------- | ------------------------------------------------- | | The owning scope ends — a block, a function, each pass of a loop body | every value it still owns | | `return`, `break`, `continue`, `fail`, `?` propagation | the values of every scope being left | | `=` or `<-` into a live place | the old value, after the new one is produced | | A destructuring `let` or `match` arm | each part bound to `_` or left out of the pattern | | A by-value parameter | the parameter, when the function returns | | Not destroyed | Why | | --------------------------------------------------------- | ------------------------------------------------------- | | A value moved away with `<-` | its new owner destroys it | | A value returned with `return <-value;` | the caller owns it now | | Storage declared without a value and never assigned | it holds nothing | | The old contents of storage written through a raw pointer | a pointer cannot tell whether the storage holds a value | | Anything, when the program panics or exits | panics do not unwind | A write through a raw pointer — `*p <- value`, `p[i] = value`, or a field reached through `*var T` — initializes the storage it addresses and destroys nothing. Code that replaces a value through a pointer destroys or moves out the old one first. ## Order Values that end together are destroyed in **reverse order of creation**, newest first: a value made later may depend on one made earlier, so it has to go while the earlier one is still there. A value's own destructor runs first, while its fields are still intact. Then the compiler destroys its contents — fields, tuple and array elements, and the payload of a variant case or optional — in reverse construction order: the last field first, the last element first. ```rux struct Part { name: char8[..]; } extend Part { func ~Part(self: &var Part) { PrintLine("~Part {}", self.name); } } struct Machine { first: Part; second: Part; } extend Machine { func ~Machine(self: &var Machine) { PrintLine("~Machine"); } } func Build() { let machine = Machine { first: Part { name: "first" }, second: Part { name: "second" } }; let a = Part { name: "a" }; let b = Part { name: "b" }; } ``` `Build` prints `~Part b`, `~Part a`, `~Machine`, `~Part second`, `~Part first`. A type with no destructor of its own still has its droppable parts destroyed: the compiler generates that cleanup for every structure, tuple, array, variant and optional that contains something to destroy. ## Replacement Assigning to a place that holds a value replaces it in three steps: the new value is produced — a [custom copy](https://rux-lang.dev/docs/lang/ownership/copy-and-move#custom-copy) runs here — then the old value is destroyed, then the new one is installed. A field, a tuple element and an element of an array or slice are places like any other, whether they belong to a local or are reached through a `&var` reference: ```rux var seat = Guest { name: "Bob" }; seat = Guest { name: "Cy" }; // Bob leaves here ``` A part of a local holds a value only while the local holds one. A droppable local declared without a value, or moved from, is assigned **whole** before any part of it is written, because a part written into empty storage would never be destroyed: ```text error: cannot write field 'guest' of 'table', which holds no value note: 'table' was declared without a value at … note: 'Table' needs destruction, and a value written into a part of storage that holds none would never be destroyed help: initialize 'table' whole, as in 'table = Table { ... }' ``` A type with nothing to destroy may still be filled one part at a time; see [Initialization](https://rux-lang.dev/docs/lang/bindings/initialization). ## Drop flags Whether a local still owns its value can depend on the path taken. When a value is moved on only some paths, the compiler keeps a **drop flag** for it, and the flag — not the source text — decides at the end of the scope whether the value is destroyed: ```rux func Visit(away: bool) { let guest = Guest { name: "Dee" }; if away { let taken <- guest; // destroyed here, as 'taken' return; } } // destroyed here only when not moved ``` Either way `Dee leaves` is printed once. A local's flag covers the whole value, which is why a part cannot be [moved out](https://rux-lang.dev/docs/lang/ownership/copy-and-move#partial-moves) on its own. ## Copies and destructors A copy is a second value with its own end, so a copyable type with a destructor runs it once per copy. For a type that releases a resource — frees memory, closes a file — that means releasing it twice. Such a type prohibits copying with a bodyless `func =(self: &var T, other: &T);`, or implements a copy that duplicates the resource; see [Copy and move](https://rux-lang.dev/docs/lang/ownership/copy-and-move#prohibiting-copies). ## No unwinding A [panic](https://rux-lang.dev/docs/lang/errors/panics) stops the program where it happens. Nothing is unwound: no destructor runs and no [deferred statement](https://rux-lang.dev/docs/lang/ownership/defer) runs, in the panicking function or in any caller. The same holds for ending the process. Cleanup that must survive a failure belongs on an error path — `fail` and `?` do run destructors. ## See also - [Defer](https://rux-lang.dev/docs/lang/ownership/defer) — cleanup tied to a scope, and how it is ordered against destructors - [Copy and move](https://rux-lang.dev/docs/lang/ownership/copy-and-move) — prohibiting copies of a type that owns a resource - [Extensions](https://rux-lang.dev/docs/lang/structs/extensions) — the `extend` block a destructor lives in - [Panics](https://rux-lang.dev/docs/lang/errors/panics) — failures that end the program without cleanup - Learn: [Destructor](https://rux-lang.dev/docs/learn/destructor) # Defer A `defer` statement registers a statement now and runs it when the enclosing scope ends, by whichever way it ends. Cleanup written once, on the line after the work it undoes, then covers every exit — including ones added later. ## Syntax ```text defer statement ``` The deferred part is exactly one statement: an expression statement such as a call, an assignment, or a statement with its own body such as `if`. A bare block is not a statement, so `defer { … }` does not parse: ```text error: expected an expression before '{' ``` To defer several steps, write several defers — remembering that they run in reverse — put the steps in a function and defer the call, or defer an `if` whose body holds them. ```rux struct Valve { name: char8[..]; } extend Valve { func Open(self: &Valve) { PrintLine("open {}", self.name); } func Close(self: &Valve) { PrintLine("close {}", self.name); } } func Fill(litres: int32) -> bool { let supply = Valve { name: "supply" }; supply.Open(); defer supply.Close(); let drain = Valve { name: "drain" }; drain.Open(); defer drain.Close(); if litres > 100 { return false; } PrintLine("filling {} litres", litres); return true; } ``` Both exits close both valves, the drain first. ## Semantics **Registration happens at run time.** A `defer` counts only once execution reaches it. A `return` before the `defer` line leaves without running it, and a `defer` inside a branch that is not taken never registers. **It belongs to its scope.** A deferred statement runs when the block it is written in ends: the function body, the body of an `if`, or one pass of a loop body — so a `defer` in a loop runs once per pass, not once after the loop. The scope may end by reaching its closing brace, by `return`, by `break` or `continue`, or by `fail` and `?` propagation; a `break` or `continue` runs the defers of the pass and of every inner scope it leaves. **Last registered, first run.** Several defers in one scope run in reverse registration order, and the defers of nested scopes run innermost first. **It is evaluated when it runs.** A deferred statement reads its variables at the end of the scope, not at the `defer` line, so it sees every change made in between. **Each function has its own.** A function's defers run when that function's scopes end; calling a function never runs, or inherits, the caller's defers. Each instantiation of a generic function has its own as well. ## Return and defer `return expr;` evaluates `expr` exactly once and keeps the result — performing the copy or move into the return value — **before** any deferred statement runs. Whatever the defers change afterwards, the caller receives the kept value: ```rux func Countdown() -> int32 { var remaining: int32 = 3; defer PrintLine("deferred code sees {}", remaining); defer remaining = 0; return remaining; } ``` `Countdown()` returns `3`, and the deferred `PrintLine` prints `deferred code sees 0`. The same holds for every part of an aggregate return value. A `return` with no value runs the same defers without capturing anything. That ordering makes "hand out the current value, then advance" a two-line method: ```rux struct Dispenser { next: int32; } extend Dispenser { func Take(self: &var Dispenser) -> int32 { defer self.next += 1; return self.next; } } ``` ## Defers and destructors When a scope ends, its deferred statements run first, newest first, and then its values are [destroyed](https://rux-lang.dev/docs/lang/ownership/destructors), newest first. Registration and declaration order are not interleaved: ```rux func Party() { let ada = Guest { name: "Ada" }; defer PrintLine("lights off"); let bob = Guest { name: "Bob" }; defer PrintLine("music off"); } ``` ```mermaid flowchart LR r["return value<br/>captured"] --> d["defers<br/>newest first"] d --> x["destructors<br/>newest first"] x --> c["control reaches<br/>the caller"] ``` `Party` prints `music off`, `lights off`, `Bob leaves`, `Ada leaves`. On a `return`, the full order is: the return value is captured, the defers run, the locals are destroyed. | | Destructor `~T` | `defer` | | ---------- | -------------------------- | ------------------------------ | | Belongs to | a type — every value of it | one piece of work in one scope | | Written | once, in `extend T` | where the work starts | | Runs | when a value's life ends | when the enclosing scope ends | A destructor cleans up after a value. `defer` is for cleanup that belongs to a piece of work rather than to any one value's life. ## Panics A [panic](https://rux-lang.dev/docs/lang/errors/panics) does not unwind, so no deferred statement runs — not in the panicking function and not in its callers. ## Leaving from a defer A deferred statement runs while its scope is already being left, so it cannot leave it another way. `return`, `fail` and `?` inside a `defer` are refused, and so are a `break` or `continue` that would leave it; one that leaves a loop written inside the deferred statement is fine. Handle a failure inside the `defer` with `catch` instead of `?`: ```text error: 'return' cannot leave a deferred statement error: '?' cannot leave a deferred statement error: 'break' cannot leave a deferred statement ``` ## See also - [Destructors](https://rux-lang.dev/docs/lang/ownership/destructors) — cleanup that belongs to a value - [Return](https://rux-lang.dev/docs/lang/statements/return) — leaving a function with a value - [Propagation](https://rux-lang.dev/docs/lang/errors/propagation) — `?` and `fail`, which run defers on the way out - Learn: [Defer](https://rux-lang.dev/docs/learn/defer), [Defer return](https://rux-lang.dev/docs/learn/defer-return) # Interfaces An **interface** names a set of functions that a type must provide. It has no fields and no code of its own: it lists function headers, and each type that **implements** it supplies the bodies in an `extend` block. Once a type implements an interface, its values can be held, passed and stored as [interface values](https://rux-lang.dev/docs/lang/interfaces/interface-values) with dynamic dispatch, and generic code can require the interface as a [bound](https://rux-lang.dev/docs/lang/generics/bounds). ## Declaring an interface ```text interface Name { func Requirement(parameters) -> Result; func Requirement(self: &Self, parameters) -> Result; func Requirement(self: &var Self, parameters) -> Result; } ``` ```rux interface Shape { func Area() -> float64; func Name() -> char8[..]; } ``` Each **requirement** is a function header ending in `;`. An interface may declare any number of requirements, including none, and is private to its module unless declared `pub interface`. A requirement says how it reaches the implementing value: | Requirement written | The implementation receives | Callable through | | ---------------------------------------- | ----------------------------- | --------------------- | | `func Area() -> float64;` (no receiver) | `self: &T` — it reads | `&I`, `&var I`, `I` | | `func Peek(self: &Self) -> int32;` | `self: &T` — it reads | `&I`, `&var I`, `I` | | `func Turn(self: &var Self, by: int32);` | `self: &var T` — it may write | `&var I`, a `var` `I` | A receiver taken by value is refused, because an interface reaches the implementing value through a reference: ```text error: receiver of requirement 'Consume' in interface 'Sink' must be '&Self' or '&var Self' note: a requirement reaches the implementing value through the data half of an interface view help: write 'self: &var Self' if 'Consume' writes through its receiver, or 'self: &Self' if it only reads it ``` ### Self Inside an interface, `Self` names the type that implements it. It is how an interface says that an operand or a result has the implementer's own type — `Core::Equatable` declares `func Equals(other: &Self) -> bool;`, so a `Fraction` is compared only with another `Fraction`. `Self` exists only inside an interface; anywhere else it is `type 'Self' is not defined in this scope`. ### No type parameters An interface takes no type parameters. `interface Box<T> { … }` does not parse: ```text error: expected '{' to start the interface body before '<' ``` A requirement that would need one is written with `Self`, or the generic part moves to the functions that use the interface, as [bounds](https://rux-lang.dev/docs/lang/generics/bounds). This is also why `Core::Iterator` lists no requirements: an iterator's item type differs per implementation, and an interface has no way to name it. ### No bodies A requirement has no body and an interface supplies no default implementations: every implementing type writes every requirement. A requirement written with a body, such as `func Area() -> float64 { return 1.0; }`, is refused: ```text error: requirement 'Area' of interface 'Shape' cannot have a body help: end the requirement with ';', and write the body in each 'extend Type : Shape' ``` ## Implementing an interface ```text extend Type : Interface { methods } extend Interface for Type { methods } ``` The two spellings are equivalent. Inside the block, every requirement appears as an ordinary [method](https://rux-lang.dev/docs/lang/structs/methods), with the receiver of the concrete type in front of the requirement's own parameters: ```rux struct Circle { radius: float64; } extend Circle : Shape { func Area(self: &Circle) -> float64 { return 3.14 * self.radius * self.radius; } func Name(self: &Circle) -> char8[..] { return "circle"; } } struct Square { side: float64; } extend Shape for Square { func Area(self: &Square) -> float64 { return self.side * self.side; } func Name(self: &Square) -> char8[..] { return "square"; } } ``` The rules: - **Every requirement must be present.** A missing one is reported on the `extend` line: `implementation of interface 'Shape' for type 'Circle' is missing method 'Name'`. - **The parameters and the result must match the requirement exactly.** Only the receiver is added. A method `func Area(self: &Circle) -> int32` for the requirement `func Area() -> float64;` fails with `method 'Area' does not match the requirement of interface 'Shape'`, and notes the two headers side by side. - **The receiver must not write more than the requirement allows.** An implementation of a reading requirement that takes `self: &var T` fails with `method 'Adjust' of 'Dial' writes through its receiver, but requirement 'Adjust' of interface 'Gauge' only reads it`. The opposite is allowed: an implementation of a `&var Self` requirement may take `self: &T` if it does not need to write. - **The receiver is a reference.** `self: T` by value is refused in a block that implements an interface. - **One interface per block.** `extend Circle : Shape, Named` does not parse; a type that implements several interfaces has one `extend` block for each. - **The block may add methods** that the interface does not require. They belong to the type, not to the interface. Methods that implement an interface are ordinary methods of the type, and are called on it like any other: `wheel.Area()`. ### Which types can implement Any type with a declaring package can implement an interface: a structure, an enum, a variant, a primitive such as `int32`, a slice type such as `char8[..]`, and a generic type through `extend Box<T> : Shape` (see [Generic types](https://rux-lang.dev/docs/lang/generics/types#implementing-interfaces)). A native form — an optional, a sum, a fallible or the unit type — has no declaring package to own the implementation: ```text error: cannot extend native type 'int32?' note: a sum, optional, fallible, or unit type has no declaring package to own methods or interface implementations help: write a generic function that takes the native type as a parameter ``` An interface from another package is imported before it is implemented: `import Core::Equatable;`, then `extend Fraction : Equatable { … }`. ### Declared, not inferred Implementing an interface is a declaration. A plain `extend Circle { … }` that happens to contain the right methods does not make `Circle` a `Shape` value: `let shape: Shape = wheel;` then fails with `cannot assign 'Circle' to 'Shape'`. Generic [bounds](https://rux-lang.dev/docs/lang/generics/bounds) are the exception — they are satisfied by any type that has the required methods. ## Using an interface | Written | What it is | Page | | --------------------------------- | -------------------------------------- | ------------------------------------------------------------------------------ | | `let shape: Shape = wheel;` | an interface value holding a copy | [Interface values](https://rux-lang.dev/docs/lang/interfaces/interface-values) | | `func Show(shape: &Shape)` | a borrow of any implementing value | [Interface values](https://rux-lang.dev/docs/lang/interfaces/interface-values) | | `func Best<T: Shape>(a: T, b: T)` | a generic accepting implementing types | [Bounds](https://rux-lang.dev/docs/lang/generics/bounds) | The standard packages define a handful of interfaces the language and libraries build on — equality, ordering, hashing, text output and iteration; see [Core interfaces](https://rux-lang.dev/docs/lang/interfaces/core-interfaces). Operators, indexing and `for` loops are not interfaces: a type provides them by declaring [operator functions](https://rux-lang.dev/docs/lang/interfaces/operators), [indexers](https://rux-lang.dev/docs/lang/interfaces/indexers) and the [iteration methods](https://rux-lang.dev/docs/lang/interfaces/iteration). ## See also - [Interface values](https://rux-lang.dev/docs/lang/interfaces/interface-values) — holding and borrowing values through an interface - [Core interfaces](https://rux-lang.dev/docs/lang/interfaces/core-interfaces) — `Equatable`, `Comparable`, `Hashable`, `Display` and the rest - [Bounds](https://rux-lang.dev/docs/lang/generics/bounds) — interfaces as requirements on type parameters - [Extensions](https://rux-lang.dev/docs/lang/structs/extensions) — the `extend` block - Learn: [Interface](https://rux-lang.dev/docs/learn/interface), [Interface parameter](https://rux-lang.dev/docs/learn/interface-parameter) # Interface Values An interface is a type in its own right. A value of an interface type holds a value of **any** type that implements the interface, together with a note of which type that is, and a call through it runs that type's method. Choosing the method while the program runs, by the value inside, is **dynamic dispatch**. ## Forms | Written | What it is | Changes reach the original? | | --------------------------- | -------------------------------------------- | --------------------------- | | `let shape: Shape = wheel;` | an interface value: a copy of `wheel`, owned | no | | `let shape: Shape <- key;` | an interface value: `key` moved in | — `key` is gone | | `shape: &Shape` | a read-only borrow of an implementing value | it cannot change anything | | `shape: &var Shape` | a writable borrow of an implementing value | yes | | `shapes: Shape[2]` | an array of interface values | no | | `args: Shape...` | a variadic parameter of interface values | no | In each case the conversion from the concrete type happens where the value is bound, assigned or passed. No `&`, cast or call is written. ## Holding a value The annotation is what turns a concrete value into an interface value. Without it, `var shape = wheel;` is simply another `Circle`. ```rux var shape: Shape = wheel; PrintLine("{} {}", shape.Name(), shape.Area()); shape = block; // a Square now: the same calls run Square's code PrintLine("{} {}", shape.Name(), shape.Area()); ``` ```mermaid flowchart LR invoke["`shape.Area()`"] --> note{"Which type is<br/>inside `shape` now?"} note -- "a `Circle`" --> c["`Circle`'s `Area`"] note -- "a `Square`" --> s["`Square`'s `Area`"] ``` An interface value **holds a copy**, made by the [copy rules](https://rux-lang.dev/docs/lang/ownership/copy-and-move) of the concrete type, or the value itself when it is moved in with `<-`. Changing the original afterwards leaves the interface value alone, and a writing requirement called on a `var` interface value changes the copy inside, not the original. An interface value owns what it holds. The held value is [destroyed](https://rux-lang.dev/docs/lang/ownership/destructors) exactly once, when the scope the interface value was made in ends, as a local of that scope would be — a value moved in with `<-` included, and the moved-from variable is not destroyed again. A value stored in a variable's interface value, by its initializer or a later assignment to the variable or to a field of it, belongs to the variable instead: it lives as long as the variable, even when a loop body or a branch stored it, and storing another value of the same type in the same place destroys the old one at the assignment: ```rux var shape: Named = Tracked { id: 1 }; shape = Tracked { id: 2 }; // Tracked 1 is destroyed here var i = 3; while i <= 5 { shape = Tracked { id: i }; // each assignment destroys the value before it i += 1; } // shape holds Tracked 5, destroyed when shape's scope ends ``` A value of another type that the place held before stays alive until the variable's scope ends, since a copy of the interface value may still point at it. An element of an array of interface values has no place of its own, so storing one made in a block inside the array's own, such as a loop body, is refused: ```text error: an interface value made in this block cannot be stored in an element of 'items', which outlives the block ``` The held value lives in the storage of the function that made the interface value, so a function cannot make one at its `return` from a concrete value. Return the concrete type, and let the caller make the interface value: ```text error: cannot return 'Tracked' as interface value 'Named' help: return 'Tracked' itself, and let the caller make the interface value ``` The same holds for a local that holds an interface value the function made, whether by its initializer, by an assignment or by copying another such local; an interface value the function was given is returned as it is, through a local too: ```text error: cannot return interface value 'value', which holds a value made in 'Make' note: 'value' points at storage 'Make' gives up when it returns help: return the concrete type, and let the caller make the interface value ``` Nor can it be stored where it outlives the call — through `self`, a pointer or a reference, or in a module variable — and an optional interface value counts the same: ```text error: cannot store an interface value made in 'Keep' where it outlives the call note: it points at storage 'Keep' gives up when it returns help: store the concrete value, and make the interface value where it is used ``` ## Many types in one array An array has one element type, so values of different types share one only as interface values. The annotation gives every element the interface type: ```rux let shapes: Shape[2] = [wheel, block]; var total = 0.0; for each in shapes { total += each.Area(); } ``` Without it, the first element decides the element type, and the second is refused: `array element 2 has type 'Square', but element 1 established element type 'Circle'`. ## Borrowing through an interface A parameter of type `&I` or `&var I` borrows the caller's own value, whatever its type, as long as it implements `I`. Nothing is copied, and the borrow follows the usual [reference rules](https://rux-lang.dev/docs/lang/references/overview): ```rux interface Gauge { func Read() -> int32; func Adjust(self: &var Self, amount: int32); } struct Dial { level: int32; } extend Dial : Gauge { func Read(self: &Dial) -> int32 { return self.level; } func Adjust(self: &var Dial, amount: int32) { self.level += amount; } } func Show(gauge: &Gauge) { PrintLine("reads {}", gauge.Read()); } func TurnUp(gauge: &var Gauge, amount: int32) { gauge.Adjust(amount); } func Main() -> int { var dial = Dial { level: 4 }; Show(dial); TurnUp(dial, 5); PrintLine("dial.level is {}", dial.level); // 9 return 0; } ``` A requirement declared with `self: &var Self` writes, so it is callable only through a writable view: ```text error: cannot call 'Adjust' through immutable reference '&Gauge' note: 'Adjust' declares a writable receiver '&var Self' help: declare the reference as '&var Gauge' ``` A writable borrow needs writable storage: passing a `let` binding to a `&var Gauge` parameter fails with `argument 1 to 'TurnUp' cannot borrow immutable 'fixed' as '&var Gauge'`. A writable concrete borrow, `&var Dial`, converts to a read-only `&Gauge` as well. ## Only the interface is visible Through an interface value or borrow, only the interface's requirements can be reached. The value inside might be of any implementing type the next time the line runs, so fields and the type's other methods are out of reach: ```text error: interface type 'Gauge' has no member 'level' ``` ## Interface values and bounds An interface value and a [bound](https://rux-lang.dev/docs/lang/generics/bounds) both use an interface, in different ways: | | Interface value: `shape: Shape` | Bound: `<T: Shape>` | | ------------------- | -------------------------------------------- | ----------------------------------- | | Which type | any implementing type, decided while running | one concrete type per instantiation | | A method call | looked up through the value at run time | direct, as if written for that type | | What comes back | the interface; the concrete type is hidden | the same `T` that went in | | Mixed types at once | yes — one array, one parameter list | no — every `T` is the same type | | Conformance | declared with `extend T : Shape` | any type with the required methods | ## See also - [Interfaces](https://rux-lang.dev/docs/lang/interfaces/overview) — declaring and implementing an interface - [References](https://rux-lang.dev/docs/lang/references/overview) — the borrow rules `&I` and `&var I` follow - [Bounds](https://rux-lang.dev/docs/lang/generics/bounds) — the statically dispatched alternative - Learn: [Interface value](https://rux-lang.dev/docs/learn/interface-value), [Interface parameter](https://rux-lang.dev/docs/learn/interface-parameter) # Core Interfaces A few interfaces are shared by the whole standard library. They are ordinary interfaces declared in packages — the compiler gives none of them special treatment — and a type opts into each one with an `extend` block like any other. | Interface | Package | Requirement | Used by | | ------------ | ------- | -------------------------------------------------------------------------------- | ----------------------------------- | | `Equatable` | Core | `func Equals(other: &Self) -> bool;` | searching, deduplication, hash keys | | `Comparable` | Core | `func Compare(other: &Self) -> Ordering;` | sorting, binary search, extremes | | `Hashable` | Core | `func Hash() -> uint64;` | hash tables | | `Iterator` | Core | none | names the iterator role | | `Iterable` | Core | none | names the container role | | `Display` | Text | `func WriteDisplay(writer: &var TextWriter, spec: FormatSpec) -> ! FormatError;` | `{}` placeholders, `PrintLine` | | `Debug` | Text | `func WriteDebug(writer: &var TextWriter, spec: FormatSpec) -> ! FormatError;` | inspection output | Each is imported by name — `import Core::{ Comparable, Equatable, Ordering };`, `import Text::{ Display, FormatError, FormatSpec, TextWriter };` — and the package is listed under `[Dependencies]` in `Rux.toml`. ## Equatable ```rux pub interface Equatable { func Equals(other: &Self) -> bool; } ``` `Equals` says whether two values of one type stand for the same thing. Because the operand is `&Self`, a value is only ever compared with another of its own type. An implementation must be an **equivalence**: | Law | Meaning | | ---------- | --------------------------------------------------- | | Reflexive | `a.Equals(a)` is `true` | | Symmetric | `a.Equals(b)` is `b.Equals(a)` | | Transitive | `a.Equals(b)` and `b.Equals(c)` imply `a.Equals(c)` | A type that cannot promise all three — one with a value that does not equal itself, as a floating-point NaN does not — should not implement `Equatable`. Generic code that relies on it is entitled to assume the laws hold. `Equals` is a method, not an operator: implementing `Equatable` leaves `==` as it was, which for a structure is [structural equality](https://rux-lang.dev/docs/lang/interfaces/operators#structural-equality). To give `==` the same meaning, declare `==` as well. ## Comparable and Ordering ```rux pub interface Comparable { func Compare(other: &Self) -> Ordering; } ``` `Compare` answers which of two values comes first with a three-way `Ordering`, so one call settles "before, same or after". An implementation must be a **total order**: for any pair exactly one of `Less`, `Equal` and `Greater` holds; swapping the operands swaps `Less` and `Greater`; and the relation is transitive. A type implementing both `Comparable` and `Equatable` keeps them in step: `Compare` reports `Equal` exactly when `Equals` reports `true`. Implementing `Comparable` adds no `<`; declare the [operators](https://rux-lang.dev/docs/lang/interfaces/operators) for that. `Ordering` is an enum stored in an `int8`, so its discriminant is the sign of the comparison: ```rux pub enum Ordering: int8 { Less = -1, Equal = 0, Greater = 1 } ``` | Member | Result | | ------------------------------------------- | ------------------------------------------ | | `IsLess(self: &Ordering) -> bool` | `true` for `Less` | | `IsEqual(self: &Ordering) -> bool` | `true` for `Equal` | | `IsGreater(self: &Ordering) -> bool` | `true` for `Greater` | | `IsLessOrEqual(self: &Ordering) -> bool` | `true` for `Less` or `Equal` | | `IsGreaterOrEqual(self: &Ordering) -> bool` | `true` for `Greater` or `Equal` | | `Reverse(self: Ordering) -> Ordering` | `Less` and `Greater` swapped, `Equal` kept | ## Hashable ```rux pub interface Hashable { func Hash() -> uint64; } ``` `Hash` returns a 64-bit summary of the value. Equal values must hash equally — a table is wrong otherwise — while unequal values may collide. A type that implements `Hashable` implements `Equatable` consistently with it, and the same value always gives the same hash within a run. ## Iterator and Iterable ```rux pub interface Iterator {} pub interface Iterable {} ``` Both are empty. A `for` loop is driven by **shape** — a `Next` method on an iterator, an `Iterate` method on a container — and the item type differs per iterator, which an interface cannot name. What these interfaces add is the name: `extend Countdown : Iterator` records that a type means to be an iterator, and a bound written `<T: Iterator>` documents what a generic expects. Neither is required to iterate, and a bound on either grants no operations. See [Iteration](https://rux-lang.dev/docs/lang/interfaces/iteration) for the protocol itself. ## Display and Debug ```rux pub interface Display { func WriteDisplay(writer: &var TextWriter, spec: FormatSpec) -> ! FormatError; } pub interface Debug { func WriteDebug(writer: &var TextWriter, spec: FormatSpec) -> ! FormatError; } ``` `Display` is the text a value has for a reader: a number is its digits, a string its characters, nothing quoted. `Debug` is the text a value has for whoever is inspecting a program: it may quote, escape and name parts. Both write into a destination rather than returning a string, so rendering allocates nothing. | Parameter | Meaning | | ------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `writer: &var TextWriter` | the destination — the console, a string builder, a buffer; `TextWriter` is itself an interface with one requirement, `func Write(self: &var Self, bytes: char8[..]) -> ! FormatError;` | | `spec: FormatSpec` | what the placeholder asked for — width, alignment, precision; `{}` passes `FormatSpec::Plain()` | | `-> ! FormatError` | a write can fail; an implementation stops at the first failed write and reports it | ### How PrintLine uses Display `PrintLine` and `Print` from the Io package take their arguments as a [variadic parameter](https://rux-lang.dev/docs/lang/functions/parameters) of `Display` interface values: ```text pub func PrintLine(#Format() format: char8[..], args: Display...) -> IoError? ``` Each argument is converted to a `Display` value at the call, and each `{}` placeholder calls its `WriteDisplay`. The primitive integers, characters and booleans, the floats from `float8` to `float64`, and the string types implement `Display` in the standard packages, which is why they print. `float80` and wider do not, because finding their digits allocates — see [Printing the wide widths](https://rux-lang.dev/docs/lang/types/floating-point#printing-the-wide-widths). A type of your own prints once it implements `Display` too. An argument that does not fits neither this overload nor the one-value overloads `PrintLine` also has for the string types and most primitives, so the call is refused as a whole: ```text error: no matching overload for 'PrintLine' with argument types (char8[..], Money) ``` No placeholder selects `Debug`. Debug text is written explicitly, with `Text::WriteDebugValue(writer, value, spec)` or through a bound such as `<T: Debug>`; `Text::WriteValue` is the matching entry point for `Display`. ## Example ```rux import Core::{ Comparable, Equatable, Hashable, Ordering }; import Io::PrintLine; import Text::{ Display, FormatError, FormatSpec, TextWriter, WriteBytes, WriteValue }; struct Version { major: int32; minor: int32; } extend Version : Equatable { func Equals(self: &Version, other: &Version) -> bool { return self.major == other.major && self.minor == other.minor; } } extend Version : Comparable { func Compare(self: &Version, other: &Version) -> Ordering { if self.major != other.major { return self.major < other.major ? Ordering::Less : Ordering::Greater; } if self.minor != other.minor { return self.minor < other.minor ? Ordering::Less : Ordering::Greater; } return Ordering::Equal; } } extend Version : Hashable { func Hash(self: &Version) -> uint64 { return (self.major as uint64) << 32 | (self.minor as uint64); } } extend Version : Display { func WriteDisplay(self: &Version, writer: &var TextWriter, spec: FormatSpec) -> ! FormatError { WriteBytes(writer, "v")?; WriteValue(writer, self.major, spec)?; WriteBytes(writer, ".")?; return WriteValue(writer, self.minor, spec); } } func Main() -> int { let old = Version { major: 1, minor: 9 }; let fresh = Version { major: 1, minor: 10 }; PrintLine("{} equals {}: {}", old, fresh, old.Equals(fresh)); PrintLine("older: {}", old.Compare(fresh).IsLess()); PrintLine("newer: {}", old.Compare(fresh).Reverse().IsLess()); return 0; } ``` ## See also - [Interfaces](https://rux-lang.dev/docs/lang/interfaces/overview) — implementing an interface - [Operators](https://rux-lang.dev/docs/lang/interfaces/operators) — `==` and `<`, which these interfaces do not provide - [Iteration](https://rux-lang.dev/docs/lang/interfaces/iteration) — the protocol `Iterator` and `Iterable` name - Learn: [Equatable](https://rux-lang.dev/docs/learn/equatable), [Comparable](https://rux-lang.dev/docs/learn/comparable), [Display](https://rux-lang.dev/docs/learn/display) # Operators A type gives a binary operator a meaning by declaring a function whose name **is** the operator, in an `extend` block. `a + b` with an `a` of that type is then a call to that function. Operators are not interfaces: there is no `Addable` to implement, only the operator function itself. ## Declaring an operator ```text extend T { func op(self: &T, right: R) -> Result { … } } ``` ```rux struct Money { cents: int64; } extend Money { func +(self: &Money, other: Money) -> Money { return Money { cents: self.cents + other.cents }; } func *(self: &Money, count: int64) -> Money { return Money { cents: self.cents * count }; } func ==(self: &Money, other: Money) -> bool { return self.cents == other.cents; } func <(self: &Money, other: Money) -> bool { return self.cents < other.cents; } } ``` - `self` is the **left** operand, borrowed. The one other parameter is the right operand, of any type: `Money * int64` above, with no `Money * Money` and no `int64 * Money`. - The result is any type. Comparisons conventionally return `bool`. - Overloads of one operator are separated by the right operand's type, like any [overload](https://rux-lang.dev/docs/lang/functions/overloading). - A right operand taken **by value** accepts anything, including a value built on the spot. One taken by reference, `other: &Money`, needs a named value: `rent == Money { cents: 5 }` then fails with `cannot pass 'Money' to parameter of type '&Money'`. | You write | The compiler calls | `self` | Right operand | | -------------- | ------------------ | ------ | ------------- | | `rent + food` | `+` | `rent` | `food` | | `rent * 3` | `*` | `rent` | `3` | | `rent == food` | `==` | `rent` | `food` | | `food < rent` | `<` | `food` | `rent` | | `sum += food` | `+`, then assigns | `sum` | `food` | A compound assignment `a op= b` uses the declared `op` and assigns its result to `a`, so declaring `+` makes `+=` work as well. An operator that is not declared does not exist for the type, and the error names both operands: ```text error: operator '/' cannot combine left operand 'Money' with right operand 'int' ``` ## Which operators | Overloadable | Operators | | ------------------- | ----------------------------------------------------------------------------------- | | Arithmetic | `+` `-` `*` `/` `%` | | Bitwise | `&` `|` `^` | | Shift | `<<` `>>` `>>>` | | Comparison | `==` `!=` `<` `<=` `>` `>=` | | Logical | `&&` `||` | | Compound assignment | `+=` `-=` … — through the binary operator | | Indexing | `[]` and `[]=` — see [Indexers](https://rux-lang.dev/docs/lang/interfaces/indexers) | An overloaded `&&` or `||` is an ordinary call: both operands are evaluated, with no short-circuit. | Not overloadable | Why | | ----------------------------------------- | ---------------------------------------------------------------------------------------------- | | unary `-`, `!`, `~`, `*`, `@`, `++`, `--` | built in for primitives and pointers only | | `=` and `<-` | copy and move are [special operations](https://rux-lang.dev/docs/lang/ownership/copy-and-move) | | `??` | `operator '??' is built in and cannot be declared or overloaded` | | `as`, `is`, `..`, `?`, `.` | part of the language, not of any type | A unary operator on a structure is refused even if a function named after it is declared: `-money` fails with `operator '-' requires a numeric operand, but found 'Money'`. ## Derived comparisons A structure declares at most two comparison operators. From `==` the compiler derives `!=`, and from `<` together with `==` it derives the other three: | You write | The compiler uses | | --------- | ----------------- | | `a != b` | `!(a == b)` | | `a > b` | `b < a` | | `a <= b` | `a < b || a == b` | | `a >= b` | `b < a || a == b` | ```mermaid flowchart LR eq["`==` (declared)"] --> ne["`!=`"] lt["`<` (declared)"] --> gt["`>`"] lt --> le["`<=`"] eq --> le lt --> ge["`>=`"] eq --> ge ``` - Each operand is evaluated **once**, even though the derivation names it twice. - `<=` is `a < b || a == b`, not `!(b < a)`. For a pair that is neither ordered nor equal, only the first is right, so a partial order stays correct. - A declared operator wins over its derivation. Declaring `!=`, `>`, `<=` or `>=` by hand is allowed, and is the one way the six can come to disagree. - Derivation works inside generic code too, after the type parameter is substituted. When neither the operator nor what it derives from is declared, the error says so — here for a `Money` that declares `==` but not `<`: ```text error: operator '>' is not defined for 'Money' note: a struct is compared through the operators it declares, never by its representation help: declare '>' on 'Money', or the '<' it is derived from ``` ## Structural equality Without any declaration, `==` and `!=` already work on structures, tuples, fixed arrays and variants, and on any nesting of them. Two values are equal when they are equal part by part: | Kind | Equal when | | --------- | --------------------------------------------------- | | Structure | every field is equal, compared in declaration order | | Tuple | every element is equal | | Array | every element is equal | | Variant | the case is the same, and so is its payload | Each part is compared with its own `==` — a declared one where its type declares it, structural otherwise — so a structure holding a `Money` uses Money's `==` for that field. Floating-point fields compare by value: a NaN field makes two values unequal, and `0.0` equals `-0.0`. Padding bytes play no part. A declared `==` on a structure replaces its structural equality. Every part must have an `==` of its own; a slice has none, so a structure with a `char8[..]` field has no structural equality: ```text error: structural equality for 'Named' is unavailable because element type 'char8[..]' has no '==' operator help: declare '==' on 'char8[..]' or compare the supported elements explicitly ``` There is no structural **ordering**. `<` and the rest are defined only by declaration: `operator '<' is not defined for 'Point'` for a structure, `operator '<' is not defined for variant 'Shape'` for a variant, and `operator '<' is not defined for tuple '(int, int)'` for a tuple. ## See also - [Comparison](https://rux-lang.dev/docs/lang/expressions/comparison) — the built-in comparison operators - [Indexers](https://rux-lang.dev/docs/lang/interfaces/indexers) — `[]` and `[]=` - [Core interfaces](https://rux-lang.dev/docs/lang/interfaces/core-interfaces) — `Equatable` and `Comparable`, which are methods rather than operators - Learn: [Operator overload](https://rux-lang.dev/docs/learn/operator-overload), [Derived operator](https://rux-lang.dev/docs/learn/derived-operator), [Structural equality](https://rux-lang.dev/docs/learn/structural-equality) # Indexers Arrays, slices and pointers are indexed by the language. Any other type indexes itself by declaring the **indexing operators** in an `extend` block, the same way it declares `==` or `+`: `[]` reads one element and `[]=` writes one. ## Syntax ```text extend T { func [](self: &T, index: I) -> E { … } func []=(self: &var T, index: I, value: E) { … } } ``` `[]` and `[]=` are written with no space inside the brackets and none before the `=`. `v[i]` on such a type is a call to `[]`, and `v[i] = x` is a call to `[]=`. ```rux struct Vect { data: int32[10]; } extend Vect { func [](self: &Vect, index: uint) -> int32 { return self.data[index]; } func []=(self: &var Vect, index: uint, value: int32) { self.data[index] = value; } func [](self: &Vect, span: int..int) -> int32[..] { return self.data[span]; } } func Main() -> int { var v = Vect { data: [0; 10] }; v[2] = 7; v[3] = v[2] + 1; let middle = v[2..5]; PrintLine("{} {} {}", v[2], v[3], middle.length); return 0; } ``` ## Shape Each operator has exactly one shape, checked where it is declared: | Operator | Receiver | Other parameters | Result | | -------- | -------------- | ------------------------- | ----------- | | `[]` | `self: &T` | the index | the element | | `[]=` | `self: &var T` | the index, then the value | none | Neither takes type parameters, a variadic or a default value. Anything else is refused with the expected shape: ```text error: the '[]' operator on 'Bad' must have signature 'func [](self: &Bad, index: I) -> E' note: an index reads one element and evaluates to it help: the index and element types are the author's to choose; overloads are separated by the index type ``` ## Index types Nothing fixes the index type: an integer, a range, an enum, a tuple, a structure. Overloads of either operator are separated by their index type, so one type may answer several index forms — `v[i]` and `v[a..b]` above. An index that no overload accepts is an error: `no '[]' on 'Vect' accepts an index of type 'char8[..]'`. An unsuffixed literal index takes the parameter's type, as in any call. A generic type substitutes its type arguments into the operators, so `func [](self: &Box<T>, index: uint) -> T` returns the element type of each instantiation. ## Reading and writing are separate The two operators are independent. A type may declare only `[]` and be read but not written, only `[]=` and be written but not read, or both: | Declared on `Grid` | `grid[i]` | `grid[i] = x` | | ------------------ | ------------------------------- | --------------------------------------------------- | | `[]` only | reads | `cannot assign through the '[]' operator on 'Grid'` | | `[]=` only | `type 'Grid' cannot be indexed` | writes | | both | reads | writes | Declaring both does not make the pair act as one place. `[]` returns a **value**, not a place — a reference cannot be returned — so: | Rejected, for a `Grid` of `Cell`s | Error | Write instead | | --------------------------------- | --------------------------------------------------------------------------------- | -------------------------- | | `grid[i] += x`, `grid[i]++` | `operator '+=' cannot read and write through the '[]' operator on 'Grid' at once` | `grid[i] = grid[i] + x` | | `grid[i].mark = x` | `cannot assign through the '[]' operator on 'Grid'` | read, change, write back | | `let r: &Cell = grid[i];` | `cannot assign 'Cell' to '&Cell'` | a copy: `let c = grid[i];` | Combining the read and the write would evaluate the receiver and the index twice, so the language leaves the two steps to be written out. ## Borrowing Either call borrows the receiver whole for its duration, exactly as a method call does. `[]=` needs a receiver it may write, so a `let` binding or a `&T` access is refused — `cannot modify immutable variable 'fixed'` — while `[]` works on either. The value written by `v[i] = x` reaches `[]=` as an ordinary by-value argument, so it is copied, or with `v[i] <- x` moved. A read never counts as a partial move: its result is a fresh value. In `v[keys[j]] = x`, only the outer subscript writes; `keys[j]` is a read. ## Built-in indexing stays built in Arrays, slices and pointers keep their own indexing, which no `extend` block can displace. Built-in indexing of an array or slice is bounds-checked on every target and in every build profile; see [Arrays](https://rux-lang.dev/docs/lang/arrays/overview). A declared indexer checks whatever its body checks. ## See also - [Operators](https://rux-lang.dev/docs/lang/interfaces/operators) — the other operators a type can declare - [Arrays](https://rux-lang.dev/docs/lang/arrays/overview) and [Slices](https://rux-lang.dev/docs/lang/slices/overview) — built-in indexing - [Ranges](https://rux-lang.dev/docs/lang/ranges/overview) — range types as index types - Learn: [Indexer](https://rux-lang.dev/docs/learn/indexer) # Iteration A [`for` loop](https://rux-lang.dev/docs/lang/statements/loops) walks an array, a slice or a range directly. Any other subject is driven by a convention of two method shapes: an **iterator** declares `Next`, which hands out one item per call, and a **container** declares `Iterate`, which hands out a fresh iterator. ## The protocol ```text extend It { func Next(self: &var It) -> Item? { … } // an iterator } extend Container { func Iterate(self: &Container) -> It { … } // a container } ``` | Subject of `for item in subject` | What the loop does | | -------------------------------- | --------------------------------------------------------- | | an array, a slice, a range | built in | | a type declaring `Iterate` | calls `Iterate` once, then drives the iterator it returns | | a type declaring `Next` | drives the subject itself | | anything else | `cannot iterate over 'T'` | The loop calls `Next` once per pass. A present result runs the body with its payload bound to the loop variable; `none` ends the loop. ```mermaid flowchart LR start["`for item in subject`"] --> it["`subject.Iterate()`<br/>(containers only)"] it --> next["call `Next()`"] next --> q{"an item,<br/>or none?"} q -- "an item" --> body["run the body<br/>with `item` bound"] body --> next q -- "none" --> done["leave the loop"] ``` The same walk written by hand is a `loop` with a [coalescing exit](https://rux-lang.dev/docs/lang/optionals/coalescing): ```rux var countdown = Countdown { remaining: 3 }; loop { let second = countdown.Next() ?? break; PrintLine("{}", second); } ``` ## Iterators ```rux struct Countdown { remaining: int32; } extend Countdown : Iterator { func Next(self: &var Countdown) -> int32? { if self.remaining == 0 { return none; } let current = self.remaining; self.remaining -= 1; return current; } } func Main() -> int { for second in (Countdown { remaining: 5 }) { Print(" {}", second); } PrintLine(" liftoff"); return 0; } ``` `Next` must take a **writable** receiver, since advancing an iterator changes it, and must return a native optional. The item type is whatever the optional carries: ```text error: iterator method 'Next' on 'A' must take a mutable receiver note: advancing an iterator writes it, so 'Next' cannot borrow its receiver read-only help: write the receiver as 'self: &var A' ``` A `Next` returning something else is not an iterator — `cannot iterate over 'B'`, with the note `type 'B' declares 'Next', but not as 'func Next(self: &var B) -> T?' returning a native optional`. A `Next` returning a variant with `Some` and `None` cases is rejected where it is declared, because a loop ends only at the absence of a native optional: ```text error: iterator method 'Next' on 'It' must return a native optional help: return 'Item?' and report the end with 'none' ``` An iterator is consumed as it is read. Once `Next` has reported `none`, it should keep reporting `none`; nothing promises that an iterator can be restarted. A struct literal written directly after `in` must be parenthesised, as above. Without the parentheses its `{` is taken for the start of the loop body, and the parser stops with `expected ';' after expression, but found ':'`. A loop over a named iterator advances the variable itself: after `for second in countdown` stops early with `break`, `countdown` holds the items not yet read, and a later loop or `Next` call continues from there. The variable must therefore be writable: ```text error: cannot advance immutable iterator 'countdown' help: declare 'countdown' with 'var' to make it mutable ``` ## Containers A container is not an iterator itself. It hands one out, so two loops over the same container walk independently, and the container is unchanged afterwards: ```rux struct Span { limit: int32; } extend Span : Iterable { func Iterate(self: &Span) -> Countdown { return Countdown { remaining: self.limit }; } } func Main() -> int { let span = Span { limit: 3 }; for n in span { Print(" {}", n); } for n in span { Print(" {}", n); // starts again from 3 } PrintLine(); return 0; } ``` `Iterate` takes no parameters besides the receiver. It borrows the container read-only — handing out an iterator changes nothing — and the iterator it returns usually borrows from the container in turn, so the container must outlive it and must not be changed while it is in use. `Iterator` and `Iterable`, from Core, are empty [marker interfaces](https://rux-lang.dev/docs/lang/interfaces/core-interfaces#iterator-and-iterable). Writing `: Iterator` or `: Iterable` records the role; the loop goes by the method names and shapes alone and works without them. ## Items An item may itself be an optional, a fallible, a sum or the unit type. Only the **outer** absence that `Next` returns ends the loop; an absent or failed item is an ordinary value the body receives: ```rux struct Readings { index: int32; } extend Readings { // Each item is an int32?, so Next returns int32??. func Next(self: &var Readings) -> int32?? { self.index += 1; if self.index > 3 { return none; } if self.index == 2 { let missing: int32? = none; return missing; } let present: int32? = self.index * 10; return present; } } func Main() -> int { for reading in (Readings { index: 0 }) { PrintLine("{}", reading ?? -1); // 10, -1, 30 } return 0; } ``` No error channel is added to iteration: a fallible item is data, and the loop continues past a failed one. ## Moves inside a loop The loop variable and the locals declared in the body are fresh on every pass and may be moved freely. Moving an outer local inside the body is subject to the rule in [Ownership](https://rux-lang.dev/docs/lang/ownership/overview#moves-on-some-paths): the same pass must refill it, or leave the loop, after the move. ## See also - [Loops](https://rux-lang.dev/docs/lang/statements/loops) — `for`, `while` and `loop` - [Optionals](https://rux-lang.dev/docs/lang/optionals/overview) — the `T?` that `Next` returns - [Core interfaces](https://rux-lang.dev/docs/lang/interfaces/core-interfaces) — `Iterator` and `Iterable` - Learn: [Iterator](https://rux-lang.dev/docs/learn/iterator), [Iterable](https://rux-lang.dev/docs/learn/iterable) # Generics A **generic** declaration takes **type parameters**: names in angle brackets that stand for types the user supplies. A generic function is written once and works for every type it is used with; a generic type is a pattern from which `Pair<int32>`, `Pair<char8[..]>` and so on are stamped out. Functions, methods, structures and variants can be generic. Nothing is decided at run time. The compiler produces a separate **instantiation** for each distinct set of type arguments a program uses, as if each had been written by hand, with its own layout, its own code and its own symbol. ## Generic functions ```text func Name<T, U, …>(parameters) -> Result { … } func Name<T: Bound + Bound, U>(parameters) -> Result { … } ``` ```rux func Larger<T>(first: T, second: T) -> T { if first > second { return first; } return second; } ``` Each type parameter is in scope in the parameter list, the result type and the body. A parameter may carry [bounds](https://rux-lang.dev/docs/lang/generics/bounds), interfaces its type arguments must implement. ## Type arguments A call supplies the type arguments explicitly, after the name, or leaves the compiler to **infer** them from the arguments: ```rux PrintLine("{}", Larger(3, 9)); // T = int, inferred PrintLine("{}", Larger(2.5, 1.5)); // T = float64 PrintLine("{}", Larger<uint8>(200, 7) + 100); // T = uint8: prints 44 ``` An explicit type argument also types the arguments: with `<uint8>`, the literals `200` and `7` become `uint8` values, and so does the result, which is why adding `100` wraps. Without it, unsuffixed literals make `T` an `int`. Inference reads type arguments out of the argument types, wherever the parameter mentions them: | Parameter written | Argument | Infers | | --------------------- | -------------------------------- | ------------------------ | | `value: T` | `7i32` | `T = int32` | | `value: &T`, `&var T` | a local `counter: Counter` | `T = Counter` — borrowed | | `p: *T` | `@counter` | `T = Counter` | | `values: T[..]` | an `int32[3]` array or a slice | `T = int32` | | `pair: Pair<T>` | a `Pair<int64>` | `T = int64` | | `f: func(T) -> U` | a function `func(int32) -> bool` | `T = int32`, `U = bool` | | `outcome: T ! E` | an `int32 ! Fault` | `T = int32`, `E = Fault` | | `value: T?` | an `int32?` | `T = int32` | A type parameter that no argument determines must be written: `Size<int16>()`. A sum of type parameters is not inferred either, since nothing says which member is `T`: `Side(v)` with `func Side<T, U>(value: T | U)` is refused, and `Side<int32, bool>(v)` is the call. Inference does not look at the result type or the destination, so `let f: int32? = Make();` with `func Make<T>() -> T?` is `function 'Make' requires 1 type argument, but 0 were provided`. Inference never relaxes a parameter's other requirements: a `&var T` parameter still needs a writable argument. Two arguments that disagree about one parameter are refused — `Larger(3, 2.5)`: ```text error: argument 1 to 'Larger' has type 'int', but parameter 'first' requires 'T' ``` ## Checking a generic body A generic body is checked in two stages. **At the declaration**, everything that does not depend on what `T` is: names, statements, and every use of `T` that needs a capability. A method call on a `T`, or passing a `T` where an interface is required, needs a [bound](https://rux-lang.dev/docs/lang/generics/bounds) that provides it: ```text error: no matching overload for 'PrintLine' with argument types (char8[..], T) ``` **At each instantiation**, the operators applied to `T`. `first > second` in `Larger` is checked once `T` is known, so `Larger(3, 9)` and `Larger('a', 'z')` compile and `Larger("abc", "abd")` does not. The error points into the generic body, and a note names the call responsible: ```text error: operator '>' is not defined for slice type 'char8[..]' note: a slice is a view, so comparing the views would compare addresses rather than elements note: in 'Larger' instantiated with T = char8[..] by the call at … ``` Without a bound, a body may store a `T`, pass it on, return it, copy or move it, take its size with `sizeof(T)`, and apply operators that every instantiation will have to support. ## Generic functions are not values A function value has one concrete signature, and a generic function has one per instantiation, so a generic function cannot be stored in a [function-typed](https://rux-lang.dev/docs/lang/functions/function-types) variable or passed as a callback: `let f: func(int32) -> int32 = Identity;` fails with `cannot assign 'func(T) -> T' to 'func(int32) -> int32'`. Wrap the instantiation in an ordinary function instead. A generic function may freely **take** a function value whose type mentions its parameters, as `Apply<T>(value: T, f: func(T) -> T)` does. ## Overloading Generic functions overload like any other, by arity and by parameter types. When a generic and a non-generic overload accept a call equally well, the non-generic one wins: ```rux func Describe<T>(value: T) -> char8[..] { return "generic"; } func Describe(value: int32) -> char8[..] { return "int32"; } ``` `Describe(5i32)` is `int32`; `Describe(true)` is `generic`. See [Overloading](https://rux-lang.dev/docs/lang/functions/overloading) for the full ranking. ## Native forms Optionals, sums and fallibles are built into the language and have no declaring package, so `extend` cannot give them methods. Generic functions whose parameters spell the form out take their place, and work for every payload and error type at once: ```rux func ValueOr<T, E>(outcome: T ! E, fallback: T) -> T { return outcome catch { else => fallback }; } func Both<T, U>(first: T?, second: U?) -> (T, U)? { return (first?, second?); } ``` `Core::Succeeded<T, E>(outcome: T ! E) -> bool` and `Core::Failed` are written this way. A sum of type parameters collapses when its members coincide: `T | U` with `T = U = int32` is plain `int32`. A `match` over a `T | U` therefore ends in `else`, which stays valid for every instantiation, where a second typed arm would be unreachable for the collapsed one. A typed arm may also name a concrete type, as in `n: int32 =>`, and each instantiation checks it against its own members. For `T = int32, U = bool` the arm selects the `int32`; an instantiation whose sum has no `int32`, such as `T = int64, U = bool`, is refused with `type 'int32' is not a member or subset of sum 'bool8 | int64'`. ## Kinds of generic declaration | Declaration | Generic? | Page | | ------------------ | -------------------------------------------------------------------------------------------- | ------------------------------------------------------------------ | | function | yes | this page | | structure, variant | yes | [Generic types](https://rux-lang.dev/docs/lang/generics/types) | | method | yes — its own parameters, as well as its type's | [Generic methods](https://rux-lang.dev/docs/lang/generics/methods) | | enum | no — `enum 'Level' cannot declare type parameters` | [Enums](https://rux-lang.dev/docs/lang/enums/overview) | | union, type alias | no | | | interface | no — see [Interfaces](https://rux-lang.dev/docs/lang/interfaces/overview#no-type-parameters) | | ## See also - [Generic types](https://rux-lang.dev/docs/lang/generics/types) — structures and variants with type parameters - [Generic methods](https://rux-lang.dev/docs/lang/generics/methods) — methods of generic types, and methods with their own type parameters - [Bounds](https://rux-lang.dev/docs/lang/generics/bounds) — what a type argument must implement - [Function types](https://rux-lang.dev/docs/lang/functions/function-types) — callbacks in generic signatures - Learn: [Generic](https://rux-lang.dev/docs/learn/generic), [Generics](https://rux-lang.dev/docs/learn/generics), [Generic outcome](https://rux-lang.dev/docs/learn/generic-outcome), [Generic sum](https://rux-lang.dev/docs/learn/generic-sum) # Generic Types A structure or a variant may declare type parameters after its name. The declaration is a pattern, not yet a type: `Pair<int32>` and `Pair<char8[..]>` are two distinct types stamped out of it, each with its own layout, sized from its own type arguments. ## Declaration ```text struct Name<T, U, …> { fields } variant Name<T, …> { cases } struct Name<T: Bound> { fields } ``` ```rux struct Pair<T> { first: T; second: T; } struct Entry<K, V> { key: K; value: V; } variant Reading<T> { Exact(T), Between(T, T), Missing } ``` The parameters are in scope in the fields and case payloads. Enums cannot be generic — `enum 'Level' cannot declare type parameters`, with the help to use a `variant` — and neither can unions, type aliases or interfaces. ## Instantiation A generic type is always named with its type arguments, filled in order: `Pair<int32>`, `Entry<char8[..], int32>`, `Reading<float64>`. They may themselves be instantiations, and nested argument lists may close on one `>>` or `>>>`: `Pair<Pair<int32>>`. | Written | Type arguments come from | | ------------------------------------- | -------------------------------------------------------------------------------------------- | | `let p: Pair<int32> = …;` | the annotation | | `Pair<int32> { first: 3, second: 4 }` | the literal — always written | | `Pair<int32>(5)` | the [constructor](https://rux-lang.dev/docs/lang/structs/constructors) call — always written | | `Reading::Exact(7)` | the payload, unless an annotation gives them | | `Reading::Missing` | the destination: an annotation, a parameter or a return type | | `Reading::Missing<int32>()` | the case itself | ```rux let point = Pair<int32> { first: 3, second: 4 }; let entry = Entry<char8[..], int32> { key: "age", value: 7 }; let temperature = Reading::Between(18.5, 21.0); // Reading<float64> let floor: Reading<int32> = Reading::Exact(7); // the annotation wins: 7 is an int32 let lost: Reading<int32> = Reading::Missing; let other = Reading::Missing<int32>(); ``` A structure literal never infers its type arguments from its fields, and a field declared `T` must then have exactly that type: | Written | Error | | ------------------------------------------ | ----------------------------------------------------------------------------------------------------- | | `Pair { first: 3, second: 4 }` | `struct initializer for 'Pair' requires 1 type argument, but 0 were provided` | | `Entry<int32> { key: 1, value: 2 }` | `struct initializer for 'Entry' requires 2 type arguments, but 1 was provided` | | `Pair(5)` | `constructor for 'Pair' requires 1 type argument, but 0 were provided` | | `let lost = Reading::Missing;` | `variant case 'Reading::Missing' requires 1 type argument, but 0 were provided` | | `Pair<int32> { first: 3, second: "four" }` | `field 'second' in initializer for 'Pair' has type 'char8[..]', but its declaration requires 'int32'` | A [generic function](https://rux-lang.dev/docs/lang/generics/overview) taking a generic type infers its own parameters from the argument, so the caller of `func Swapped<T>(pair: Pair<T>) -> Pair<T>` writes `Swapped(point)`. The function's parameters may fill the type's in any order: `func Take<K, V>(entry: Entry<V, K>) -> K`, given an `Entry<int32, bool>`, infers `K = bool` and `V = int32`. ## Layout Every instantiation is laid out from its own type arguments, so `Pair<int64>` is twice the size of `Pair<int32>`, and a `Box<Wide>` reserves the full width of `Wide` for its field. Two instantiations are unrelated types: a `Pair<int32>` is not a `Pair<int64>`, and neither converts to the other. ## Methods and extensions Methods, constructors, operators, destructors and the copy and move operations of a generic type live in an `extend` block that names the type with **its own** parameter names: ```rux extend Pair<T> { func Pair(both: T) -> Pair<T> { return Pair<T> { first: both, second: both }; } func Swapped(self: &Pair<T>) -> Pair<T> { return Pair<T> { first: self.second, second: self.first }; } } ``` One block serves every instantiation. The parameter names must match the declaration's: `extend Pair { … }` is `struct type 'Pair' requires 1 type argument, but 0 were provided`, and `extend Pair<U>` for a type declared `Pair<T>` is `type 'U' is not defined in this scope`. See [Generic methods](https://rux-lang.dev/docs/lang/generics/methods) for calling them, and for methods with type parameters of their own. An `extend` block may also name one instantiation, `extend Pair<int32> { … }`, to give that instantiation alone extra methods. A method declared there belongs to `Pair<int32>` only; with `func Sum(self: &Pair<int32>) -> int32` in that block, calling `Sum` on a `Pair<int64>` is refused: ```text error: type 'Pair<int64>' has no method 'Sum' note: 'Sum' is declared in 'extend Pair<int32>' help: call it on the instantiation its extension names ``` Extensions of two instantiations, `extend Pair<int32>` and `extend Pair<int64>`, may each declare a method of the same name and parameters, since no receiver can call both. A method of the same signature in `extend Pair<T>` competes with each of them and is refused with `function 'Sum' has the same parameter signature as an earlier overload`. ## Bounds on type parameters A type parameter of a structure may carry [bounds](https://rux-lang.dev/docs/lang/generics/bounds). Every instantiation is checked against them where it is written, and methods of the type may call the bounds' requirements on its fields: ```rux interface Scored { func Score() -> int32; } struct Board<T: Scored> { leader: T; } extend Board<T> { func Top(self: &Board<T>) -> int32 { return self.leader.Score(); } } ``` ```text error: type argument 'float64' does not satisfy interface bound 'Scored' on type parameter 'T' note: interface 'Scored' requires method 'Score', which type 'float64' does not implement note: type parameter 'T' of struct 'Board' is bound by 'Scored' help: implement the interface, as in 'extend float64: Scored { ... }' ``` ## Implementing interfaces A generic type implements an interface for every instantiation at once, with `extend Box<T> : Named { … }`. Each instantiation then satisfies a `Named` [bound](https://rux-lang.dev/docs/lang/generics/bounds), and converts as any implementing type does: a `Box<int32>` becomes an [interface value](https://rux-lang.dev/docs/lang/interfaces/interface-values) of type `Named`, or a `&Named` borrow. ## See also - [Generics](https://rux-lang.dev/docs/lang/generics/overview) — generic functions and inference - [Generic methods](https://rux-lang.dev/docs/lang/generics/methods) — methods of generic types - [Structures](https://rux-lang.dev/docs/lang/structs/overview) and [Variants](https://rux-lang.dev/docs/lang/variants/overview) — the non-generic forms - Learn: [Generic type](https://rux-lang.dev/docs/learn/generic-type) # Generic Methods A method can be generic in two ways. A method of a [generic type](https://rux-lang.dev/docs/lang/generics/types) uses the type's parameters, fixed when the value was made. And any method — on a generic type or not, with a receiver or without — may declare **type parameters of its own**, chosen afresh at each call. ## Methods of a generic type Inside `extend Box<T>`, `T` means whatever the receiver's instantiation says. Receivers, parameters and results are written with it: ```rux struct Labeled<T> { label: char8[..]; value: T; } extend Labeled<T> { func Labeled(label: char8[..], value: T) -> Labeled<T> { return Labeled<T> { label: label, value: value }; } func Get(self: &Labeled<T>) -> T { return self.value; } func Set(self: &var Labeled<T>, value: T) { self.value = value; } } ``` ```rux var count = Labeled<int32>("count", 7); count.Set(15); let n = count.Get(); // an int32 ``` The type arguments are written on the type name for a constructor or an associated call, `Labeled<int32>("count", 7)`, and come from the receiver for an instance call. Each method is compiled for each instantiation that calls it. ## Methods with their own type parameters A method declares its own type parameters after its name, exactly as a generic function does. They are independent of the type's: ```rux extend Labeled<T> { func With<U>(self: &Labeled<T>, other: U) -> (T, U) { return (self.value, other); } func Map<U>(self: &Labeled<T>, change: func(T) -> U) -> Labeled<U> { return Labeled<U> { label: self.label, value: change(self.value) }; } } ``` | Parameter | Declared on | Fixed when | In `count.With("apples")` | | --------- | ---------------------- | ----------------- | ------------------------- | | `T` | the type, `Labeled<T>` | the value is made | `int32` | | `U` | the method, `With<U>` | each call | `char8[..]` | A method's own parameters are inferred from its arguments, or written after the method name: ```rux let fruit = count.With("apples"); // U = char8[..], inferred let flag = count.With<bool>(true); // U = bool, written let half = count.Map(Half); // U from Half's result type ``` A method's result may be a different instantiation of its own type, as `Map` returns `Labeled<U>`. ## Associated calls A method without a receiver is called through its type. On a non-generic type, the method's own type arguments follow the method name: ```rux struct Factory { bias: int; } extend Factory { func Width<T>() -> uint { return sizeof(T); } func Echo<T>(value: T) -> T { return value; } func Read<T>(self: &Factory, value: T) -> T { return value; } } ``` ```rux let w = Factory::Width<int32>(); // 4: nothing to infer from, so written let e = Factory::Echo(42i32); // T inferred from the argument let factory = Factory { bias: 5 }; let r = factory.Read<bool>(true); // an instance call, written ``` On a **generic** type, an associated call has two sets of parameters to fill: the receiver type's and the method's. They are written in one list after the method name — the receiver type's arguments first, then the method's: ```rux struct Holder<T> { value: T; } extend Holder<T> { func OtherWidth<U>() -> uint { return sizeof(T) + sizeof(U); } func Pair<U>(self: &Holder<T>, other: U) -> (T, U) { return (self.value, other); } } ``` ```rux let total = Holder::OtherWidth<int32, int64>(); // T = int32, U = int64: 12 ``` A list that does not fill both fails with `cannot resolve type arguments for method 'OtherWidth'`. An instance call needs no such list for the type's parameters: `holder.Pair<int64>(34)` takes `T` from `holder` and `int64` for the method's own parameter. ## Bounds on method parameters A method's own type parameters may carry [bounds](https://rux-lang.dev/docs/lang/generics/bounds), checked at each call like a function's: ```rux interface Scored { func Score() -> int; } extend Factory { func Score<T: Scored>(self: &Factory, value: &T) -> int { return self.bias + value.Score(); } } ``` ```text error: type argument 'int' does not satisfy interface bound 'Scored' on type parameter 'T' note: interface 'Scored' requires method 'Score', which type 'int' does not implement note: type parameter 'T' of method 'Score' is bound by 'Scored' help: implement the interface, as in 'extend int: Scored { ... }' ``` ## What cannot be generic The special methods have fixed shapes with no type parameters of their own: [destructors](https://rux-lang.dev/docs/lang/ownership/destructors), the copy and move operations `=` and `<-`, and the [indexers](https://rux-lang.dev/docs/lang/interfaces/indexers) `[]` and `[]=`. They may still use the type parameters of a generic type they belong to. ## See also - [Generic types](https://rux-lang.dev/docs/lang/generics/types) — declaring and extending generic types - [Methods](https://rux-lang.dev/docs/lang/structs/methods) — receivers and method calls - [Bounds](https://rux-lang.dev/docs/lang/generics/bounds) — constraining type parameters - Learn: [Generic method](https://rux-lang.dev/docs/learn/generic-method) # Bounds An unconstrained type parameter promises nothing: the body may store, pass and return a `T`, but cannot call a method on it. A **bound** makes the promise. `T: Scored` admits only type arguments that provide the methods of the [interface](https://rux-lang.dev/docs/lang/interfaces/overview) `Scored`, and in return the body may call those methods on any `T`. ## Syntax ```text <T: Interface> <T: First + Second + …> <T: Interface, U> ``` A bound follows its parameter after a colon; several bounds are joined with `+`. A comma always starts the next type parameter, so `<T: Scored, Display>` declares a second parameter named `Display` rather than a second bound. Bounds may appear on the type parameters of functions, methods and [generic types](https://rux-lang.dev/docs/lang/generics/types). ```rux interface Scored { func Score() -> int32; } interface Named { func Name() -> char8[..]; } func Best<T: Scored>(first: T, second: T) -> T { if second.Score() > first.Score() { return second; } return first; } func Announce<T: Scored + Named>(value: &T) { PrintLine("{} has {}", value.Name(), value.Score()); } ``` ## Inside the body A bounded `T` is exactly what its bounds say, and nothing more. Every requirement of every bound is callable on it; nothing else is: ```text error: no interface bound on type parameter 'T' provides method 'Score' note: type parameter 'T' has no interface bounds help: add a bound whose interface declares 'Score', as in 'T: SomeInterface' ``` The same holds for passing a `T` where an interface is expected: a `T` prints with `{}` only under a `Display` bound. Inside the body, `Self` in a bound's requirements stands for the type argument, so with `Core::Equatable` as the bound, `left.Equals(right)` takes another `T` — and a requirement returning `Self` returns a `T`. Results stay concrete. `Best` called with two `Player` values returns a `Player`, with every field and method of `Player` available — it never becomes "some `Scored`". ## Satisfying a bound A type argument satisfies a bound when it **has every method the interface requires**. Implementing the interface with `extend T : Scored { … }` is the usual way to provide them, but a bound is structural: a type whose plain `extend` block declares the required methods satisfies it too. ```rux struct Player { name: char8[..]; points: int32; } extend Player : Scored { func Score(self: &Player) -> int32 { return self.points; } } extend Player : Named { func Name(self: &Player) -> char8[..] { return self.name; } } struct Team { total: int32; } // No ': Scored', but Score is there, so Team satisfies the bound. extend Team { func Score(self: &Team) -> int32 { return self.total; } } ``` [Interface values](https://rux-lang.dev/docs/lang/interfaces/interface-values) are stricter: only a declared implementation converts to one. An interface that requires nothing, such as `Core::Iterator`, is satisfied by every type and only documents intent. ### Primitives A primitive type has no methods of its own, so it satisfies a bound only once an `extend` block gives it the methods: ```rux extend int32 : Scored { func Score(self: &int32) -> int32 { return self; } } ``` After this `Best<int32>(3, 9)` is accepted, while `Best(2.5, 1.5)` is not — `float64` has `>` but no `Score`. Note that bare literals make `T` an `int`, not an `int32`: `Best(3, 9)` fails naming `'int'`, and the explicit `<int32>` is what makes `3` and `9` `int32` values. ### `Sendable` `Core::Sendable` is the one interface the compiler decides for itself. No extension implements it: every type satisfies it except a reference and a type that is or holds one declared [`#Unsendable()`](https://rux-lang.dev/docs/lang/attributes/unsendable), such as the standard `Rc`, whose count is not atomic. A raw pointer satisfies it, since what a pointer shares is the program's to vouch for, and a type parameter satisfies it only when bound by it. `Thread::Spawn` bounds a thread's context and result by it, so handing an `Rc` to another thread is refused: ```text error: type argument 'Rc<uint64>' does not satisfy interface bound 'Sendable' on type parameter 'T' note: 'Rc<uint64>' is declared '#Unsendable()', so it stays on the thread that made it note: type parameter 'T' of function 'Spawn' is bound by 'Sendable' help: keep the value on the thread that made it, or share it through a type made for threads, such as 'Arc' in place of 'Rc' ``` ## Checked at each use A bound is checked where a type argument meets it — at each call of a bounded function or method, and at each written instantiation of a bounded type — never somewhere inside the body. The type arguments are inferred first, then every bound is checked on its own, and the failing one is reported with the missing method: ```text error: type argument 'float64' does not satisfy interface bound 'Scored' on type parameter 'T' note: interface 'Scored' requires method 'Score', which type 'float64' does not implement note: type parameter 'T' of function 'Best' is bound by 'Scored' help: implement the interface, as in 'extend float64: Scored { ... }' ``` A type that meets one bound of `Scored + Named` but not the other is refused just the same. ## Bounds travel Inside a generic body, a type parameter satisfies exactly the bounds it was declared with. A generic that calls a bounded generic must therefore promise at least what the callee demands: ```rux func Margin<T: Scored>(first: T, second: T) -> int32 { let winner = Best(first, second); // T is Scored here, as Best requires return winner.Score() * 2 - first.Score() - second.Score(); } ``` Without the bound on `Margin`, the call to `Best` is refused: ```text error: type argument 'T' does not satisfy interface bound 'Scored' on type parameter 'T' note: type parameter 'T' is not constrained by 'Scored' note: type parameter 'T' of function 'Best' is bound by 'Scored' help: add the bound to the enclosing declaration, as in 'T: Scored' ``` ## Static dispatch Each instantiation calls the method of its own type argument directly, resolved when it is compiled: no interface value is built, and nothing is looked up at run time. The comparison with dynamic dispatch through an interface value is tabled in [Interface values](https://rux-lang.dev/docs/lang/interfaces/interface-values#interface-values-and-bounds). ## See also - [Interfaces](https://rux-lang.dev/docs/lang/interfaces/overview) — declaring the interfaces bounds name - [Generics](https://rux-lang.dev/docs/lang/generics/overview) — type parameters and inference - [Interface values](https://rux-lang.dev/docs/lang/interfaces/interface-values) — the dynamically dispatched alternative - Learn: [Generic bound](https://rux-lang.dev/docs/learn/generic-bound), [Multiple bounds](https://rux-lang.dev/docs/learn/multiple-bounds) # Packages and Modules Rux organises code at two levels. A **package** is the unit that is compiled, versioned and shared: a `Rux.toml` manifest and the source files under `Src/`. A **module** is a named namespace *inside* a package, declared with `module A::B { … }`. Packages are described by the [packaging guide](https://rux-lang.dev/docs/packaging); this chapter covers what the source sees of them — modules, [imports](https://rux-lang.dev/docs/lang/modules/imports) and [visibility](https://rux-lang.dev/docs/lang/modules/visibility). ```text module-decl = [ "pub" ] "module" identifier { "::" identifier } "{" { declaration } "}" ``` ## Files are not modules Every `.rux` file under `Src/` belongs to the package, and the compiler reads them all as one unit. A file adds nothing to any name: its own name means nothing to the compiler, and a package may be split across as many files as is convenient — or none of them besides `Src/Main.rux`. There are no `mod` lists or file-level `module X;` headers; where a declaration lives is decided only by the `module { }` blocks around it. ```text error: expected '{' to start the module body before ';' ``` is what a file-level `module Text;` produces. Write the block form. ## The package root A declaration that is not inside any `module` block sits at the **package root**. Every root item of a package is one namespace, whichever file declares it — two files cannot both declare a root function with the same signature: ```text error: function 'Area' has the same parameter signature as an earlier overload ``` Seen from another package, a root item is reached as `Package::Name`, where `Package` is the package's import name (see [Imports](https://rux-lang.dev/docs/lang/modules/imports)). ## Module declarations `module` opens a namespace and holds any declarations: functions, types, constants, `extend` blocks, `extern` blocks, [imports](https://rux-lang.dev/docs/lang/modules/imports), [`when`](https://rux-lang.dev/docs/lang/comptime/conditional) blocks and further modules. A module may appear at the package root, inside another module, or inside a `when` branch — never inside a function. A path declares the nested modules in one step. These two are the same declaration: ```rux module Shape::Circle { func Area(radius: float64) -> float64 { return 3.14159 * radius * radius; } } module Shape { module Circle { func Area(radius: float64) -> float64 { return 3.14159 * radius * radius; } } } ``` (Written together, as here, they would clash: both declare `Shape::Circle::Area` with the same signature.) A module is **open**: every `module` block with the same path adds to the same module, in the same file or in different ones. Two functions called `Area` do not clash when they are in different modules, because a module's name is part of the full name of everything in it. ## Example A package called `Geometry` with two files. `Src/Shapes.rux` declares a root constant and two modules under a shared parent: ```rux // The package root: these declarations are in no module. const Pi: float64 = 3.14159; module Shape::Circle { func Area(radius: float64) -> float64 { return Pi * radius * radius; } } module Shape { module Rectangle { func Area(width: float64, height: float64) -> float64 { return width * height; } } } ``` `Src/Main.rux` reaches them in two ways: ```rux import Io::PrintLine; import Geometry::Shape::Circle; func Main() -> int { PrintLine("circle {}", Circle::Area(2.0)); PrintLine("rectangle {}", Shape::Rectangle::Area(3.0, 4.0)); return 0; } ``` ```text circle 12.56636 rectangle 12.0 ``` ```mermaid flowchart LR pkg(["`package Geometry`"]) --> pi["`Pi`<br/>(root)"] pkg --> main["`Main`<br/>(root)"] pkg --> shape["`module Shape`"] shape --> circle["`module Circle`<br/>`Area`"] shape --> rect["`module Rectangle`<br/>`Area`"] ``` ## Name lookup inside a package A name is looked up in the innermost module that encloses its use, then in each enclosing module, and finally at the package root. So `Circle::Area` above can use the root constant `Pi` unqualified, and code inside `Shape::Rectangle` could call `Circle::Area` through their shared parent. Every root item — including each top-level module — is visible throughout the package without an import, which is why `Main` can write `Shape::Rectangle::Area(…)`. A nested module or an item inside one is reached either by its path from the root or by importing it: `import Geometry::Shape::Circle;` makes `Circle` a name of its own. An import always starts with a package name, the package's own included — see [Imports](https://rux-lang.dev/docs/lang/modules/imports). Inside one package every declaration is usable from every file, `pub` or not. `pub` only matters to the packages that depend on this one — see [Visibility](https://rux-lang.dev/docs/lang/modules/visibility). ## See also - [Imports](https://rux-lang.dev/docs/lang/modules/imports) — bringing names from a package or module into scope - [Visibility](https://rux-lang.dev/docs/lang/modules/visibility) — what `pub` shows to dependent packages - [Packaging](https://rux-lang.dev/docs/packaging) — manifests, [directory layout](https://rux-lang.dev/docs/packaging/layout) and [dependencies](https://rux-lang.dev/docs/packaging/dependencies) - Learn: [Module](https://rux-lang.dev/docs/learn/module), [Package](https://rux-lang.dev/docs/learn/package) # Imports An `import` declaration brings names from a package into the current scope. Every path starts with a **package**, and nothing from another package — not even a fully qualified path — can be named without an import. ```text import-decl = "import" package { "::" segment } [ "::" ( "*" | "{" name { "," name } [ "," ] "}" ) ] ";" segment = identifier | "#" identifier name = identifier | "#" identifier ``` ## Forms | Form | Brings in | Used as | | -------------------------------- | ---------------------------------------------------- | ------------------- | | `import Pkg::Item;` | one root item of `Pkg` | `Item` | | `import Pkg::Mod;` | a module of `Pkg` | `Mod::Item` | | `import Pkg::Mod::Item;` | one item of a module | `Item` | | `import Pkg::{ A, B, #target };` | several items or modules from one place | `A`, `B`, `#target` | | `import Pkg::Mod::{ A, B };` | several items of one module | `A`, `B` | | `import Pkg::*;` | every public root item and top-level module of `Pkg` | each by its name | | `import Pkg::Mod::*;` | every public item of a module | each by its name | | `import Pkg;` | `Pkg`'s module named `Pkg`, when it has one | `Pkg::Item` | ```rux import Io::PrintLine; // a root item import Core::{ #target, int8 }; // a compile-time value and a primitive's constants import Tally::{ Counter, Level }; // two items from one package import Shapes::Square; // a whole module import Shapes::Square::Perimeter; // one item of a module import Shapes::Circle::*; // every public item of a module func Main() -> int { var counter = Counter(3); counter.Tick(); PrintLine("{} {}", counter.Count(), Level::Low == Level::Low); PrintLine("{} {} {}", Square::Area(5), Perimeter(5), Diameter(2)); PrintLine("{} {}", int8::Max, #target.pointerBits); return 0; } ``` Importing a module rather than its items keeps calls qualified, which is the better choice whenever a bare name would be unclear or would collide: `Square::Area(5)` says which `Area` is meant. `import Pkg;` on its own names a module, not the package: it works only when `Pkg` declares a module called `Pkg` (`pub module Pkg { … }`). Otherwise it is an error — import an item or a module instead: ```text error: import 'Io' does not name a module help: import an item instead, for example 'import Io::Name' ``` ## The first segment is a package The first segment of every import is a package's **import name**: - the current package's own `Name` from `Rux.toml` — a package imports its own nested modules this way, as in `import Geometry::Shape::Circle;`; - or a key under `[Dependencies]`. The key is usually the package's name, but it may differ, which renames the package for imports: with `Shapes = { Package = "Geometry2", Path = "../Geometry2" }`, the example above imports from `Shapes`. A first segment that is neither fails before analysis starts: ```text error: package 'Shape' is not listed in [Dependencies] of '…\Rux.toml' note: the import requires a package dependency with the same import name help: add the package under [Dependencies] or correct the import path ``` The remaining segments walk the package's modules. An item or module that is not there is reported as `name 'Gauge' was not found in package 'Tally'` or `module 'Counter' was not found in package 'Tally'`. ## Qualified paths need an import A path in an expression or a type starts from a name already in scope. Another package's name is never in scope by itself, so a fully qualified call does not work: ```rux func Main() -> int { return Tally::Clamp(12); // error: name 'Tally' is not defined in this scope } ``` Import the item, or the module that contains it, and qualify from there. Inside one package, every root item and every top-level module is already in scope, so `Shape::Circle::Area(2.0)` works without an import from anywhere in the package that declares `Shape` — see [Name lookup](https://rux-lang.dev/docs/lang/modules/overview#name-lookup-inside-a-package). ## Compile-time values and primitive constants Imports also reach two kinds of name that look built in but come from the `Core` package: - **Compile-time values and directives** are imported by their `#` names: `import Core::{ #target, #build, #Error };`. Without the import, `#target.os` fails with `error: name '#target' is not defined in this scope`. See [Compile-time context](https://rux-lang.dev/docs/lang/comptime/context). - **Associated constants of primitive types** — `int8::Max`, `uint::Bits`, `float64::NaN` — come from `Core`'s extensions of those built-in types, so the extension must be imported by the type's name: `import Core::int8;`. An alias imports its target's, so `import Core::byte;` gives `byte::Max` and `uint8::Max`. The primitive type itself is usable without any import; only its constants need one. Without it: ```text error: 'Max' not found in extend for type 'int8' ``` The full list of primitive constants is in [Primitive types](https://rux-lang.dev/docs/lang/appendix/primitives); how a package declares them is in [Intrinsics](https://rux-lang.dev/docs/lang/comptime/intrinsics#primitive-types-are-not-intrinsics). ## Where imports go An import is a declaration. It may appear at the package root, inside a `module` body, and inside a [`when`](https://rux-lang.dev/docs/lang/comptime/conditional) branch; in a `when` match arm the trailing `;` is optional. An import inside a module applies to that module and the modules nested in it. It cannot appear inside a function body: ```text error: expected an expression before 'import' ``` An import at the top of a file belongs to that file alone, so each file starts with the imports it uses. Another file of the same package that uses the name must import it itself: ```text error: name 'PrintLine' is not defined in this scope note: 'Main.rux' imports 'PrintLine', but an import belongs to the file that writes it help: import 'PrintLine' in this file too ``` ## Glob imports `import Pkg::*;` and `import Pkg::Mod::*;` bring in every **public** name at that level — items, and with the package form also its public top-level modules. Private declarations are skipped silently, so a glob never fails on them; naming a private item explicitly does fail: ```text error: function 'Clamp' is private to package 'Tally' help: add 'pub' to the declaration of 'Clamp' ``` A glob makes it hard to see where a name came from, and grows when the package does. Prefer a list. ## Conflicts An imported function joins the overload set of a function with the same name already in scope. Two candidates that accept the same arguments make every call ambiguous: ```text error: call to 'Validate' is ambiguous: 2 overloads accept argument types () help: rename one of the overloads, or remove a default value that makes them overlap ``` Import the module instead and qualify the call. ## See also - [Packages and modules](https://rux-lang.dev/docs/lang/modules/overview) — what a path walks through - [Visibility](https://rux-lang.dev/docs/lang/modules/visibility) — which names another package can import - [Dependencies](https://rux-lang.dev/docs/packaging/dependencies) — the `[Dependencies]` table that supplies import names - Learn: [Module](https://rux-lang.dev/docs/learn/module), [Dependency](https://rux-lang.dev/docs/learn/dependency) # Visibility Every declaration is **package-private** unless it starts with `pub`. Package-private means usable from every file and every module of the declaring package; it does not mean file-private or module-private. `pub` marks what a package shows to the packages that **depend** on it. ```text visibility = [ "pub" ] ``` Inside one package `pub` changes nothing. It matters only at the border between packages, where everything without it is refused. ## What takes `pub` `pub` is written before the declaration it applies to, and each declaration chooses for itself: | Declaration | Default | Notes | | -------------------------------------------------------------------------- | --------------- | ------------------------------------------------------ | | `func`, `const`, `type`, `struct`, `union`, `enum`, `variant`, `interface` | package-private | at the root or in a module | | `module` | package-private | `pub module A::B` makes both `A` and `B` public | | struct and union fields | package-private | each field separately | | methods, constructors, operators in `extend` | package-private | each member separately; `extend` itself takes no `pub` | | `extern func`, `extern` block members | package-private | `pub` before a member, or `pub extern { … }` for all | | enum members, variant cases | inherit | public exactly when their type is | | interface requirements | inherit | public exactly when the interface is | A type being public does not make its members public, and a public member of a private type is still unreachable, because the type cannot be named. ## Example A library package `Tally`, depended on by a program. The promise it keeps — the count never passes its limit — rests on what is private: ```rux pub struct Counter { pub step: int; count: int; } extend Counter { pub func Counter(step: int) -> Counter { return Counter { step: step, count: 0 }; } pub func Tick(self: &var Counter) { self.count = Clamp(self.count + self.step); } pub func Count(self: &Counter) -> int { return self.count; } } const Limit: int = 10; func Clamp(value: int) -> int { return value > Limit ? Limit : value; } ``` The program sees `Counter`, its `step` field and its three functions, and nothing else: ```rux import Io::PrintLine; import Tally::Counter; func Main() -> int { var counter = Counter(4); counter.Tick(); counter.Tick(); counter.Tick(); PrintLine("step {}, count {}", counter.step, counter.Count()); // step 4, count 10 return 0; } ``` Every attempt to reach past the public surface is refused, for reading as much as for writing: | Attempt in the program | Error | | ----------------------------------- | ------------------------------------------------------------------------------------------ | | `import Tally::{ Counter, Clamp };` | `function 'Clamp' is private to package 'Tally'` | | `import Tally::Limit;` | `constant 'Limit' is private to package 'Tally'` | | `let n = counter.count;` | `struct field 'count' is private to package 'Tally'` | | a private method `counter.Reset()` | `method 'Reset' is private to package 'Tally'` | | `Counter { step: 1, count: 0 }` | `struct 'Counter' cannot be initialized outside its package because it has private fields` | Each error comes with a help line naming the fix — "add 'pub' to the declaration of 'Clamp'", or for the struct literal, "use a public constructor instead". ## Construction A struct literal must name every field, so outside its package a struct with any private field can only be made by a public [constructor](https://rux-lang.dev/docs/lang/structs/constructors) or another public function. That is the usual way to protect an invariant: keep the representation private and publish the operations. ## Private modules An item is **effectively public** only when it and every module that contains it are public. A `pub` function inside a private module stays package-private: ```rux module Hidden { pub func Inside() -> int { return 4; } } ``` ```text error: module 'Hidden' is private to package 'Lib' help: add 'pub' to the declaration of 'Hidden' ``` `pub module Text::Utf8 { … }` publishes both `Text` and `Utf8`; the items inside still choose individually. ## Public signatures A public declaration may not expose a private type. A public function's parameters and result, a public field's type, a public alias, constant, extern, generic bound, variant payload or interface requirement must all name public types, down to nested generic arguments. Publishing an item never re-exports the private types its signature uses; the compiler rejects the leak instead: ```rux struct Secret { value: int; } pub func Reveal() -> Secret { return Secret { value: 1 }; } pub struct Holder { pub inner: Secret; } ``` ```text error: public function 'Reveal' exposes private type 'Secret' help: make 'Secret' public or remove it from the public signature error: public field 'Holder.inner' exposes private type 'Secret' help: make 'Secret' public or remove it from the public signature ``` ## Interfaces and overloads A private method may still satisfy a public interface. Code in another package can call it through the [interface value](https://rux-lang.dev/docs/lang/interfaces/interface-values) but not directly on the concrete type: ```rux pub interface Named { func Name(self: &Self) -> char8[..]; } extend Counter : Named { func Name(self: &Counter) -> char8[..] { return "counter"; } } ``` From the program, `Describe(counter)` with a `&Named` parameter calls `Name`, while `counter.Name()` fails with `method 'Name' is private to package 'Tally'`. When a function name has public and private overloads, another package's overload resolution sees only the public ones, and its diagnostics do not mention the private candidates. A [glob import](https://rux-lang.dev/docs/lang/modules/imports#glob-imports) silently skips private declarations. ## Other rules - Compiler-generated copy and move operations are available wherever their type is; a custom copy or move, like any operator, must be `pub` to be used from another package. Destructors are called by the compiler whatever their visibility, and normally stay private. - Field visibility applies inside a [`when`](https://rux-lang.dev/docs/lang/comptime/conditional) condition too: `when #build.debugAssertions` works because `Core` declares that field `pub`. - `rux doc` documents only effectively public declarations unless asked for private ones. ## See also - [Packages and modules](https://rux-lang.dev/docs/lang/modules/overview) — the namespaces `pub` applies to - [Imports](https://rux-lang.dev/docs/lang/modules/imports) — how a dependent package names public items - [Structs](https://rux-lang.dev/docs/lang/structs/overview) and [Constructors](https://rux-lang.dev/docs/lang/structs/constructors) — fields and the functions that build them - Learn: [Visibility](https://rux-lang.dev/docs/learn/visibility), [Documentation](https://rux-lang.dev/docs/learn/documentation) # Compile-Time Evaluation Part of every Rux program is settled while it is being **compiled**, before any of it runs. Constants are folded to values, `sizeof` and `alignof` to numbers, and a [`when`](https://rux-lang.dev/docs/lang/comptime/conditional) keeps one branch and throws the others away unread. The compiler also describes the build itself — the target machine, the build profile, the compiler, the source location and user defines — as ordinary values a program can read. None of this costs anything at run time: by then a compile-time value is a plain constant, and a discarded branch does not exist. There is no preprocessor and no separate build language. Everything in this chapter is written in Rux and checked by the same compiler. ## What is known at compile time | Construct | Known while compiling | Page | | ------------------------------------------------------ | --------------------------------------------------------------------- | ------------------------------------------------------------------------------ | | literals and `const` declarations | the value, folded from literals, operators, casts and other constants | [Constants](https://rux-lang.dev/docs/lang/bindings/constants) | | `sizeof(T)`, `alignof(T)` | a type's size and alignment in bytes, as `uint` | [Layout](https://rux-lang.dev/docs/lang/memory/layout) | | primitive constants such as `int32::Max`, `uint::Bits` | their values | [Primitive types](https://rux-lang.dev/docs/lang/appendix/primitives) | | `#target`, `#build`, `#compiler`, `#source` | facts about the build and the source location | [Context](https://rux-lang.dev/docs/lang/comptime/context) | | `#config` | user-defined values from `Rux.toml` or `--define` | [Config](https://rux-lang.dev/docs/lang/comptime/config) | | `when` | which branch is compiled | [Conditional compilation](https://rux-lang.dev/docs/lang/comptime/conditional) | | `#Error`, `#Warn` | diagnostics that stop or annotate the build | [Diagnostics](https://rux-lang.dev/docs/lang/comptime/diagnostics) | | `intrinsic` declarations | the values and functions the compiler itself supplies | [Intrinsics](https://rux-lang.dev/docs/lang/comptime/intrinsics) | A `const` initializer may use literals, operators, casts, struct literals, other constants, `sizeof`/`alignof`, primitive constants and the scalar fields of the `#` values. A function call is never a compile-time value, even when it could be computed: ```rux func Square(x: int) -> int { return x * x; } const Nine = Square(3); ``` ```text error: call to 'Square' is not a compile-time value help: initialize a constant from literals, operators, casts, and other constants ``` ## The `#` values come from `Core` `#target`, `#build`, `#compiler`, `#source` and `#config`, and the directives `#Error` and `#Warn`, are declared in the `Core` package and imported like any other name: ```rux import Core::{ #target, #build, #Error }; ``` They are not keywords. A package that declares them itself — see [Intrinsics](https://rux-lang.dev/docs/lang/comptime/intrinsics) — can stand in for `Core`. ## Compile time and run time Rux keeps the two kinds of decision visibly apart. A chain is `if`/`else if` throughout or `when`/`else when` throughout, never a mixture, so a reader always knows which branches the compiler has already settled: | | `if` | `when` | | ------------------- | ------------------------- | --------------------------------------------- | | Decided | while the program runs | while the program is compiled | | Condition | any `bool` | an expression the compiler can fold | | Untaken branch | compiled and type-checked | parsed, then discarded before name resolution | | Scope of a branch | its own | none: declarations and bindings stay after it | | Where it can appear | inside a function body | between declarations and inside bodies | ```mermaid flowchart LR src["source"] --> parse["parse"] parse --> fold["fold `when`<br/>keep one branch"] fold --> resolve["resolve names,<br/>check types"] resolve --> code["generate code"] fold -. "untaken branches<br/>never reach here" .-> resolve ``` A `#` value read in ordinary code is just as free: `#build.debugAssertions` in an expression compiles to the constant `true` or `false`. ## See also - [Conditional compilation](https://rux-lang.dev/docs/lang/comptime/conditional) — `when` in full - [Context](https://rux-lang.dev/docs/lang/comptime/context) — every field of `#target`, `#build`, `#compiler` and `#source` - [Config](https://rux-lang.dev/docs/lang/comptime/config) — values a build passes in - [Constants](https://rux-lang.dev/docs/lang/bindings/constants) — `const` declarations - Learn: [Compile time](https://rux-lang.dev/docs/learn/compile-time), [When](https://rux-lang.dev/docs/learn/when) # Conditional Compilation `when` is the compile-time counterpart of [`if`](https://rux-lang.dev/docs/lang/statements/if). Its condition is folded while compiling, the branch it selects is kept, and every other branch is discarded **before names are resolved** — so an untaken branch may call functions, name types or link libraries that do not exist in this build. That is what makes one source tree serve several targets and configurations. ```text when-chain = "when" condition "{" items "}" { "else" "when" condition "{" items "}" } [ "else" "{" items "}" ] when-match = "when" subject "{" arm { [ "," ] arm } [ "," ] "}" arm = ( pattern { "," pattern } | "else" ) "=>" arm-body ``` `items` are declarations or statements, depending on where the `when` stands. ## Chains A chain is tested from top to bottom; the first condition that holds selects its branch, and a final bare `else` is taken when none does. Without an `else`, a chain whose conditions all fail compiles to nothing. ```rux import Core::{ #compiler, SemanticVersion }; const Rux040 = SemanticVersion { major: 0, minor: 4, patch: 0 }; const Rux100 = SemanticVersion { major: 1, minor: 0, patch: 0 }; when #compiler.version >= Rux100 { func Channel() -> char8[..] { return "stable"; } } else when #compiler.version >= Rux040 { func Channel() -> char8[..] { return "preview"; } } else { // Never resolved by this compiler, so a function nobody wrote is not an error. func Channel() -> char8[..] { return LegacyChannel(); } } ``` A chain keeps the keyword it opened with. `else if` inside a `when` chain — or `else when` inside an `if` chain — is an error: ```text error: expected 'when' after 'else' in a compile-time 'when' chain; 'if' is the run-time conditional ``` ## Match form When the condition picks between several values of one subject, the match form is shorter than a chain of `==`. Each arm lists one or more patterns before `=>`; the first arm with a matching pattern is kept. Patterns are compile-time values compared for equality — enum members (the `.Linux` shorthand takes its enum from the subject), integers and strings: ```rux import Core::{ #target, #Error }; when #target.os { .Linux, .FreeBSD => const Family: char8[..] = "unix"; .macOS => const Family: char8[..] = "darwin"; .Windows => const Family: char8[..] = "windows"; else => #Error("unsupported operating system") } ``` The `else` arm must be last (`error: the 'else' arm must be last in a 'when' match`). Without one, a build that no arm matches stops: ```text error: no arm of this 'when' matches .FreeBSD ``` That is the right outcome when the code truly cannot work elsewhere; when it can, add an `else` arm. Commas between arms are optional, except after an arm whose body is a bare expression: there the comma is what ends the expression, so `.Windows => Setup(), .Linux => …` needs it. ### Arm bodies | Position | An arm body may be | | -------------------- | ----------------------------------------------------------------------------------------------- | | between declarations | one declaration, a `{ … }` block of declarations, an `import`, or an `#Error`/`#Warn` directive | | inside a body | one expression — usually a call — or a `{ … }` block of statements | A statement written bare as an arm body is refused, because it is not an expression: ```text error: a 'when' arm body that is a statement must be written as a block, as in '.Windows => { return 1; }' ``` ## Where `when` can appear - **Between declarations** — at the package root, inside a `module`, and inside another `when` branch. The taken branch's declarations are spliced into the enclosing list, as if written there. - **Inside an `extend` block** — selecting methods and associated constants. - **Inside a function body** — selecting statements. `when` cannot stand inside a struct's field list, an `extern` block or an expression. ### No new scope A taken branch opens no scope. A `let` in it, or a declaration, is still there after the `when`: ```rux import Core::{ #target }; import Io::PrintLine; func Main() -> int { when #target.os { .Windows => { let separator = "\\"; }, else => { let separator = "/"; } } PrintLine("{}", separator); return 0; } ``` The same code with `if` would fail twice: each `separator` would end with its branch, and both branches would have to compile. ## Untaken branches An untaken branch is **parsed** — it must be well-formed Rux — but never resolved or type-checked. Calls to missing functions, unknown types, a library absent on this system, assembly for another architecture: none of them is an error there. The flip side is that a mistake in an untaken branch stays hidden until a build takes it. Build for each target that matters (`rux build --target linux-x86_64`, for instance) to check every branch. ## Conditions A condition — or a match subject — must be something the compiler can fold before name resolution: | Operand | Example | | -------------------------------------------------------------------------------------- | ------------------------------------ | | `bool`, integer, floating-point, character and string literals | `true`, `64`, `"windows-x86_64"` | | constants with foldable initializers | `when Chosen == 20` | | primitive constants (with the extension imported from `Core`) | `int32::Bits == 32` | | `sizeof` and `alignof` of a primitive type | `sizeof(int) == 8` | | fields of `#target`, `#build`, `#compiler`, `#source` | `#target.pointerBits`, `#build.mode` | | the queries `#target.HasFeature`, `#compiler.HasFeature`, `#config.Has`, `#config.Get` | `#config.Has("Verbose")` | | `#compiler.version` and `SemanticVersion` constants | `#compiler.version >= Rux040` | They combine with `==` `!=` on any of these, `<` `<=` `>` `>=` on numbers, characters and versions, the `SemanticVersion` methods (`IsAtLeast`, `IsLessThan`, …), `&&` `||` `!`, and arithmetic. Floating-point values retain their declared width and use exact compiler arithmetic. Conditions can read the [intrinsic](https://rux-lang.dev/docs/lang/comptime/intrinsics#constants) finite limits, infinities and NaNs at every width, including `float512::Max`, and compare values beyond the `float64` range. Integer casts retain or truncate all bits at the requested width. A cast to a character width never truncates: the value is checked against the width, and one it cannot hold makes the condition invalid. `sizeof` and `alignof` of a non-primitive type, and function calls, are not available: ```text error: 'when' condition is not a valid compile-time expression ``` A `let` binding is never a compile-time value (`error: 'minor' is not a compile-time constant`). Enum-valued fields compare only with `==` and `!=`; ordering `#target.os < .Windows` is the same "not a valid compile-time expression" error. A misspelt member lists the real ones: ```text error: '.MacOS' is not a variant of 'OperatingSystem'; the variants are: .FreeBSD, .Linux, .macOS, .Windows ``` ## See also - [Context](https://rux-lang.dev/docs/lang/comptime/context) — the fields and queries a condition reads - [Config](https://rux-lang.dev/docs/lang/comptime/config) — conditions on user defines - [Diagnostics](https://rux-lang.dev/docs/lang/comptime/diagnostics) — `#Error` and `#Warn` in an untaken-by-design branch - [`if`](https://rux-lang.dev/docs/lang/statements/if) — the run-time conditional - Learn: [When](https://rux-lang.dev/docs/learn/when), [Target](https://rux-lang.dev/docs/learn/target) # Compile-Time Context Four values describe the build a program is part of. The compiler fills them in before compiling starts, and `Core` declares them, so each is imported by its `#` name: ```rux import Core::{ #target, #build, #compiler, #source }; ``` | Value | Type | Describes | | ----------- | ---------- | ------------------------------------------------- | | `#target` | `Target` | the machine the program is built **for** | | `#build` | `Build` | the build profile, its options and the output | | `#compiler` | `Compiler` | the compiler doing the build | | `#source` | `Source` | the place in the source where the read is written | A fifth, `#config`, carries values the build is given — see [Config](https://rux-lang.dev/docs/lang/comptime/config). The struct and enum types (`Target`, `OperatingSystem`, `BuildMode`, …) are ordinary `Core` declarations; import them too when code names them, as in `OperatingSystem::Linux` or `BuildMode::Debug`. Fields are read with `.`, are lowerCamelCase, and are fixed for the whole build. A read can drive a [`when`](https://rux-lang.dev/docs/lang/comptime/conditional), initialize a scalar [constant](https://rux-lang.dev/docs/lang/bindings/constants), or appear in any expression, where it compiles to a constant. Text fields (`char8[..]`) work in expressions and conditions; a `const` of slice type, though, must be initialized with a literal, so `const Date: char8[..] = #build.date;` is refused with `a constant sequence must be initialized with an array literal or a string literal` — use a `let` instead. ## `#target` The machine the program will run on — not the machine compiling it. `rux build --target linux-x86_64` on Windows answers every field for Linux. | Field / query | Type | Notes | | --------------------- | ---------------------------- | ------------------------------------------------- | | `os` | `OperatingSystem` | the operating system | | `arch` | `Architecture` | the processor architecture | | `abi` | `ApplicationBinaryInterface` | the calling and layout conventions | | `endian` | `Endianness` | byte order; `.Little` on every supported target | | `pointerBits` | `uint` | `64` on every supported target | | `dataModel` | `DataModel` | the C widths of `long` and pointers | | `objectFormat` | `ObjectFormat` | the object format the linker emits | | `triple` | `char8[..]` | the canonical `<os>-<arch>` name `--target` takes | | `HasFeature(feature)` | `bool` | whether the build enables a CPU feature | The eight supported targets: | `triple` | `os` | `arch` | `abi` | `dataModel` | `objectFormat` | | ----------------- | ---------- | ---------- | ------------- | ----------- | -------------- | | `windows-x86_64` | `.Windows` | `.X86_64` | `.WindowsX64` | `.LLP64` | `.COFF` | | `windows-aarch64` | `.Windows` | `.AArch64` | `.AAPCS64` | `.LLP64` | `.COFF` | | `linux-x86_64` | `.Linux` | `.X86_64` | `.SystemV` | `.LP64` | `.ELF` | | `linux-aarch64` | `.Linux` | `.AArch64` | `.AAPCS64` | `.LP64` | `.ELF` | | `macos-x86_64` | `.macOS` | `.X86_64` | `.SystemV` | `.LP64` | `.MachO` | | `macos-aarch64` | `.macOS` | `.AArch64` | `.AAPCS64` | `.LP64` | `.MachO` | | `freebsd-x86_64` | `.FreeBSD` | `.X86_64` | `.SystemV` | `.LP64` | `.ELF` | | `freebsd-aarch64` | `.FreeBSD` | `.AArch64` | `.AAPCS64` | `.LP64` | `.ELF` | `HasFeature` takes a `TargetFeature`. A build for the machine running the compiler reports the features that compiler was itself built to use; a build for any other target reports none. Inside a `when` condition the shorthand `.AVX2` works; in an ordinary expression write `TargetFeature::AVX2`. An unknown name is an error (`unknown target feature '.MMX'`). ```rux import Core::{ #target }; when #target.arch == .X86_64 && #target.HasFeature(.AVX2) { func Kernel() -> char8[..] { return "avx2"; } } else { func Kernel() -> char8[..] { return "scalar"; } } ``` ## `#build` The build profile and what it produces. Every field is the same everywhere in one build. | Field | Type | Debug profile | Release profile | | ----------------- | ------------------ | ------------- | --------------- | | `profile` | `char8[..]` | `"Debug"` | `"Release"` | | `mode` | `BuildMode` | `.Debug` | `.Release` | | `optimization` | `OptimizationMode` | `.None` | `.Speed` | | `debugAssertions` | `bool` | `true` | `false` | | `debugInfo` | `bool` | `true` | `false` | | Field | Type | Value | | ------------ | ------------ | ----------------------------------------------------------------------------------- | | `isTest` | `bool` | `true` in a `rux test` build | | `outputKind` | `OutputKind` | the artifact: `.Executable`, `.SharedLibrary`, `.StaticLibrary` or `.SourceLibrary` | | `timestamp` | `uint64` | when the build started, in seconds since the Unix epoch | | `date` | `char8[..]` | `timestamp` as `YYYY-MM-DD`, in UTC | | `time` | `char8[..]` | `timestamp` as `HH:MM:SS`, in UTC | `profile` is a name, and a project may define profiles of its own; branch on `mode`, which every profile has. `debugAssertions` decides whether [`DebugAssert`](https://rux-lang.dev/docs/lang/errors/panics) is kept — when it is `false` the call is removed and its arguments are not evaluated. The timestamp is taken once per build, and honours the `SOURCE_DATE_EPOCH` environment variable for reproducible builds. ```rux import Core::{ #build, BuildMode }; import Io::PrintLine; func Main() -> int { when #build.mode == BuildMode::Debug { PrintLine("debug build of {} at {}", #build.date, #build.time); } return 0; } ``` ## `#compiler` | Field / query | Type | Notes | | ------------------ | ----------------- | --------------------------------------------------------------- | | `version` | `SemanticVersion` | the compiler's version, with `major`, `minor`, `patch` (`uint`) | | `HasFeature(name)` | `bool` | whether the compiler reports a named feature | `SemanticVersion` is an ordinary struct with the comparison operators `==` `!=` `<` `<=` `>` `>=` and the methods `Compare`, `IsEqualTo`, `IsLessThan`, `IsAtMost`, `IsGreaterThan` and `IsAtLeast`, all of which work in a `when`. A version to compare against is a **struct literal** constant — a constructor call is a run-time call and is refused (`call to 'SemanticVersion' is not a compile-time value`): ```rux import Core::{ #compiler, SemanticVersion }; const Rux040 = SemanticVersion { major: 0, minor: 4, patch: 0 }; when #compiler.version.IsAtLeast(Rux040) { const HasDefines: bool = true; } else { const HasDefines: bool = false; } ``` `HasFeature` is the better test when code needs one capability rather than a release: it names what is needed and stays right however releases are numbered. Its argument must be a string literal; an unknown name is simply `false`. Rux 0.4.0 reports: | Feature name | Feature name | Feature name | | --------------------------- | ------------------------------ | ---------------------------- | | `"conditional-compilation"` | `"namespaced-intrinsics"` | `"target-intrinsics"` | | `"build-intrinsics"` | `"compiler-feature-detection"` | `"source-location-defaults"` | | `"extern-symbol-names"` | `"link-attribute"` | `"no-return-attribute"` | ## `#source` Each read of `#source` describes the place where that read is written — the expression itself, not the function around it or its caller. | Field | Type | Value | | ---------- | ----------- | ---------------------------------------------------------------------------------------------------------- | | `line` | `uint` | the one-based line of the read | | `column` | `uint` | the one-based column of the read | | `file` | `char8[..]` | the file name as the build names it, such as `"Main.rux"` | | `fileName` | `char8[..]` | the file's last path component, such as `"Main.rux"` | | `filePath` | `char8[..]` | the path inside the package, such as `"Src/Main.rux"` | | `function` | `char8[..]` | the enclosing function, qualified for a method (`"Point::Length"`) or a module function (`"Tools::Parse"`) | | `module` | `char8[..]` | the enclosing module path | `#source.module` names only `module` blocks: a read inside `module Tools` is `"Tools"`, one inside its nested `module Inner` is `"Tools::Inner"`, and one outside every module is `""`. A file is not a module, so its name never appears. A helper that reads `#source` in its own body always reports its own body. To report where it was called from, the caller reads `#source` and passes the value: ```rux import Core::{ #source }; import Io::PrintLine; func LogAt(line: uint, message: char8[..]) { PrintLine("line {}: {}", line, message); } func Main() -> int { LogAt(#source.line, "first call"); // the line of this call LogAt(#source.line, "second call"); // and of this one return 0; } ``` A parameter default does that passing for the caller. A `#source` read written as a default is expanded at each call, so it describes the call, not the parameter list: with `func LogAt(message: char8[..], line: uint = #source.line)`, every `LogAt("…")` reports its own line, and a `#source.function` default names the function the call is in. ## Enum reference Every enum here is a `Core` declaration with a `uint8` representation. | Enum | Variants | | ---------------------------- | --------------------------------------------------------------------------------- | | `OperatingSystem` | `Unknown`, `FreeBSD`, `Linux`, `macOS`, `Windows` | | `Architecture` | `Unknown`, `AArch64`, `X86_64` | | `ApplicationBinaryInterface` | `Unknown`, `AAPCS64`, `SystemV`, `WindowsX64` | | `Endianness` | `Big`, `Little` | | `DataModel` | `Unknown`, `LLP64`, `LP64` | | `ObjectFormat` | `Unknown`, `COFF`, `ELF`, `MachO` | | `TargetFeature` | `AVX`, `AVX2`, `AVX512`, `NEON`, `SSE2`, `SSE3`, `SSE41`, `SSE42`, `SSSE3`, `SVE` | | `BuildMode` | `Debug`, `Release` | | `OptimizationMode` | `None`, `Size`, `Speed` | | `OutputKind` | `Executable`, `SharedLibrary`, `StaticLibrary`, `SourceLibrary` | No supported build produces an `Unknown` variant; it exists so a provider can describe a target the compiler has no name for. The variant is `.macOS`, with a lower-case `m`. ## See also - [Conditional compilation](https://rux-lang.dev/docs/lang/comptime/conditional) — branching on these values - [Config](https://rux-lang.dev/docs/lang/comptime/config) — `#config`, the build's own values - [Intrinsics](https://rux-lang.dev/docs/lang/comptime/intrinsics) — how `Core` declares them - API: [`Target`](https://rux-lang.dev/docs/api/core/target), [`Build`](https://rux-lang.dev/docs/api/core/build), [`Compiler`](https://rux-lang.dev/docs/api/core/compiler), [`Source`](https://rux-lang.dev/docs/api/core/source) - Learn: [Target](https://rux-lang.dev/docs/learn/target), [Build mode](https://rux-lang.dev/docs/learn/build-mode), [Source location](https://rux-lang.dev/docs/learn/source-location) # Build Configuration `#config` reads **defines**: named values handed to a build, such as a feature switch, a vendor name or a limit. They come from the manifest and the command line, are fixed for the whole build, and are read while compiling, so a [`when`](https://rux-lang.dev/docs/lang/comptime/conditional) can keep only the code a configuration needs. ```rux import Core::{ #config }; ``` | Query | Type | Result | | --------------------- | ----------- | ------------------------------------------------------------- | | `#config.Has("Name")` | `bool` | whether the build defines `Name`, whatever its value | | `#config.Get("Name")` | `char8[..]` | the value of `Name`, or an empty slice when it is not defined | `Get` alone cannot tell "not defined" from "defined as empty"; ask `Has` when the difference matters. Names are case-sensitive. ## Supplying defines **In the manifest.** A `[Build.Defines]` table in `Rux.toml` gives the package's defaults. A value may be a TOML string, boolean or integer, and is always read as text: ```toml [Build.Defines] Name = "Grace" Retries = 3 Fast = true ``` Here `#config.Get("Retries")` is `"3"` and `#config.Get("Fast")` is `"true"`. The table holds at most 128 defines; see the [manifest reference](https://rux-lang.dev/docs/packaging/manifest). **On the command line.** `--define NAME=VALUE` sets or overrides one define for one build of `rux build`, `rux run`, `rux check` or `rux test`, and may be repeated. `--define NAME` without a value defines it as `"true"`; `--define NAME=` defines it as empty. ```sh rux run --define Name=Ada --define Verbose ``` ```mermaid flowchart LR m["`Rux.toml`<br/>`[Build.Defines]`"] --> d{"the build's defines"} c["`--define NAME[=VALUE]`"] -- "overrides" --> d d --> has["`#config.Has`"] d --> get["`#config.Get`"] ``` ## Reading defines The argument to `Has` and `Get` must be a **string literal** written at the call, because the lookup happens while compiling. Even a constant holding the name is refused: ```text error: the argument to 'Has' must be a string literal written in the source help: the value is looked up while compiling, so it cannot come from a variable ``` Both queries work in a `when` condition — `Get` compares with `==` and `!=` against a string — and in ordinary expressions, where they compile to constants: ```rux import Core::{ #config }; import Io::PrintLine; when #config.Has("Verbose") { const Verbose: bool = true; } else { const Verbose: bool = false; } func Main() -> int { when #config.Has("Name") { let name = #config.Get("Name"); } else { let name = "World"; } PrintLine("Hello, {}!", name); when #config.Get("Name") == "Ada" { PrintLine("(a special greeting)"); } PrintLine("verbose: {}", Verbose); return 0; } ``` | Started with | Output | | -------------------------------------------- | -------------------------------------------------------- | | `rux run` | `Hello, World!` · `verbose: false` | | `rux run --define Name=Ada --define Verbose` | `Hello, Ada!` · `(a special greeting)` · `verbose: true` | A define is folded in while compiling: changing one means rebuilding. An executable built earlier keeps the defines it was built with, and the code for a configuration it was not built with is not in it at all. ## See also - [Conditional compilation](https://rux-lang.dev/docs/lang/comptime/conditional) — `when` and its conditions - [Context](https://rux-lang.dev/docs/lang/comptime/context) — `#target`, `#build`, `#compiler` and `#source` - [Manifest](https://rux-lang.dev/docs/packaging/manifest) — the `[Build]` and `[Build.Defines]` tables - [`rux build`](https://rux-lang.dev/docs/cli/build) and [`rux run`](https://rux-lang.dev/docs/cli/run) — the `--define` option - API: [`Config`](https://rux-lang.dev/docs/api/core/config) · Learn: [Define](https://rux-lang.dev/docs/learn/define) # Intrinsics An **intrinsic** is something the compiler implements itself: the value of `float64::Infinity`, the fields of `#target`, the code an `Assert` turns into. A program reaches it only through an `intrinsic` **declaration**, which names it and gives its type, with no body. The `Core` package holds the standard declarations, and every program imports them from there — `import Core::{ #target, Assert, float64 };` — but `Core` has no special status: any package may declare the same intrinsics and be imported instead. ```text intrinsic-decl = [ "pub" ] "intrinsic" ( "const" identifier ":" type ";" | "#" identifier ":" type ";" | function-signature ";" ) ``` `intrinsic const` is written inside an `extend` block, and `intrinsic func` may be too, where it declares a method. ## Three kinds | Declaration | The compiler supplies | The provider writes | | ------------------------------------ | ------------------------------ | ---------------------------------------- | | `intrinsic const Infinity: float64;` | the value | the name and type, in an `extend` block | | `intrinsic #target: Target;` | each field the struct declares | the struct, with the fields it exposes | | `intrinsic func Assert(…);` | the code at every call | the exact signature the compiler expects | A provider package, declaring a little of each beside the constants it adds to built-in types: ```rux // A built-in type needs no declaration. Its constants are ordinary source in an extension. extend int8 { pub const Min: int8 = -128i8; pub const Max: int8 = 127i8; } // A constant no literal can spell. extend float64 { pub intrinsic const Infinity: float64; } // A compiler-supplied value, exposing only the fields this provider chooses. pub struct Target { pub pointerBits: uint; } pub intrinsic #target: Target; // Functions the compiler emits at each call. pub intrinsic func Assert(condition: bool, message: char8[..]); pub intrinsic func #Error(message: char8[..]); ``` A program that depends on it imports the same names it would otherwise take from `Core`, and works the same way. Importing `int8` and `float64` imports the provider's extensions of those built-in types: ```rux import Basis::{ #target, #Error, Assert, float64, int8 }; func Main() -> int { when #target.pointerBits < 64 { #Error("needs a 64-bit target"); } Assert(int8::Max == 127i8, "the provider's constant"); Assert(float64::Infinity > 1.0e308, "a compiler-supplied constant"); return 0; } ``` Only what the provider declares is available: with `Basis` alone, `int16` still exists as a type, but `int16::Max` does not, and `import Basis::int16;` is refused because `Basis` does not extend it. ## Primitive types are not intrinsics Every primitive type is built into the compiler — `int8` … `int512`, `uint8` … `uint512`, `int`, `uint`, `float8` … `float512`, `bool8` … `bool512`, `char8` … `char512`, and the aliases `bool`, `byte`, `char` and `float` — so no package declares one, and `intrinsic type` no longer exists: ```text error: intrinsic type declarations have been removed; primitive types are built in help: declare its associated constants in 'extend int8 { ... }' instead ``` A primitive's representation exists everywhere; an extension supplies its *API*. That is why `int8::Max` needs `import Core::int8;` while the type `int8` does not — see [Imports](https://rux-lang.dev/docs/lang/modules/imports#compile-time-values-and-primitive-constants). ## Constants Associated constants are normally plain source (`pub const Max: int8 = 127i8;`). The only compiler-supplied ones are the floating-point limits `Max`, `Lowest`, `MinPositive`, `Epsilon`, `Infinity` and `NaN`, at every width from `float8` to `float512`. Each is declared without an initializer in an `extend` of its own type, and has that type: ```rux extend float128 { pub intrinsic const Max: float128; pub intrinsic const Epsilon: float128; } ``` `Max` is the largest finite value, `Lowest` its negation, `MinPositive` the smallest positive normal value, `Epsilon` the gap between one and the next value up, and `NaN` a quiet NaN. `Core` declares `Infinity` and `NaN` this way at every width, and all six for `float80` and wider, whose limits are too long to be worth spelling in decimal; it writes the finite limits of `float8` through `float64` as literals. Any other name, or a type other than the extended one, is refused: ```text error: intrinsic associated constants support only floating-point Infinity, NaN, Max, Lowest, MinPositive and Epsilon error: intrinsic associated constant must have its owning floating-point type ``` A [`when` condition](https://rux-lang.dev/docs/lang/comptime/conditional#conditions) computes with floats as `float64`, so it can read `Infinity` and `NaN` at every width, but not the intrinsic finite limits of `float80` and wider. ## Compile-time values `intrinsic #name: Root;` declares a value the compiler fills in. The type names which value it is — one of the structs `Target`, `Build`, `Source`, `Compiler` or `Config` — and the `#` name is how code refers to it. `Core` uses `#target`, `#build`, `#source`, `#compiler` and `#config`. The struct may declare any subset of the fields the compiler supplies for its root, and nothing else, since nothing would fill a field it does not know: ```text error: field 'wordSize' of 'Target' is not one the compiler supplies for '#target' help: remove 'wordSize'; the compiler supplies 'os', 'arch', 'abi', 'endian', 'pointerBits', 'dataModel', 'objectFormat', 'triple' error: 'Widget' is not a value the compiler supplies for '#thing' help: declare '#thing' with one of 'Target', 'Build', 'Source', 'Compiler', 'Config' ``` The fields themselves are listed in [Context](https://rux-lang.dev/docs/lang/comptime/context). Field visibility is ordinary: a field the provider leaves private cannot be read by another package, in an expression or in a `when` condition. ## Functions `intrinsic func` names a function the compiler implements, so only those it knows are accepted, each with exactly one signature: | Intrinsic | Signature | Purpose | | ---------------------------------------- | ------------------------------------------------------------------- | --------------------------------------------------------------------------------------- | | `Assert` | `(condition: bool, message: char8[..])` | stop the program unless `condition` holds | | `DebugAssert` | `(condition: bool, message: char8[..])` | the same, removed without debug assertions | | `Panic` | `(message: char8[..])` | stop the program | | `#Error` | `(message: char8[..])` | stop the build — see [Diagnostics](https://rux-lang.dev/docs/lang/comptime/diagnostics) | | `#Warn` | `(message: char8[..])` | warn during the build | | `CheckedAdd`, `CheckedSub`, `CheckedMul` | `(left: uint64, right: uint64, result: *var uint64) -> bool` | arithmetic that reports overflow (`true` on overflow) | | `Zeroize` | `(memory: *var uint8, length: uint64)` | a clearing write the optimizer may not remove | | `Target.HasFeature` | method `(self: &Target, feature: TargetFeature) -> bool` | [`#target.HasFeature`](https://rux-lang.dev/docs/lang/comptime/context#target) | | `Compiler.HasFeature` | method `(self: &Compiler, feature: char8[..]) -> bool` | [`#compiler.HasFeature`](https://rux-lang.dev/docs/lang/comptime/context#compiler) | | `Config.Get`, `Config.Has` | methods `(self: &Config, name: char8[..]) -> char8[..]` / `-> bool` | [`#config`](https://rux-lang.dev/docs/lang/comptime/config) | A method intrinsic is declared inside an `extend` of its struct, which is what gives it its `Type.Name` key: ```rux extend Target { pub intrinsic func HasFeature(self: &Target, feature: TargetFeature) -> bool; } ``` The diagnostic intrinsics are checked against their signatures, because the compiler emits the call in its own shape: ```text error: 'Square' is not a supported intrinsic function help: give the function a body, or declare a foreign function in an 'extern' block error: intrinsic 'Assert' must be declared as 'func Assert(condition: bool, message: char8[..])' note: parameter 'condition' has type 'int' error: 'intrinsic' function cannot have a body ``` ## Not intrinsics Slices, ranges, optionals, fallibles and sums are native types with no declaration at all. `intrinsic struct` does not exist (`error: intrinsic aggregate declarations have been removed; use native slice or range types`), and an ordinary struct never gains compiler-owned behaviour from its name. An `intrinsic` declaration can only bind what the compiler already implements; it cannot add a feature. ## See also - [Context](https://rux-lang.dev/docs/lang/comptime/context) — the fields of the compile-time values - [Imports](https://rux-lang.dev/docs/lang/modules/imports) — importing `#` names and primitive constants - [Primitive types](https://rux-lang.dev/docs/lang/appendix/primitives) — the built-in types and the constants `Core` extends them with - API: [`Assert`](https://rux-lang.dev/docs/api/core/diagnostics#assert), [`Panic`](https://rux-lang.dev/docs/api/core/diagnostics#panic) · Learn: [Intrinsic](https://rux-lang.dev/docs/learn/intrinsic), [Checked arithmetic](https://rux-lang.dev/docs/learn/checked-arithmetic), [Zeroize](https://rux-lang.dev/docs/learn/zeroize) # Build Diagnostics `#Error("…")` and `#Warn("…")` are messages from the source to whoever builds it. Written as a **directive**, `#Error` stops the build where the compiler reaches it and `#Warn` prints a warning and lets the build go on. Neither produces any code. ```text directive = ( "#Error" | "#Warn" ) "(" string-literal ")" ``` ```rux import Core::{ #target, #Error }; func Main() -> int { when #target.pointerBits < 64 { #Error("this program needs a 64-bit target"); } return 0; } ``` On a build that reaches it, the error points at the directive itself: ```text Src/Main.rux:5:9: error: this program needs a 64-bit target ``` The same names written *above a declaration* are attributes, which fire at every call of that declaration instead — see [`#Error`](https://rux-lang.dev/docs/lang/attributes/error) and [`#Warn`](https://rux-lang.dev/docs/lang/attributes/warn). ## They run after `when` Directives are evaluated after [conditional compilation](https://rux-lang.dev/docs/lang/comptime/conditional) has chosen its branches, and a branch that is not taken is never looked at — so a directive in it never fires. That is how they are meant to be used: `#Error` in the branch a build should never take, `#Warn` in the branch that deserves a remark. A directive outside any `when` is always reached, so a bare `#Error("…");` in a body stops every build on every target. ## Where they may be written | Position | Form | Import from `Core` | | ------------------------------------------------- | ------------------------- | ------------------ | | a statement in a function body | `#Error("…");` | yes | | a bare-expression arm of a `when` match in a body | `.AArch64 => #Warn("…"),` | yes | | an arm of a `when` match between declarations | `else => #Error("…")` | no | Between declarations, the match arm is the **only** place a directive can stand. Inside the braces of a declaration-level `when` chain, `#Error("…")` is read as the start of an attribute, and the compiler then wants a declaration after it: ```text error: expected a declaration after the attributes before '}' ``` Write the declaration-level check as a match with an `else` arm: ```rux import Core::{ #target }; when #target.os { .FreeBSD, .Linux, .macOS => const Separator: char8[..] = "/"; .Windows => const Separator: char8[..] = "\\"; else => #Error("this package does not know the path separator of this system") } ``` As a statement, a directive is a call to the intrinsic functions `Core` declares (`pub intrinsic func #Error(message: char8[..]);`), so it must be imported; without the import the build fails with `error: name '#Warn' is not defined in this scope`. ## The message The message must be a **string literal** written in place — it is printed while compiling, before any constant or variable has a value at run time. A constant is refused: ```text error: '#Warn' message must be a string literal ``` The same holds in a declaration-level `when` arm, whether or not the build takes it: `.Windows => #Error(Message)` is `'#Error' message must be a string literal` on every target. Escapes in the literal work as in any string (`\n`, `\"`, …). Write the message for the person building: say what is unsupported and, where it helps, what to do instead. ## See also - [Conditional compilation](https://rux-lang.dev/docs/lang/comptime/conditional) — choosing the branch a directive sits in - [`#Error`](https://rux-lang.dev/docs/lang/attributes/error) and [`#Warn`](https://rux-lang.dev/docs/lang/attributes/warn) — the attribute forms, reported at each call - [Panics](https://rux-lang.dev/docs/lang/errors/panics) — `Panic` and `Assert`, which stop the running program instead - API: [`#Error`](https://rux-lang.dev/docs/api/core/diagnostics#error), [`#Warn`](https://rux-lang.dev/docs/api/core/diagnostics#warn) · Learn: [Compile error](https://rux-lang.dev/docs/learn/compile-error) # Attributes An **attribute** is a `#Name(...)` call written before what it describes. It instructs the compiler — link a foreign library, fix a calling convention, flag a function at every call — without changing the code of the declaration it annotates. Rux has a fixed set of attributes; a program cannot define new ones. ```text attribute = "#" identifier "(" [ argument { "," argument } ] ")" attributes = { attribute } declaration-with-attributes = attributes [ "pub" ] declaration parameter-with-attributes = attributes parameter ``` Attributes come before `pub`, one after another. The parentheses are always written, even when empty: ```rux import Core::Panic; #NoReturn() #Warn("Abort skips the cleanup that Exit runs") pub func Abort() { Panic("aborted"); } ``` ## The attributes | Attribute | Arguments | Applies to | | --------------------------------------------------------------------- | ------------------------- | --------------------------------------------------------- | | [`#Link`](https://rux-lang.dev/docs/lang/attributes/link) | library, optional symbol | `extern func`, `extern { }` blocks | | [`#Abi`](https://rux-lang.dev/docs/lang/attributes/abi) | `.C`, `.SysV` or `.Win64` | functions, `asm func`, `extern func`, `extern { }` blocks | | [`#NoReturn`](https://rux-lang.dev/docs/lang/attributes/noreturn) | none | functions and `extern func` without a result | | [`#Warn`](https://rux-lang.dev/docs/lang/attributes/warn) | a message string | functions, methods, `extern func` | | [`#Error`](https://rux-lang.dev/docs/lang/attributes/error) | a message string | functions, methods, `extern func` | | [`#Allow`](https://rux-lang.dev/docs/lang/attributes/allow) | a lint rule name | declarations (rule-dependent) | | [`#Format`](https://rux-lang.dev/docs/lang/attributes/format) | none | a `char8[..]` parameter | | [`#Test`](https://rux-lang.dev/docs/lang/attributes/test) | none | functions without parameters, outside `extend` and `when` | | [`#Unsendable`](https://rux-lang.dev/docs/lang/attributes/unsendable) | none | `struct`, `variant` and `union` declarations | `#Format` is the one **parameter attribute**; it is written before a parameter inside the parameter list. All the others are declaration attributes, written before a declaration at the package root, inside a `module`, or before a member of an `extend` block. Members of an `extern { }` block take no attributes of their own — the attributes on the block apply to all of them: ```text error: expected 'func' or a variable declaration in the external block before '#' ``` `#Error` and `#Warn` also have a second form, as directives inside a function body or a `when` arm — see [Build diagnostics](https://rux-lang.dev/docs/lang/comptime/diagnostics). ## Rules Each attribute checks where it stands and what it is given, and the errors name the rule: | Mistake | Error | | ------------------------------------- | ----------------------------------------------------------- | | a name Rux does not have | `unknown attribute call '#Foo'` | | an attribute on the wrong declaration | `'#Abi' can only be applied to a function or extern block` | | the same attribute twice | `duplicate '#Abi' attribute`, `duplicate '#Link' attribute` | | arguments where none are taken | `'#NoReturn' does not accept arguments` | | an unknown parameter attribute | `unknown parameter attribute '#Trim'` | Restricting code to one platform is not an attribute. Use [conditional compilation](https://rux-lang.dev/docs/lang/comptime/conditional): `when #target.os == .Windows { … }` removes the other platforms' code before it is ever resolved. ## See also - [Foreign function interface](https://rux-lang.dev/docs/lang/ffi/overview) — where `#Link` and `#Abi` are used - [Build diagnostics](https://rux-lang.dev/docs/lang/comptime/diagnostics) — `#Error` and `#Warn` as directives - [Functions](https://rux-lang.dev/docs/lang/functions/declaration) — the declarations most attributes annotate - [`#Test`](https://rux-lang.dev/docs/lang/attributes/test) — unit tests that `rux test` runs - Learn: [Compile error](https://rux-lang.dev/docs/learn/compile-error), [ABI](https://rux-lang.dev/docs/learn/abi) # `#Unsendable` `#Unsendable()` marks a struct, variant or union whose values must stay on the thread that made them, such as a handle whose count is not atomic. A type declared with it, and any type that holds one in a field, element or payload, does not satisfy the compiler-known bound [`Core::Sendable`](https://rux-lang.dev/docs/api/core), which is what a thread's context and result are written with. ```text unsendable-attribute = "#Unsendable" "(" ")" ``` ## A type that stays on its thread ```rux import Core::Sendable; #Unsendable() struct Session { id: uint64; } struct Request { session: Session; } func Run<T: Sendable>(value: T) {} func Main() -> int { Run(Request { session: Session { id: 1 } }); return 0; } ``` `Request` is not declared `#Unsendable()`, but it holds a `Session`, so it is refused too: ```text error: type argument 'Request' does not satisfy interface bound 'Sendable' on type parameter 'T' note: 'Request' holds 'Session', which is declared '#Unsendable()' note: type parameter 'T' of function 'Run' is bound by 'Sendable' help: keep the value on the thread that made it, or share it through a type made for threads, such as 'Arc' in place of 'Rc' ``` `Sendable` is the one interface the compiler decides for itself: no extension implements it, and every type satisfies it except a reference and a type that is or holds one declared `#Unsendable()`. A raw pointer satisfies it, since what a pointer shares is the program's to vouch for, and a type parameter satisfies it only when bound by it. The standard `Rc` is declared `#Unsendable()`, so [`Thread::Spawn`](https://rux-lang.dev/docs/api/thread), which bounds its context and result by `Sendable`, refuses one: ```text error: type argument 'Rc<uint64>' does not satisfy interface bound 'Sendable' on type parameter 'T' note: 'Rc<uint64>' is declared '#Unsendable()', so it stays on the thread that made it ``` ## Rules | Mistake | Error | | ------------------------------- | ----------------------------------------------------------------- | | arguments to the attribute | `'#Unsendable' does not accept arguments` | | the attribute twice | `duplicate '#Unsendable' attribute` | | anything but a type declaration | `'#Unsendable' can only be applied to a struct, variant or union` | ## See also - [Bounds](https://rux-lang.dev/docs/lang/generics/bounds) — interfaces a type argument must satisfy - [Attributes](https://rux-lang.dev/docs/lang/attributes/overview) — every attribute - API: [the Thread package](https://rux-lang.dev/docs/api/thread) # `#Link` `#Link` names the shared library an [`extern`](https://rux-lang.dev/docs/lang/ffi/overview) declaration is imported from, and optionally the symbol the library exports under a different name. Every extern function needs one. ```text link-attribute = "#Link" "(" library [ "," symbol ] ")" library = string-literal | constant-name symbol = string-literal | constant-name ``` ## Library The first argument is the library's file name as the system loader finds it — `"Kernel32.dll"`, `"libc.so.6"`, `"libSystem.B.dylib"` — not a path. It may be a string literal or the name of a string constant declared in the **same package**; a constant imported from another package is refused: ```text error: '#Link' library name 'CRuntime' is not a compile-time constant ``` A constant lets one [`when`](https://rux-lang.dev/docs/lang/comptime/conditional) choose the library for every declaration that uses it: ```rux import Core::{ #target, #Error }; when #target.os { .FreeBSD => const CRuntime = "libc.so.7"; .Linux => const CRuntime = "libc.so.6"; .macOS => const CRuntime = "libSystem.B.dylib"; .Windows => const CRuntime = "ucrtbase.dll"; else => #Error("unknown C runtime") } #Link(CRuntime) extern func llabs(n: int64) -> int64; ``` ## Symbol By default the imported symbol is the declaration's own name. A second argument binds a different exported name, so the Rux name can follow Rux conventions: ```rux #Link(CRuntime, "abs") extern func AbsoluteValue(n: int32) -> int32; // calls C's abs ``` The symbol may also be a string constant. One symbol cannot stand for every function in a block, so the two-argument form applies only to a single `extern func`: ```text error: an imported symbol name cannot be applied to an extern block; use the one-argument '#Link("library")' form ``` ## On a block The one-argument form on an `extern { }` block applies the library to every member: ```rux #Link(CRuntime) extern { func abs(n: int32) -> int32; func strlen(text: *char8) -> uint; } ``` ## Rules | Mistake | Error | | ----------------------------------------- | --------------------------------------------------------------------------------- | | an `extern func` with no `#Link` | `extern function 'GetTickCount64' must specify a source DLL via #Link("dll.dll")` | | `#Link` on anything but an extern | `'#Link' can only be applied to an extern function or extern block` | | three arguments | `'#Link' accepts at most two arguments` | | a name that is not a string constant here | `'#Link' library name 'Missing' is not a compile-time constant` | | two `#Link`s on one declaration | `duplicate '#Link' attribute` | The compiler cannot see inside the library. On Windows the linker checks that the DLL exports the symbol, and a misspelt name stops the build at linking: ```text error: cannot link PE/COFF executable 'Extern': import function 'GetCurrentProcessID' was not found in DLL 'Kernel32.dll' ``` On the other systems the name is resolved by the dynamic loader when the program is loaded. ## See also - [Foreign function interface](https://rux-lang.dev/docs/lang/ffi/overview) — `extern` declarations - [Linking](https://rux-lang.dev/docs/lang/ffi/linking) — choosing libraries per platform - [`#Abi`](https://rux-lang.dev/docs/lang/attributes/abi) — the calling convention of an extern - Learn: [Extern](https://rux-lang.dev/docs/learn/extern), [ABI](https://rux-lang.dev/docs/learn/abi) # `#Abi` `#Abi` fixes the **calling convention** of a function: which registers and stack slots carry its arguments and result. Between two Rux functions the compiler handles the convention itself, so most code never names one. `#Abi` matters at a border with code the compiler did not generate — a C library calling back into Rux, or an [`asm func`](https://rux-lang.dev/docs/lang/ffi/assembly) whose body reads its arguments from particular registers. ```text abi-attribute = "#Abi" "(" "." ( "C" | "SysV" | "Win64" ) ")" ``` | Argument | Convention | | -------- | -------------------------------------------------------------------------------------------- | | `.C` | the C convention of the target being built | | `.SysV` | System V AMD64: integer arguments in `rdi`, `rsi`, `rdx`, `rcx`, `r8`, `r9`; result in `rax` | | `.Win64` | Microsoft x64: integer arguments in `rcx`, `rdx`, `r8`, `r9`; result in `rax` | `#Abi` applies to a function, an `asm func`, an `extern func` and an `extern { }` block, whose members all take it. Anything else is refused: ```text error: '#Abi' can only be applied to a function or extern block error: unknown ABI '.Fast'; valid ABIs are: .C, .SysV, .Win64 ``` ## Defaults Without `#Abi`, a function, an `asm func` and an `extern` all use the target's C convention — exactly what `#Abi(.C)` names: | Target | Default (`.C`) | | ---------------------------------- | ------------------------------------------------ | | Windows on x86-64 | Win64 | | Linux, macOS and FreeBSD on x86-64 | System V AMD64 | | every system on AArch64 | AAPCS64 (arguments in `x0`–`x7`, result in `x0`) | `.SysV` and `.Win64` name x86-64 conventions. Pinning one makes a function use it on every x86-64 target: the compiler adapts each call, so a Rux caller on Windows passes the arguments of a `#Abi(.SysV)` function in `rdi` and `rsi`. AArch64 has one convention, which `.C` names, so `#Abi(.SysV)` or `#Abi(.Win64)` in an AArch64 build is an error: ```text error: '#Abi(.Win64)' names an x86-64 calling convention, which a build for AArch64 cannot use note: AArch64 has one calling convention, which '#Abi(.C)' names help: write '#Abi(.C)', or keep the x86-64 declaration in a 'when #target.arch' arm ``` ## A function C calls A function handed to C as a callback must use the convention C uses. Rux functions already do by default, but `#Abi(.C)` writes the promise down — so it stays true, and so the next reader knows the function is called from outside Rux: ```rux import Core::{ #target, #Error }; import Io::PrintLine; when #target.os { .FreeBSD => const CRuntime = "libc.so.7"; .Linux => const CRuntime = "libc.so.6"; .macOS => const CRuntime = "libSystem.B.dylib"; .Windows => const CRuntime = "ucrtbase.dll"; else => #Error("unknown C runtime") } #Link(CRuntime) extern func qsort(base: *var opaque, count: uint, size: uint, compare: func(*opaque, *opaque) -> int32); // Called by C, so it promises C's convention. #Abi(.C) func Descending(left: *opaque, right: *opaque) -> int32 { let a = *(left as *int32); let b = *(right as *int32); return a > b ? -1i32 : a < b ? 1i32 : 0i32; } func Main() -> int { var values: int32[5] = [3, 9, 1, 7, 5]; qsort(@values[0] as *var opaque, values.length, sizeof(int32), Descending); PrintLine("{} {} {} {} {}", values[0], values[1], values[2], values[3], values[4]); // 9 7 5 3 1 return 0; } ``` A C convention can only carry the floating-point types C has, `float32` and `float64`. A `#Abi` function whose parameter or result is `float8`, `float16`, or `float80` or wider is refused with `parameter 'value' of '#Abi' function 'Callback' has type 'float16', which has no C ABI mapping`; see [Foreign Function Interface](https://rux-lang.dev/docs/lang/ffi/overview#floating-point-widths). ## A wrong convention is not an error The compiler cannot see what the other side expects. Pin `Descending` to `#Abi(.SysV)` and build for Windows: `qsort` passes the two addresses in `rcx` and `rdx`, the function reads `rdi` and `rsi`, and it compares whatever was there. Nothing reports it. The same holds for an `asm func` body written for one convention and pinned to another. Use `.C` for anything C calls, and pin an `asm func` to the convention its body was written for. ## See also - [Assembly](https://rux-lang.dev/docs/lang/ffi/assembly) — bodies written against a convention - [Foreign function interface](https://rux-lang.dev/docs/lang/ffi/overview) — extern declarations and function pointers - [Compile-time context](https://rux-lang.dev/docs/lang/comptime/context#target) — `#target.abi`, the target's own convention - Learn: [ABI](https://rux-lang.dev/docs/learn/abi), [Assembly](https://rux-lang.dev/docs/learn/asm) # `#NoReturn` `#NoReturn()` declares that a function never returns to its caller: it ends the program, loops forever, or transfers control somewhere else for good. The compiler uses that to check control flow — code after a call is unreachable, and a call can end a path that would otherwise need a `return`. ```text noreturn-attribute = "#NoReturn" "(" ")" ``` It applies to a function and to an `extern func`, and takes no arguments. A function that never returns has no result to declare: ```text error: '#NoReturn' function cannot declare a return type error: '#NoReturn' can only be applied to a function error: '#NoReturn' does not accept arguments ``` ## Ending a path A function with a result must return a value on every path. A call to a `#NoReturn` function counts as the end of its path: ```rux import Core::Panic; import Io::PrintLine; #NoReturn() func Fail(message: char8[..]) { PrintLine("fatal: {}", message); Panic(message); } func Digit(c: char8) -> int { if c >= c8'0' && c <= c8'9' { return (c - c8'0') as int; } Fail("not a digit"); // no return needed after this } ``` Without the attribute on `Fail`, `Digit` fails with `function 'Digit' must return a value of type 'int' on every control-flow path`. `Panic` itself is declared in `Core` as an intrinsic that never returns, and an `extern` binding of a C function such as `abort` or `exit` takes the attribute the same way: ```rux #NoReturn() #Link(CRuntime) extern func abort(); ``` An `extern { }` block cannot carry `#NoReturn` for its members; declare such a function on its own. ## The body must not return A `return` in a `#NoReturn` function is an error: ```text error: return is not allowed in a '#NoReturn' function ``` The body has to end by calling something that does not return either — `Panic`, another `#NoReturn` function, or an endless `loop`. A body that can reach its closing brace, such as one that stops after a `PrintLine`, is an error too, since a call that came back would continue into code the compiler marked unreachable: ```text error: '#NoReturn' function 'Stop' can reach the end of its body note: a call to it would come back to code that assumes it does not help: end every path with 'Panic', a call to another '#NoReturn' function, or an endless 'loop' ``` ## See also - [Panics](https://rux-lang.dev/docs/lang/errors/panics) — `Panic` and `Assert` - [Functions](https://rux-lang.dev/docs/lang/functions/declaration) — results and the every-path rule - [Foreign function interface](https://rux-lang.dev/docs/lang/ffi/overview) — extern declarations - API: [`Panic`](https://rux-lang.dev/docs/api/core/diagnostics#panic) # `#Warn` `#Warn("message")` before a declaration makes the compiler report a **warning at every call** of it, or at every use of a type or constant. The declaration stays usable and the build carries on; the warning points at the call, not at the declaration. It is the way to deprecate a function: callers see the message, with the replacement named, every time they build. ```text warn-attribute = "#Warn" "(" string-literal ")" ``` ```rux import Io::PrintLine; #Warn("Average rounds toward zero; call AverageRounded instead") func Average(total: int, count: int) -> int { return total / count; } func Main() -> int { PrintLine("{}", Average(7, 2)); return 0; } ``` ```text Src/Main.rux:9:21: warning: Average rounds toward zero; call AverageRounded instead ``` The message must be a string literal (`expected a message string in '#Warn'` otherwise). As an attribute, `#Warn` needs no import. ## What it applies to `#Warn` fires at calls of a function, a method in an `extend` block, a constructor and an `extern func`, and at a function named as a value, `let f = Average;`. On a struct, a constant, a type alias or an enum it fires at every use of the name, once per use: with `#Warn("Point is deprecated; use Vector")` on `struct Point`, both `Point { x: 1 }` and `let q: Point = p;` report `warning: Point is deprecated; use Vector`. Uses inside the declaration's own fields and `extend` blocks are not reported. ## The directive form Written as a statement in a body, or as a `when` arm, `#Warn("…")` is a directive that warns where it stands instead — see [Build diagnostics](https://rux-lang.dev/docs/lang/comptime/diagnostics). ## See also - [`#Error`](https://rux-lang.dev/docs/lang/attributes/error) — refuse every call instead of warning - [Build diagnostics](https://rux-lang.dev/docs/lang/comptime/diagnostics) — the directive form - [Attributes](https://rux-lang.dev/docs/lang/attributes/overview) — the full set - Learn: [Compile error](https://rux-lang.dev/docs/learn/compile-error) # `#Error` `#Error("message")` before a declaration makes **every call** of it, or every use of a type or constant, a compile error with that message. The declaration itself compiles; only its use is refused, and the error points at the call. It lets a function that was removed, or that cannot work on this build, explain what to call instead rather than simply vanishing. ```text error-attribute = "#Error" "(" string-literal ")" ``` ```rux #Error("Connect was removed; call Open instead") func Connect() -> int { return 0; } func Main() -> int { let k = Connect(); return 0; } ``` ```text Src/Main.rux:7:13: error: Connect was removed; call Open instead ``` A declaration nobody uses produces nothing. The message must be a string literal, and as an attribute `#Error` needs no import. ## Per-platform stubs Combined with [`when`](https://rux-lang.dev/docs/lang/comptime/conditional), the attribute turns a missing implementation into a clear message at the call, instead of a missing name or a link failure: ```rux import Core::{ #target }; when #target.os == .Windows { func OpenConsole() -> bool { return true; // the real Windows implementation } } else { #Error("OpenConsole is available on Windows only") func OpenConsole() -> bool { return false; } } ``` Every other target still compiles the package; only a program that calls `OpenConsole` there is refused. ## What it applies to Like [`#Warn`](https://rux-lang.dev/docs/lang/attributes/warn), `#Error` fires at calls of a function, a method, a constructor or an `extern func`, and at a function named as a value, `let c = Connect;`. On a struct, a constant, a type alias or an enum it fires at every use of the name, each use its own error: with `#Error("Handle was removed; use File")` on `struct Handle`, `let h: Handle = …;` is `error: Handle was removed; use File`. Uses inside the declaration's own fields and `extend` blocks are not reported. ## The directive form Written as a statement in a body or as a `when` arm, `#Error("…")` is a directive that stops the build wherever it is reached — see [Build diagnostics](https://rux-lang.dev/docs/lang/comptime/diagnostics). ## See also - [`#Warn`](https://rux-lang.dev/docs/lang/attributes/warn) — report every call without refusing it - [Build diagnostics](https://rux-lang.dev/docs/lang/comptime/diagnostics) — the directive form - [Conditional compilation](https://rux-lang.dev/docs/lang/comptime/conditional) — per-platform declarations - Learn: [Compile error](https://rux-lang.dev/docs/learn/compile-error) # `#Allow` `#Allow("rule")` switches off one [`rux lint`](https://rux-lang.dev/docs/cli/lint) rule for the declaration below it, and nowhere else. It is for a declaration with a deliberate reason to break a convention — most often a name that must match an outside contract, such as a C struct or a C macro. ```text allow-attribute = "#Allow" "(" string-literal ")" ``` ## Rules | Rule | `rux lint` reports | `#Allow` applies to | | ---------------- | ------------------------------------------------------------------------ | --------------------- | | `"naming.type"` | a struct, enum, variant, union or type alias name that is not PascalCase | type declarations | | `"naming.const"` | a constant name that is not PascalCase | constant declarations | | `"docs.missing"` | a public declaration without a `///` or `/** … */` comment | any declaration | ```rux // Mirrors the C struct, so it keeps C's spelling. #Allow("naming.type") struct timespec { seconds: int64; nanoseconds: int64; } // A C macro's own name, which a reader porting code will look for. #Allow("naming.const") const SEEK_SET: int32 = 0; ``` Without the attributes, `rux lint` reports: ```text warning: struct name 'timespec' should be PascalCase help: rename it to 'Timespec' warning: constant name 'SEEK_SET' should be PascalCase help: rename it to 'SeekSet' ``` One `#Allow` names one rule; stack several for several rules. The rule names are checked when the source is compiled, not only when it is linted, so a typo cannot silence nothing: | Mistake | Error | | --------------------------- | -------------------------------------------------------------------------------------------- | | an unknown rule | `unknown lint rule 'naming.konst'; valid rules are: naming.type, naming.const, docs.missing` | | `naming.type` on a function | `'#Allow("naming.type")' can only be applied to a type declaration` | | `naming.const` on a struct | `'#Allow("naming.const")' can only be applied to a constant declaration` | | the same rule twice | `duplicate '#Allow("naming.const")' attribute` | | two rules in one attribute | `'#Allow' accepts exactly one argument` | ## See also - [`rux lint`](https://rux-lang.dev/docs/cli/lint) — the checks these rules belong to - [Identifiers](https://rux-lang.dev/docs/lang/lexical/identifiers) — the naming conventions - Learn: [Compile error](https://rux-lang.dev/docs/learn/compile-error), [Tooling](https://rux-lang.dev/docs/learn/tooling) # `#Format` `#Format()` is the one attribute written before a **parameter**. It marks a `char8[..]` parameter as a format string, followed by a [variadic](https://rux-lang.dev/docs/lang/functions/parameters) parameter whose arguments fill its placeholders. When a call passes a string literal for it, the compiler counts the placeholders against the arguments and refuses a mismatch while compiling, rather than leaving it to fail at run time. ```text format-parameter = "#Format" "(" ")" identifier ":" "char8[..]" ``` The standard printing functions are declared this way: ```rux pub func PrintLine(#Format() format: char8[..], args: Display...) -> IoError? ``` A function of your own takes it just as well; the compiler recognizes no package or function by name, only the attribute: ```rux import Io::PrintLine; import Format::Display; func Log(level: int, #Format() format: char8[..], args: Display...) { PrintLine(format, args...); } func Main() -> int { Log(1, "{} of {}", 3, 4); // 3 of 4 Log(1, "{{}} {:x}", 255); // {} ff return 0; } ``` ## Placeholders A placeholder is `{}` or `{:spec}`; `{{` and `}}` are literal braces and count for nothing. A call whose literal has a different number of placeholders than arguments is an error: ```text error: format string has 2 placeholders, but 1 argument was provided note: format parameter 'format' of 'Log' declared at 'Src/Main.rux':4:32 help: pass one argument for each '{}' placeholder ``` Only a literal can be counted. A format held in a variable, a spread argument such as `args...`, and a spec the formatter itself would reject are left to the formatter's check at run time. ## Rules | Mistake | Error | | -------------------------------- | ----------------------------------------------------------------------- | | no variadic parameter after it | `'#Format' parameter 'format' must be followed by a variadic parameter` | | on the variadic parameter itself | `'#Format' cannot be applied to variadic parameter 'args'` | | on two parameters | `'#Format' is already applied to parameter 'a'` | | on the receiver | `'#Format' cannot be applied to the receiver 'self'` | | with an argument | `'#Format' does not accept arguments` | | another name before a parameter | `unknown parameter attribute '#Trim'` | A function has at most one format string, and the variadic parameter it counts against must be the last parameter. ## See also - [Parameters](https://rux-lang.dev/docs/lang/functions/parameters) — variadic parameters and spreads - [Attributes](https://rux-lang.dev/docs/lang/attributes/overview) — the declaration attributes - Learn: [Format](https://rux-lang.dev/docs/learn/format), [Variadic](https://rux-lang.dev/docs/learn/variadic) # `#Test` `#Test()` marks a function as a **unit test**. An ordinary build compiles it as a plain function and ignores the mark. A test build — [`rux test`](https://rux-lang.dev/docs/cli/test) — collects every marked function of the package, generates a `Main` that runs them, and reports each one as passed or failed. ```text test-attribute = "#Test" "(" ")" ``` ## A test function A test function takes no parameters, is not generic, and returns either nothing or `! TestFailure`. The checks of the standard `Test` package return `! TestFailure`, so a test hands a failed check on with `?`: ```rux import Test::{ ExpectEqual, TestFailure }; pub func Add(a: int, b: int) -> int { return a + b; } #Test() func AddsSmallNumbers() -> ! TestFailure { ExpectEqual(Add(2, 3), 5)?; } #Test() func AddsNegatives() -> ! TestFailure { ExpectEqual(Add(-2, 3), 1)?; } ``` A test passes when it returns, and fails when it returns a `TestFailure`. A panic is not a failed test: it ends the whole test program, so the tests after it never run and `rux test` reports the package as failed. The package must list `Test` under `[Dependencies]` — `Test = { Namespace = "Rux", Version = "*" }` — because the generated runner calls `Test::RunTests`. ## Where tests live Tests sit beside the code they test, in the same package, so they can call functions that are not `pub`. That works for every package type. A library has no `Main` of its own, and the test build gives it one. An executable already has a `Main`, so it cannot hold tests: move them into a library package that the executable depends on. `rux test` builds every package whose sources mark `#Test()` functions, plus every executable package under `Tests/`, and runs them all. Each test is named by its module path, `AddsSmallNumbers` here and `Parser::ReadsNumbers` for a test inside `module Parser`. Arguments after `--` go to the runner as name filters, and a test runs when any of them matches: ```sh rux test # every test rux test -- Adds # tests whose names contain "Adds" rux test -- Adds Parser # tests whose names contain either rux test -- --exact Parser::ReadsNumbers # exactly one test ``` The runner also takes `--skip`, `--list` and `--quiet`. A package with no test the filters match is reported as skipped, and `rux test` fails when no package had one, so a misspelt name never passes with nothing run. A failed check prints what it expected and what it got. Change the `1` in `AddsNegatives` to `2` and the run reports: ```text running 2 of 2 tests test AddsSmallNumbers ... ok (0.005 ms) test AddsNegatives ... FAILED expected 2, but got 1 failed: AddsNegatives result: FAILED. 1 passed, 1 failed, 0 skipped, 0 filtered out; finished in 0.202 ms ``` A test build is a build with [`#build.isTest`](https://rux-lang.dev/docs/lang/comptime/context) set to `true`, so `when #build.isTest` can include test-only helpers. ## Rules | Mistake | Error | | ----------------------------------- | ---------------------------------------------------------------------------------------------- | | arguments to the attribute | `'#Test' does not accept arguments` | | a test with parameters | `a '#Test' function takes no parameters` | | a generic test | `a '#Test' function cannot be generic` | | a test in an `extend` block | `a '#Test' function cannot be a method` | | a test inside a `when` branch | `a '#Test' function cannot be declared inside 'when'` | | any other result type | `'#Test' function 'Counts' must return nothing or '! TestFailure'` | | tests and `Main` in one package | `package 'App' declares 'Main' and '#Test()' functions; a test build generates its own 'Main'` | | tests without the `Test` dependency | `package 'App' has '#Test()' functions but does not depend on 'Test'` | The last two are reported by a test build only; an ordinary build compiles the package as usual. ## See also - [`rux test`](https://rux-lang.dev/docs/cli/test) — the command that runs tests - [Build context](https://rux-lang.dev/docs/lang/comptime/context) — `#build.isTest` - [Attributes](https://rux-lang.dev/docs/lang/attributes/overview) — every attribute - API: [the Test package](https://rux-lang.dev/docs/api/test) - Learn: [Unit tests](https://rux-lang.dev/docs/learn/unit-test) # Foreign Function Interface An `extern` declaration names a function compiled outside Rux — in the operating system or a C library — and gives its signature, with no body. Once declared, it is called like any other function. The compiler takes the declaration on trust: it cannot look inside the library, so a declaration that does not match the real function is not an error but a program that misbehaves. ```text extern-decl = attributes [ "pub" ] "extern" ( extern-func | extern-var | extern-block ) extern-func = "func" identifier "(" [ parameters [ "," "..." ] ] ")" [ "->" type ] ";" extern-var = identifier ":" type ";" extern-block = "{" { [ "pub" ] ( extern-func | extern-var ) } "}" ``` Every extern function and variable needs a [`#Link`](https://rux-lang.dev/docs/lang/attributes/link) naming its library; [Linking](https://rux-lang.dev/docs/lang/ffi/linking) covers choosing it per platform. Its calling convention is the target's C convention unless [`#Abi`](https://rux-lang.dev/docs/lang/attributes/abi) says otherwise. ## Declarations A single function: ```rux #Link("Kernel32.dll") extern func GetCurrentProcessId() -> uint32; ``` A block groups declarations from one library, with the attributes written once. Inside a block, members are written without `extern`, may each be `pub`, and take no attributes of their own: ```rux #Link(CRuntime) extern { func strlen(text: *char8) -> uint; func malloc(size: uint) -> *var opaque; func free(memory: *var opaque); } ``` An `extern` variable, `extern Name: Type;` or `Name: Type;` inside a block, declares data defined outside the program. It is read, written and addressed with `@` like a module variable: ```rux #Link("libc.so.6") extern opterr: int32; // nonzero: getopt prints its own error messages func Quiet() { opterr = 0; } ``` Like a function, it names its library with `#Link("library")` before it or on its `extern { }` block, and `#Link("library", "symbol")` before it gives it a Rux name of its own. Without one it is `extern variable 'opterr' must name the library it is imported from`. Its type must have a C ABI mapping, as a parameter's does — see [Type mapping](https://rux-lang.dev/#type-mapping). ## Example The C runtime, called directly — a formatted write, a struct returned by value, and memory from `malloc`: ```rux import Core::{ #target, #Error }; import Io::PrintLine; when #target.os { .FreeBSD => const CRuntime = "libc.so.7"; .Linux => const CRuntime = "libc.so.6"; .macOS => const CRuntime = "libSystem.B.dylib"; .Windows => const CRuntime = "msvcrt.dll"; else => #Error("unknown C runtime") } // div_t: two C ints, in C's field order. struct Div { quot: int32; rem: int32; } #Link(CRuntime) extern { func sprintf(buffer: *var char8, format: *char8, ...) -> int32; func div(numerator: int32, denominator: int32) -> Div; func malloc(size: uint) -> *var opaque; func free(memory: *var opaque); } func Main() -> int { var buffer: char8[64]; let written = sprintf(@buffer[0], "%s has %d legs".data, "spider".data, 8i32); PrintLine("{}", buffer[..written as uint]); // spider has 8 legs let d = div(17i32, 5i32); PrintLine("{} r {}", d.quot, d.rem); // 3 r 2 let memory = malloc(16) as *var char8; if memory == null { return 1; } free(memory as *var opaque); return 0; } ``` ## Type mapping A C declaration translates type by type. Rux's `int` is 64 bits, so C's `int` is `int32`, never `int`: | C | Rux | | ------------------------------------------------------------ | ---------------------------------------------------------------------------- | | `int`, `unsigned int` | `int32`, `uint32` | | `short`, `long long`, `int64_t`, … | the integer of the same width | | `long` | `int32` on Windows, `int64` elsewhere — choose with `when #target.dataModel` | | `size_t`, `uintptr_t` | `uint` | | `double`, `float` | `float64`, `float32` | | `char` (as a byte) | `char8` or `int8`/`uint8` | | `const T *` | `*T` | | `T *` written through | `*var T` | | `void *` | `*opaque` or `*var opaque` | | a pointer to a struct the code never looks inside (`FILE *`) | a pointer to an empty struct, or `*opaque` | | `struct S` by value | a Rux `struct` with the same fields in the same order | | a function pointer | a function type: `func(*opaque, *opaque) -> int32` | | `void` result | no `->` | ### Floating-point widths The C calling convention knows two floating-point types, `float` and `double`, which are `float32` and `float64`. Rux's other widths — `float8`, `float16`, `float80`, `float128`, `float256` and `float512` — are passed by the compiler's own convention, which matches no C type: not `_Float16`, not `long double`, not `__float128`. One of them as a parameter or result of an `extern` function, as a parameter or result of a function marked [`#Abi`](https://rux-lang.dev/docs/lang/attributes/abi), or as a [C-variadic](https://rux-lang.dev/#variadic-functions) argument is refused: ```text error: extern parameter 'value' has type 'float80', which has no C ABI mapping note: 'float80' is passed by the compiler's own convention, which matches no C type such as '_Float16', 'long double' or '__float128' help: convert the value to 'float32' or 'float64' at the boundary, or pass a pointer to it ``` A result is reported as `the return value of extern function 'sqrtl' has type 'float80'`, an `#Abi` function's parameter as `parameter 'value' of '#Abi' function 'Callback' has type 'float16'`, and a variadic argument as `a C-variadic argument has type 'float16'`, each with the same note and help. Convert the value to `float32` or `float64` at the boundary, or pass a pointer to it. ::note **Structures are not checked.**:br The check reads the declared type itself, so a structure passed by value that holds a `float16` or `float80` field is not diagnosed. Its layout still matches no C type; do not pass one to C. :: The `C` package declares aliases named after C's types — `c_int`, `c_long`, `size_t`, `time_t` — that resolve to the right width on each target, and binds much of the C runtime; prefer it to hand-written declarations. Struct layout follows the C rules, so a struct declared field for field matches C — see [Layout](https://rux-lang.dev/docs/lang/memory/layout). ## Strings C finds the end of a string by its zero byte. A Rux string literal keeps a NUL after its last unit — not counted by `.length` — so a literal's `.data` is a valid C string: ```rux let greeting = "hello"; let n = strlen(greeting.data); // 5, the same as greeting.length ``` That holds for **literals**. A slice cut from the middle of a string, or text built at run time, has no NUL after it unless the program writes one; handing its `.data` to C makes C read past the end. Passing a slice where C wants an address is a type error: ```text error: argument 1 to 'strlen' has type 'char8[..]', but parameter 'text' requires '*char8' ``` ## Pointers Arguments that C reads or writes through are [pointers](https://rux-lang.dev/docs/lang/pointers/overview): `@value` for one variable, `@array[0]` for the first element of a buffer, `.data` for a slice. A result C returns as `void *` is converted with `as` to the type it really points to, and checked for `null` — C reports failure with a sentinel, never with a panic or a fallible: | Function | Success | Failure | | --------- | ----------------- | ---------------- | | `malloc` | an address | `null` | | `sprintf` | the bytes written | a negative count | ## Variadic functions A trailing `...` declares a C variadic function. Any number of arguments of any type may follow the fixed ones, and **nothing** checks them against what the callee expects: pass each at exactly the type the callee will read — `8i32` for `%d`, a `float64` for `%f`, `.data` for `%s`. A wrong one builds and prints garbage. The one argument type the compiler does refuse is a [floating-point width C lacks](https://rux-lang.dev/#floating-point-widths), such as a `float16`. Rux can call a C variadic function but not define one; a Rux variadic parameter (`args: T...`) is a different, type-checked feature — see [Parameters](https://rux-lang.dev/docs/lang/functions/parameters). ## Callbacks A Rux function can be passed where C expects a function pointer, by naming it. C then calls it with C's convention, which a Rux function uses by default; mark it [`#Abi(.C)`](https://rux-lang.dev/docs/lang/attributes/abi) to keep that promise explicit. The `qsort` example on that page shows the whole round trip. ## See also - [Linking](https://rux-lang.dev/docs/lang/ffi/linking) — `#Link` and per-platform libraries - [Assembly](https://rux-lang.dev/docs/lang/ffi/assembly) — writing the machine code yourself - [Pointers](https://rux-lang.dev/docs/lang/pointers/overview) — `*T`, `*var T` and `*opaque` - API: [C package](https://rux-lang.dev/docs/api/c) · Learn: [Extern](https://rux-lang.dev/docs/learn/extern), [C interop](https://rux-lang.dev/docs/learn/c-interop), [ABI](https://rux-lang.dev/docs/learn/abi) # Linking Libraries An [`extern`](https://rux-lang.dev/docs/lang/ffi/overview) declaration says *what* a foreign function looks like; [`#Link`](https://rux-lang.dev/docs/lang/attributes/link) says *where* it lives. The Rux linker records the shared library (`.dll`, `.so`, `.dylib`) and the symbol in the executable's import tables, and the system loader finds the library when the program starts. ```rux #Link("Kernel32.dll") extern func GetCurrentProcessId() -> uint32; // the library alone #Link("Kernel32.dll", "GetTickCount64") extern func Milliseconds() -> uint64; // and the exported symbol #Link("Kernel32.dll") extern { // every member of a block func GetCurrentThreadId() -> uint32; } ``` | Form | Library | Symbol | On | | ------------------------ | ------- | -------------------------- | --------------------------- | | `#Link("lib")` | `lib` | the declaration's own name | `extern func`, `extern { }` | | `#Link("lib", "symbol")` | `lib` | `symbol` | `extern func` only | Either argument may be a string literal or the name of a string constant declared in the same package. An `extern func` without `#Link` is an error on every target (`extern function 'GetTickCount64' must specify a source DLL via #Link("dll.dll")`). ## One library per platform A library's name differs from system to system — the C runtime alone has four. Declare its name once, as a constant chosen by [`when`](https://rux-lang.dev/docs/lang/comptime/conditional), and link against the constant: ```rux import Core::{ #target, #Error }; when #target.os { .FreeBSD => const CRuntime = "libc.so.7"; .Linux => const CRuntime = "libc.so.6"; .macOS => const CRuntime = "libSystem.B.dylib"; .Windows => const CRuntime = "ucrtbase.dll"; else => #Error("unknown C runtime") } #Link(CRuntime) extern { func abs(n: int32) -> int32; func strlen(text: *char8) -> uint; } ``` | System | C runtime | | ------- | ------------------- | | Windows | `ucrtbase.dll` | | Linux | `libc.so.6` | | macOS | `libSystem.B.dylib` | | FreeBSD | `libc.so.7` | On Windows the formatted-output family (`printf`, `sprintf`, …) is not exported by `ucrtbase.dll`, which implements it as header inlines; bind those from `msvcrt.dll`. The constant must be declared in the package that links against it; a constant imported from another package — even the `C` package's own `CRuntime` — is refused with `'#Link' library name 'CRuntime' is not a compile-time constant`. ## Functions that exist on one system only When a function exists on one system only, declare it only there, and give the other targets either another implementation or an explanation. A missing branch is better than a program that builds and then cannot find its library: ```rux import Core::{ #target }; when #target.os { .Windows => { #Link("Kernel32.dll") extern func GetTickCount64() -> uint64; func Uptime() -> uint64 { return GetTickCount64() / 1000; } }, else => { #Error("Uptime is implemented for Windows only") func Uptime() -> uint64 { return 0; } } } ``` The declarations in an untaken branch are never resolved, so a library that does not exist on the target never reaches the linker. The [`#Error`](https://rux-lang.dev/docs/lang/attributes/error) attribute makes a call to `Uptime` on any other system a compile error that says why. ## Renaming a symbol The second argument binds a Rux name to an export with a different name — a terse C name to a readable one, or one entry point to two Rux signatures: ```rux #Link(CRuntime, "abs") extern func AbsoluteValue(n: int32) -> int32; ``` `AbsoluteValue(-7)` calls the library's `abs`. One symbol cannot stand for every member of a block, so this form applies to a single `extern func`. ## What is checked The compiler cannot open the library. Building for Windows, the linker does check that the named DLL exports each symbol, and a misspelt name stops the build: ```text error: cannot link PE/COFF executable 'Extern': import function 'GetCurrentProcessID' was not found in DLL 'Kernel32.dll' ``` For Linux, macOS and FreeBSD the name is resolved by the dynamic loader when the program is loaded. Neither check covers the signature: parameter and result types are taken on trust everywhere. `rux build --target <name>` links for any of the eight targets from any host, so every branch of a per-platform `when` can be linked without the other systems at hand. ## See also - [Foreign function interface](https://rux-lang.dev/docs/lang/ffi/overview) — extern declarations and C types - [`#Link`](https://rux-lang.dev/docs/lang/attributes/link) — the attribute reference - [Conditional compilation](https://rux-lang.dev/docs/lang/comptime/conditional) — per-platform declarations - Learn: [Extern](https://rux-lang.dev/docs/learn/extern), [ABI](https://rux-lang.dev/docs/learn/abi) # Assembly Functions An `asm func` is a function whose body is processor instructions instead of statements. Its signature is ordinary Rux, and callers call it like any function; its body is assembled by the compiler's own assembler and emitted exactly as written — no prologue, no epilogue, no checks. Use one for an instruction the language cannot express, a system-call stub, or exact control over a hot loop, and expect to manage registers, the stack and the calling convention yourself. ```text asm-func = attributes [ "pub" ] "asm" "func" identifier "(" [ parameters ] ")" [ "->" type ] "{" { asm-item } "}" asm-item = label ":" | mnemonic [ operand { "," operand } ] ``` `asm` is not a keyword; it means this only directly before `func`. Instructions are separated by nothing but whitespace — one per line by convention — and `//` and `/* … */` comments are allowed. Mnemonics and register names are case-insensitive. ## The body works on registers The parameters fix the signature and the convention callers use, but they are **not names inside the body**. The arguments are in whatever registers the convention puts them in, and the result goes where the convention says: ```rux // Win64: the first two integers arrive in rcx and rdx; the result goes back in rax. #Abi(.Win64) asm func Add(a: int64, b: int64) -> int64 { mov rax, rcx add rax, rdx ret } ``` Naming a parameter is an operand error (`add rax, b` fails with `unsupported operands for 'add'`). Nothing is added around the body, not even the `ret`: leave it out and execution runs on into whatever bytes follow. Preserving callee-saved registers and keeping the stack aligned across a `call` are the body's job. ## Choosing the convention Without [`#Abi`](https://rux-lang.dev/docs/lang/attributes/abi) an `asm func` uses the target's C convention, so a body that reads `rcx` is right on Windows and wrong on Linux. Pin every x86-64 body to the convention it was written for — `#Abi(.Win64)` or `#Abi(.SysV)` — and it works on every x86-64 system, because the compiler adapts each call to it: | Convention | Integer arguments | Float arguments | Result | | ---------- | -------------------------------------- | --------------- | -------------- | | Win64 | `rcx`, `rdx`, `r8`, `r9` | `xmm0`–`xmm3` | `rax` / `xmm0` | | System V | `rdi`, `rsi`, `rdx`, `rcx`, `r8`, `r9` | `xmm0`–`xmm7` | `rax` / `xmm0` | | AAPCS64 | `x0`–`x7` | `d0`–`d7` | `x0` / `d0` | AArch64 has the one convention on every system, so its bodies carry no `#Abi`. ## Labels A label is a name followed by `:`, and jumps and branches name it. Labels belong to their function, so two functions may both use `next:`: ```rux // The sum 1 + 2 + … + n, as a label and a conditional jump. #Abi(.Win64) asm func SumTo(n: int64) -> int64 { xor rax, rax next: test rcx, rcx jle done add rax, rcx dec rcx jmp next done: ret } ``` A name that is neither a register nor a label is a **symbol**: another function, which `call` and `jmp` reach through a relocation the linker resolves, or a module variable. Every name a body reaches must be a label of the body, a function or a module variable; anything else — a misspelt label, a constant, a parameter, a thread-local or an extern variable — is an error: ```text error: 'dnoe' in asm func 'Names' is not a label, a function or a module variable help: define the label in the body, or declare the function or module variable it names ``` A constant, a parameter, a thread-local variable or an extern variable adds a note saying why it has no address the body can name, such as `'Limit' is a constant, which has no storage`. An overloaded or a generic function has no single address either, and is `'Twice' in asm func 'Names' names no single function`. On x86-64 a module variable is read or written relative to the next instruction, `mov rax, qword [rip + Counter]`. A symbol beside a base or index register, or alone in the brackets, has no encoding: ```text error: 'Counter' in a memory operand is reached relative to 'rip', so the operand must be '[rip + Counter]' ``` ## One architecture per body An asm body belongs to one architecture, and the compiler checks every mnemonic against the target's: ```text error: 'csel' is an AArch64 instruction, but asm func 'A' is compiled for x86-64 ``` A package that supports both architectures writes one body per architecture and lets [`when`](https://rux-lang.dev/docs/lang/comptime/conditional) keep the right one. The untaken body is parsed but never assembled: ```rux import Core::{ #target, #Error }; when #target.arch { .X86_64 => { #Abi(.SysV) asm func Add(a: int64, b: int64) -> int64 { mov rax, rdi add rax, rsi ret } }, .AArch64 => { asm func Add(a: int64, b: int64) -> int64 { add x0, x0, x1 ret } }, else => #Error("no assembly for this architecture") } ``` Mnemonic and operand checks run when the body is **assembled**, which `rux build` does and `rux check` does not. Build for each architecture — `rux build --target linux-aarch64` works on any host — to have every body assembled. ## x86-64 Intel syntax: the destination is the first operand. | Operand | Written as | | --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- | | register | `rax`…`r15`, `eax`…`r15d`, `ax`…`r15w`, `al`…`r15b` (with `spl`, `bpl`, `sil`, `dil`), `ah`, `bh`, `ch`, `dh`, `xmm0`…`xmm15` | | immediate | `42`, `-1`, `0x10`, `0o7`, `0b1010`, `1_000` | | memory | `[base + index*scale ± disp]`, any part optional, `scale` 1, 2, 4 or 8; a size prefix `byte`, `word`, `dword` or `qword` where the width is otherwise unclear | | symbol | a function name, as in `call Helper` | ```rux #Abi(.Win64) asm func Index(values: *int64, i: int64) -> int64 { mov rax, qword [rcx + rdx*8] ret } ``` The assembler encodes a chosen subset of x86-64: | Family | Instructions | | ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | | data movement | `mov`, `movzx`, `movsx`, `movsxd`, `lea`, `push`, `pop` | | integer arithmetic | `add`, `adc`, `sub`, `sbb`, `inc`, `dec`, `neg`, `mul`, `imul`, `div`, `idiv`, `cmp` | | logic, shifts, rotates | `and`, `or`, `xor`, `not`, `test`, `shl`, `sal`, `shr`, `sar`, `rol`, `ror` (count an immediate or `cl`) | | sign extension | `cdq`, `cqo`, `cdqe` | | control flow | `jmp`, `jcc` (`je`, `jne`, `jl`, `jge`, `jb`, `ja`, …), `setcc` (`sete`, `setl`, …), `call`, `ret`, `leave`, `nop` | | system | `syscall`, `int`, `int3` | | SSE moves | `movd`, `movq`, `movss`, `movsd`, `movaps`, `movapd`, `movups`, `movupd` | | SSE arithmetic | `add`, `sub`, `mul`, `div`, `min`, `max`, `sqrt` in `ss`, `sd`, `ps` and `pd` forms (`addsd`, `sqrtps`, …) | | SSE compare and convert | `comiss`, `comisd`, `ucomiss`, `ucomisd`, `cvtsi2ss`, `cvtsi2sd`, `cvtss2si`, `cvtsd2si`, `cvttss2si`, `cvttsd2si`, `cvtss2sd`, `cvtsd2ss` | | SSE bitwise and integer | `andps`, `andpd`, `andnps`, `andnpd`, `orps`, `orpd`, `xorps`, `xorpd`, `pand`, `por`, `pxor`, `paddb`/`w`/`d`/`q`, `psubb`/`w`/`d`/`q`, `pmullw` | Other x86-64 instructions — `cmovcc`, `popcnt`, `bsf`, `cpuid`, `xchg`, the string instructions, the x87 stack and more — are recognized but not encoded: ```text error: instruction 'popcnt' is recognized for target 'windows-x86_64' but is not implemented by its assembler note: this is an internal compiler limitation, not malformed inline assembly ``` A misspelling is answered with the nearest real name: `unknown instruction 'movx'; did you mean 'mov'?`. ## AArch64 Most instructions take a destination and two sources (`add x0, x0, x1`), and an immediate is written with `#`. | Operand | Written as | | --------- | ---------------------------------------------------------------------------------------------------------------------------------------- | | register | `x0`–`x30`, `w0`–`w30`, `xzr`, `wzr`, `sp`, `wsp`, `fp` (`x29`), `lr` (`x30`); `b`, `h`, `s`, `d`, `q` `0`–`31` for the vector registers | | immediate | `#1`, `#-1`, `#0xF`; a shift or extend after a comma: `#0x1234, lsl #16`, `x1, lsl #3` | | memory | `[x0]`, `[x0, #8]`, `[x0, x1]`, `[x0, x1, lsl #3]`, `[x0, w1, sxtw #2]`; pre-index `[sp, #-16]!`; post-index `[sp], #16` | | condition | as a branch suffix, `b.lt` or `blt`; or as an operand, `csel x0, x0, x1, gt` | | symbol | a function name, as in `bl Twice` | ```rux asm func Max(a: int64, b: int64) -> int64 { cmp x0, x1 csel x0, x0, x1, gt ret } asm func Element(values: *int32, i: int32) -> int64 { ldrsw x0, [x0, w1, sxtw #2] ret } asm func Twice(x: int64) -> int64 { lsl x0, x0, #1 ret } asm func TwiceThenAddOne(x: int64) -> int64 { stp x29, x30, [sp, #-16]! mov x29, sp bl Twice add x0, x0, #1 ldp x29, x30, [sp], #16 ret } ``` A body that calls another function must save and restore `x30`, the link register, as `TwiceThenAddOne` does; AAPCS64 also gives no red zone, so a body opens its own stack space before storing below `sp`. | Family | Instructions | | -------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | arithmetic | `add`, `adds`, `sub`, `subs`, `neg`, `negs`, `cmp`, `cmn`, `mul`, `madd`, `msub`, `mneg`, `smull`, `umull`, `smulh`, `umulh`, `smaddl`, `umaddl`, `sdiv`, `udiv` | | logic and bits | `and`, `ands`, `orr`, `orn`, `eor`, `eon`, `bic`, `bics`, `mvn`, `tst`, `lsl`, `lsr`, `asr`, `ror` (and `…v` forms), `clz`, `cls`, `rbit`, `rev`, `rev16`, `rev32`, `extr`, `bfi`, `bfxil`, `bfm`, `sbfm`, `ubfm`, `sbfx`, `ubfx`, `sxtb`, `sxth`, `sxtw`, `uxtb`, `uxth` | | moves | `mov`, `movz`, `movn`, `movk`, `adr`, `adrp`, `mrs`, `msr` | | conditional | `csel`, `csinc`, `csinv`, `csneg`, `cset`, `csetm`, `cinc`, `cinv`, `cneg` | | memory | `ldr`, `ldrb`, `ldrh`, `ldrsb`, `ldrsh`, `ldrsw`, `ldur…`, `str`, `strb`, `strh`, `stur…`, `ldp`, `stp` | | branches | `b`, `b.cond`, `bl`, `br`, `blr`, `ret`, `cbz`, `cbnz`, `tbz`, `tbnz` | | system | `svc`, `brk`, `hlt`, `hint`, `nop`, `dmb`, `dsb`, `isb`, `udf` | | floating point | `fadd`, `fsub`, `fmul`, `fdiv`, `fsqrt`, `fabs`, `fneg`, `fmin`, `fmax`, `fminnm`, `fmaxnm`, `fmadd`, `fmsub`, `fnmadd`, `fnmsub`, `fcmp`, `fcmpe`, `fccmp`, `fcsel`, `fmov`, `fcvt`, `fcvtzs`, `fcvtzu`, `scvtf`, `ucvtf`, `frinta`, `frintm`, `frintn`, `frintp`, `frintz` | `fmov` takes registers only; a floating-point immediate such as `#0.5` is not accepted. Instructions outside this set — atomics, `ccmp`, `prfm`, the cache and TLB maintenance instructions and others — are recognized but not encoded, as on x86-64. Operand mistakes name the form the instruction takes: ```text error: 'add' takes 3 operands, found 2; the form is 'ADD Rd, Rn, #imm | Rd, Rn, Rm{, shift #amount}' ``` A name as the last operand of `add`, or as the offset of `[Xn, symbol]`, is the low 12 bits of that symbol's address, and completes an `adrp` of the same symbol: `adrp x0, Counter` then `add x0, x0, Counter` or `ldr x0, [x0, Counter]`. The name follows the same rule as any other, so `add x0, x0, banana` is `'banana' in asm func 'Bad' is not a label, a function or a module variable`. ## See also - [`#Abi`](https://rux-lang.dev/docs/lang/attributes/abi) — the conventions a body is written against - [Conditional compilation](https://rux-lang.dev/docs/lang/comptime/conditional) — per-architecture bodies - [Compile-time context](https://rux-lang.dev/docs/lang/comptime/context#target) — `#target.arch` - [RCU](https://rux-lang.dev/docs/lang/appendix/rcu) — how an assembled body and its relocations are stored - Learn: [Assembly](https://rux-lang.dev/docs/learn/asm), [ARM assembly](https://rux-lang.dev/docs/learn/asm-arm) # Layout Every type has a **size**, the number of bytes one value occupies, and an **alignment**: a value of the type must sit at an address that is a multiple of it. The compiler fixes both for every type, and two operators report them. ```text size-query = "sizeof" "(" type ")" alignment-query = "alignof" "(" type ")" ``` ```rux let bytes = sizeof(int64) * 4; // 32 let align = alignof(float32); // 4 ``` ## `sizeof` and `alignof` `sizeof(T)` and `alignof(T)` take a type, not a value, and produce a `uint64` that is known at compile time. They can initialise a [constant](https://rux-lang.dev/docs/lang/bindings/constants) and appear in a [`when`](https://rux-lang.dev/docs/lang/comptime/conditional) condition, and they are the way to compute an allocation's size: multiply a count by `sizeof(T)`, never by a number written down. ```rux const Record: uint64 = sizeof(int64) * 4; func Main() -> int { when sizeof(int) == 8 { PrintLine("int is 64-bit on this target"); } return 0; } ``` A type whose layout is not known has no size — a [flexible tail](https://rux-lang.dev/docs/lang/arrays/overview#flexible-tails) on its own, for one: ```text error: cannot determine the size of type 'uint8[]' note: 'sizeof' needs a type whose layout is known at compile time ``` `sizeof`, `alignof` and constants computed from them work wherever a compile-time integer is required, including an array length and a repeat count: `uint8[sizeof(int64)]` is eight bytes, and `[0u8; alignof(float32)]` holds four. ## Primitive types Every supported target is 64-bit, so these values are the same on all of them. Treat them as facts about the target, nonetheless, and ask `sizeof` and `alignof` rather than writing them into a program. | Type | Size | Alignment | | ---------------------------------------------------------------- | ---- | --------- | | `bool8`, `int8`, `uint8`, `char8`, `float8` | 1 | 1 | | `bool16`, `int16`, `uint16`, `char16`, `float16` | 2 | 2 | | `bool32`, `int32`, `uint32`, `char32`, `float32` | 4 | 4 | | `bool64`, `int64`, `uint64`, `char64`, `float64`, `int`, `uint` | 8 | 8 | | `bool128`, `int128`, `uint128`, `char128`, `float80`, `float128` | 16 | 16 | | `bool256`, `int256`, `uint256`, `char256`, `float256` | 32 | 16 | | `bool512`, `int512`, `uint512`, `char512`, `float512` | 64 | 16 | | `*T`, `*var T`, `&T`, `&var T`, a function value | 8 | 8 | | `()` | 0 | 1 | A `float80` holds 80 bits of value in 16 bytes; the other six bytes are padding. The aliases have the sizes of what they name: `bool` is 1, `byte` is 1, `char` is 4 and `float` is 8. See [Primitive types](https://rux-lang.dev/docs/lang/appendix/primitives). ## Structs: natural alignment and padding A struct keeps its fields **in the order they are declared**, and each field is placed at the next offset that is a multiple of its own alignment. Unused bytes left in between are *padding*. The struct's alignment is the largest alignment of its fields, and its size is rounded up to a multiple of that alignment, so that in an array every element is aligned too. A struct containing `uint8` followed by `int128` places its second field at offset 16, has alignment 16 and occupies 32 bytes. All primitives stored in 16 bytes or more use alignment 16, including `float80`. The same three fields therefore cost different amounts in different orders: ```rux struct Loose { flag: bool; total: int64; mark: uint8; } struct Tight { total: int64; flag: bool; mark: uint8; } func Main() -> int { PrintLine("Loose {} {}", sizeof(Loose), alignof(Loose)); PrintLine("Tight {} {}", sizeof(Tight), alignof(Tight)); var loose = Loose { flag: true, total: 1, mark: 2 }; let start = @loose as uint; PrintLine("flag at {}, total at {}, mark at {}", (@loose.flag as uint) - start, (@loose.total as uint) - start, (@loose.mark as uint) - start); PrintLine("Loose[4] {}, Tight[4] {}", sizeof(Loose[4]), sizeof(Tight[4])); return 0; } ``` ```text Loose 24 8 Tight 16 8 flag at 0, total at 8, mark at 16 Loose[4] 96, Tight[4] 64 ``` ```mermaid flowchart TB subgraph loose["`Loose` — 24 bytes"] direction LR l1["`flag`<br/>0"] --- l2["padding<br/>1–7"] --- l3["`total`<br/>8–15"] --- l4["`mark`<br/>16"] --- l5["padding<br/>17–23"] end subgraph tight["`Tight` — 16 bytes"] direction LR t1["`total`<br/>0–7"] --- t2["`flag`<br/>8"] --- t3["`mark`<br/>9"] --- t4["padding<br/>10–15"] end ``` The compiler never reorders fields. Declaring the widest fields first usually leaves the least padding. A [tuple](https://rux-lang.dev/docs/lang/tuples/overview) is laid out the same way, its elements in order: `(int8, int16, int8)` is 6 bytes, aligned to 2. ## Arrays An array `T[N]` is its `N` elements side by side, each `sizeof(T)` bytes from the last, with nothing between them: `sizeof(T[N])` is `N * sizeof(T)`, and its alignment is `T`'s. The padding inside each element is what keeps the next one aligned, so [pointer arithmetic](https://rux-lang.dev/docs/lang/pointers/arithmetic) and indexing both step by `sizeof(T)`. A **flexible tail** `T[]`, the last field of a struct, contributes its alignment and no storage. With `struct Packet { length: uint16; bytes: uint32[]; }`, `sizeof(Packet)` is 4 and `alignof(Packet)` is 4: the tail begins at offset 4, where the allocation continues. See [Arrays](https://rux-lang.dev/docs/lang/arrays/overview#flexible-tails). ## Zero-sized types `()`, an empty struct, and an aggregate made only of them occupy no bytes and have alignment 1. A zero-sized field takes no room in its struct: with `struct Marker {}`, a `struct Tagged { id: int32; marker: Marker; flag: bool; }` is 8 bytes, exactly as it would be without `marker`. ## Views, ranges and interface values | Type | Size | Alignment | Contents | | ----------------------------------- | --------------- | ------------ | ---------------------------------------- | | `T[..]`, `var T[..]` | 16 | 8 | `.data` at 0, `.length` at 8 | | `a..b`, `a..=b` of a bound type `B` | `2 * sizeof(B)` | `alignof(B)` | `.start`, then `.end` | | `a..`, `..b`, `..=b` | `sizeof(B)` | `alignof(B)` | the one bound | | `..` | 0 | 1 | nothing | | an interface value | 16 | 8 | two words: the data and its method table | A slice's elements and an interface value's data live elsewhere and are not part of these sizes. ## Optionals, fallibles and sums Each level of an [optional](https://rux-lang.dev/docs/lang/optionals/overview) `T?`, a [fallible](https://rux-lang.dev/docs/lang/errors/overview) `T ! E` and a [sum](https://rux-lang.dev/docs/lang/sums/overview) `A | B` is a tagged aggregate: an **8-byte tag at offset 0**, followed by the payload of the active case at the first offset after the tag that suits the payload's alignment. The size is that of the tag plus the largest payload, rounded up to the alignment. A zero-sized payload reserves nothing, so `()?` is the tag alone. | Type | Size | Alignment | | --------------------------------------------- | ---- | --------- | | `()?` | 8 | 8 | | `uint8?`, `int32?`, `int64?` | 16 | 8 | | `(*int)?` | 16 | 8 | | `int32??` | 24 | 8 | | `int32 ! E`, with `E` a struct of one `int32` | 16 | 8 | | `int32 | float64` | 16 | 8 | Nested levels never share a tag: `int32??` is an outer tag in front of a whole `int32?`. Absent is tag 0 and present tag 1; success is 0 and failure 1; a sum's members are numbered in their canonical order. These numbers describe what the compiler does today and are not a stable binary interface — never write a tag to a file or hand it to foreign code. A [`variant`](https://rux-lang.dev/docs/lang/variants/overview) is likewise a private tag followed by storage for its widest case, and an [`enum`](https://rux-lang.dev/docs/lang/enums/overview) is exactly its base integer type: an `enum Small: uint8` is 1 byte, an enum with no base type is 8. ## Unions A [union](https://rux-lang.dev/docs/lang/unions/overview) overlays its members: every member starts at offset 0, and the union is as large as its largest member, rounded up to the largest alignment. It stores no tag, so writing one member and reading another reinterprets the same bytes: ```rux union Bits { whole: uint32, bytes: uint8[4] } union Uneven { small: uint8, large: uint64 } func Main() -> int { PrintLine("{} {}", sizeof(Bits), sizeof(Uneven)); // 4 8 var bits = Bits { whole: 0x01020304u32 }; PrintLine("{}", bits.bytes[0]); // 4 on a little-endian target return 0; } ``` ## See also - [Arrays](https://rux-lang.dev/docs/lang/arrays/overview) — `T[N]` and flexible tails - [Structs](https://rux-lang.dev/docs/lang/structs/overview) — field declarations - [Unions](https://rux-lang.dev/docs/lang/unions/overview) — overlapping storage - [Pointer arithmetic](https://rux-lang.dev/docs/lang/pointers/arithmetic) — offsets scaled by `sizeof` - [Foreign functions](https://rux-lang.dev/docs/lang/ffi/overview) — layout at a C boundary - Learn: [Layout](https://rux-lang.dev/docs/learn/layout), [Union](https://rux-lang.dev/docs/learn/union), [Raw memory](https://rux-lang.dev/docs/learn/raw-memory) # Atomics An ordinary load or store may be split, reordered or removed by the compiler and the processor. That is harmless while one thread owns the memory, and wrong the moment two threads share it. The *atomic operations* in `Core` are compiled to the instructions each architecture provides for shared memory, so no thread ever sees one half done. ```rux import Core::{ AtomicFetchAdd, AtomicLoad, MemoryOrder }; var Hits: uint64 = 0; func Record() { AtomicFetchAdd<uint64>(@Hits, 1, MemoryOrder::Relaxed); } func Total() -> uint64 { return AtomicLoad<uint64>(@Hits, MemoryOrder::Acquire); } ``` They act on one value of 8, 16, 32 or 64 bits — an integer, a `bool` or a pointer — through its address, which must be aligned to its size. Every thread that touches the value must reach it only through atomic operations. The `Rux/Atomic` package wraps them in an `Atomic<T>` type; they live in `Core` because only the compiler can emit them. ## Operations | Intrinsic | Does, as one indivisible step | Returns | | ------------------------------------------------------------------------ | ------------------------------------------------------- | --------------------- | | `AtomicLoad<T>(address, order)` | reads the value | the value | | `AtomicStore<T>(address, value, order)` | writes `value` | nothing | | `AtomicExchange<T>(address, value, order)` | writes `value` | the value it replaced | | `AtomicCompareExchange<T>(address, expected, desired, success, failure)` | writes `desired` if the value is `expected` | the value it found | | `AtomicFetchAdd`, `AtomicFetchSub` | adds or subtracts, wrapping on overflow (integers only) | the value before | | `AtomicFetchAnd`, `AtomicFetchOr`, `AtomicFetchXor` | combines bitwise (integers and `bool`) | the value before | `AtomicCompareExchange` wrote exactly when the value it returns equals `expected`, so a retry loop starts again from what was really there. It never fails spuriously. ## Memory orderings Every operation takes a `MemoryOrder`, which says which of the thread's other memory operations may be reordered across it: | Order | Guarantees | | ------------------------ | --------------------------------------------------------------------------------------------------------------- | | `Relaxed` | the operation itself is atomic; nothing around it is held back — right for a counter no other memory depends on | | `Acquire` | later operations are not moved before this load, so what a releasing thread wrote before its release is visible | | `Release` | earlier operations are not moved after this store, so they are visible to a thread that acquires what it stores | | `AcquireRelease` | both, for a read-modify-write operation that reads and writes | | `SequentiallyConsistent` | `AcquireRelease`, and one order of every such operation that all threads agree on | The weakest ordering that keeps a program correct is also the fastest, and a stronger one is never wrong. When in doubt, use `SequentiallyConsistent`. The order is written at the call as a `MemoryOrder` case, because the compiler chooses the instructions from it while compiling. A value computed at run time is refused: ```text error: the memory order of 'AtomicLoad' must be written as a 'MemoryOrder' case help: write the order at the call, such as 'MemoryOrder::Acquire' ``` A load cannot release and a store cannot acquire, so `AtomicLoad` takes only `Relaxed`, `Acquire` or `SequentiallyConsistent`, and `AtomicStore` only `Relaxed`, `Release` or `SequentiallyConsistent`: ```text error: 'AtomicStore' cannot use memory order 'Acquire' note: a store only writes, so it cannot acquire ``` For `AtomicCompareExchange`, `success` orders the operation when it writes and `failure` when it only reads; `failure` may not be `Release` or `AcquireRelease`, nor acquire more than `success` does. ## Fences and spin hints `Fence(order)` orders the thread's memory operations without touching memory, for code that pairs relaxed operations with one ordering point. `SpinHint()` tells the processor the thread is waiting in a loop for another thread: it saves power and lets a sibling hardware thread run, and has no effect on memory. A loop that may wait long should block instead, through the `Rux/Sync` package. ## On each architecture On x86-64, loads and weaker stores are plain `mov` instructions and the other operations are `lock`-prefixed. On AArch64, the acquire and release forms of loads and stores are used, and read-modify-write operations run in exclusive-access loops. ## See also - [Module variables](https://rux-lang.dev/docs/lang/bindings/module-variables) — storage every thread shares, and `thread var` for storage each thread owns - [Layout](https://rux-lang.dev/docs/lang/memory/layout) — sizes and alignments # Primitive Types Every primitive type in Rux, by family — 38 of them, every one implemented by rux 0.4.0. The names are predefined type names, not [keywords](https://rux-lang.dev/docs/lang/lexical/keywords). | Type | Family | Bits | Bytes | Holds | Literal | | ---------- | ---------------- | ---- | ----- | ---------------------------------------------------- | ----------------- | | `int8` | Signed integer | 8 | 1 | −128 to 127 | `i8` | | `int16` | Signed integer | 16 | 2 | −32,768 to 32,767 | `i16` | | `int32` | Signed integer | 32 | 4 | −231 to 231 − 1 | `i32` | | `int64` | Signed integer | 64 | 8 | −263 to 263 − 1 | `i64` | | `int128` | Signed integer | 128 | 16 | −2127 to 2127 − 1 | `i128` | | `int256` | Signed integer | 256 | 32 | −2255 to 2255 − 1 | `i256` | | `int512` | Signed integer | 512 | 64 | −2511 to 2511 − 1 | `i512` | | `int` | Signed integer | 64 | 8 | Pointer-sized; as `int64` on every supported target | `i`, or none | | `uint8` | Unsigned integer | 8 | 1 | 0 to 255 | `u8` | | `uint16` | Unsigned integer | 16 | 2 | 0 to 65,535 | `u16` | | `uint32` | Unsigned integer | 32 | 4 | 0 to 232 − 1 | `u32` | | `uint64` | Unsigned integer | 64 | 8 | 0 to 264 − 1 | `u64` | | `uint128` | Unsigned integer | 128 | 16 | 0 to 2128 − 1 | `u128` | | `uint256` | Unsigned integer | 256 | 32 | 0 to 2256 − 1 | `u256` | | `uint512` | Unsigned integer | 512 | 64 | 0 to 2512 − 1 | `u512` | | `uint` | Unsigned integer | 64 | 8 | Pointer-sized; as `uint64` on every supported target | `u` | | `float8` | Floating-point | 8 | 1 | E4M3, with infinities and NaNs | `f8` | | `float16` | Floating-point | 16 | 2 | IEEE 754 binary16 | `f16` | | `float32` | Floating-point | 32 | 4 | IEEE 754 binary32 | `f32` | | `float64` | Floating-point | 64 | 8 | IEEE 754 binary64 | `f64`, or none | | `float80` | Floating-point | 80 | 16 | x87 extended precision, 80 bits in 16 bytes | `f80` | | `float128` | Floating-point | 128 | 16 | IEEE 754 binary128 | `f128` | | `float256` | Floating-point | 256 | 32 | IEEE 754 binary256 | `f256` | | `float512` | Floating-point | 512 | 64 | binary512: 23-bit exponent, 489 bits of precision | `f512` | | `bool8` | Boolean | 8 | 1 | `false`, `true` | `true`, `false` | | `bool16` | Boolean | 16 | 2 | `false`, `true` | — | | `bool32` | Boolean | 32 | 4 | `false`, `true` | — | | `bool64` | Boolean | 64 | 8 | `false`, `true` | — | | `bool128` | Boolean | 128 | 16 | `false`, `true` | — | | `bool256` | Boolean | 256 | 32 | `false`, `true` | — | | `bool512` | Boolean | 512 | 64 | `false`, `true` | — | | `char8` | Character | 8 | 1 | A UTF-8 code unit, 0 to 255 | `c8'…'` | | `char16` | Character | 16 | 2 | A UTF-16 code unit, 0 to 65,535 | `c16'…'` | | `char32` | Character | 32 | 4 | A Unicode scalar value | `c32'…'`, or none | | `char64` | Character | 64 | 8 | A Unicode scalar value | `c64'…'` | | `char128` | Character | 128 | 16 | A Unicode scalar value | `c128'…'` | | `char256` | Character | 256 | 32 | A Unicode scalar value | `c256'…'` | | `char512` | Character | 512 | 64 | A Unicode scalar value | `c512'…'` | ## Built-in aliases | Alias | Same type as | | ------- | ------------ | | `bool` | `bool8` | | `byte` | `uint8` | | `char` | `char32` | | `float` | `float64` | An alias is another name for its target, not a separate type; see [Type Aliases](https://rux-lang.dev/docs/lang/types/aliases#built-in-aliases). ## Defaults - An unsuffixed integer literal is an `int`, unless its context requires another integer type. - An unsuffixed floating-point literal is a `float64`. - An unprefixed character literal is a `char32`, unless it initialises a `char8` or `char16`. - An unprefixed string literal is a `char8[..]`. ## Associated constants Each primitive is extended with constants in `Core`, available once that extension is imported, as in `import Core::int32;`. The types themselves are built in and need no import: | Family | Constants | | -------------- | ----------------------------------------------------------------------------- | | Integers | `Bits`, `Bytes`, `Min`, `Max` | | Floating-point | `Bits`, `Bytes`, `Lowest`, `Max`, `MinPositive`, `Epsilon`, `Infinity`, `NaN` | | Booleans | `Bits`, `Bytes` | | Characters | `Bits`, `Bytes`, `Min`, `Max` | ## See also - [Types](https://rux-lang.dev/docs/lang/types/overview) — conversions and type expressions - [Integers](https://rux-lang.dev/docs/lang/types/integers), [Floating-Point](https://rux-lang.dev/docs/lang/types/floating-point), [Booleans](https://rux-lang.dev/docs/lang/types/booleans), [Characters](https://rux-lang.dev/docs/lang/types/characters) - [Literals](https://rux-lang.dev/docs/lang/lexical/literals) — suffixes and prefixes # Token Reference The lexer turns a source file into a sequence of tokens, reading each one by the [longest-match rule](https://rux-lang.dev/docs/lang/lexical/source-files#tokens). This page lists every token kind under the name the compiler gives it. ## Literals | Token | Examples | See | | --------------- | ------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------- | | `IntLiteral` | `42`, `0xFF`, `0o77`, `0b1010`, `200u8` | [Integer literals](https://rux-lang.dev/docs/lang/lexical/literals#integer-literals) | | `FloatLiteral` | `3.14`, `1.0e-9`, `0.5f32` | [Floating-point literals](https://rux-lang.dev/docs/lang/lexical/literals#floating-point-literals) | | `StringLiteral` | `"hello"`, `c8"hello"`, `c16"hello"`, `c32"hello"` | [String literals](https://rux-lang.dev/docs/lang/lexical/literals#string-literals) | | `CharLiteral` | `'A'`, `'\n'`, `c8'A'`, `c16'A'`, `c32'A'`, `c64'A'`, `c128'A'`, `c256'A'`, `c512'A'` | [Character literals](https://rux-lang.dev/docs/lang/lexical/literals#character-literals) | | `BoolLiteral` | `true`, `false` | [Boolean literals](https://rux-lang.dev/docs/lang/lexical/literals#boolean-literals) | A numeric suffix and a character or string prefix are part of the literal's token. ## Identifiers | Token | Examples | | ------------ | ------------------------ | | `Identifier` | `count`, `Point`, `_tmp` | Contextual words such as `asm`, `sizeof` and `Self` are identifiers to the lexer; see [Keywords](https://rux-lang.dev/docs/lang/lexical/keywords#contextual-words). ## Keywords | Token | Spelling | Token | Spelling | | ----------------- | ---------- | ------------------ | ----------- | | `AsKeyword` | `as` | `InterfaceKeyword` | `interface` | | `BreakKeyword` | `break` | `IntrinsicKeyword` | `intrinsic` | | `CatchKeyword` | `catch` | `IsKeyword` | `is` | | `ConstKeyword` | `const` | `LetKeyword` | `let` | | `ContinueKeyword` | `continue` | `LoopKeyword` | `loop` | | `DeferKeyword` | `defer` | `MatchKeyword` | `match` | | `DoKeyword` | `do` | `ModuleKeyword` | `module` | | `ElseKeyword` | `else` | `NoneKeyword` | `none` | | `EnumKeyword` | `enum` | `NullKeyword` | `null` | | `ExtendKeyword` | `extend` | `PubKeyword` | `pub` | | `ExternKeyword` | `extern` | `ReturnKeyword` | `return` | | `FailKeyword` | `fail` | `SelfKeyword` | `self` | | `ForKeyword` | `for` | `StructKeyword` | `struct` | | `FuncKeyword` | `func` | `TypeKeyword` | `type` | | `IfKeyword` | `if` | `UnionKeyword` | `union` | | `ImportKeyword` | `import` | `VarKeyword` | `var` | | `InKeyword` | `in` | `VariantKeyword` | `variant` | | | | `WhenKeyword` | `when` | | | | `WhileKeyword` | `while` | Together with `true` and `false`, which are `BoolLiteral` tokens, these are the 38 reserved words. ## Punctuation | Token | Spelling | Token | Spelling | | -------------- | -------- | ------------------ | -------- | | `LeftParen` | `(` | `Dot` | `.` | | `RightParen` | `)` | `DotDot` | `..` | | `LeftBrace` | `{` | `DotDotDot` | `...` | | `RightBrace` | `}` | `DotDotEqual` | `..=` | | `LeftBracket` | `[` | `Arrow` | `->` | | `RightBracket` | `]` | `FatArrow` | `=>` | | `Comma` | `,` | `At` | `@` | | `Semicolon` | `;` | `Hash` | `#` | | `Colon` | `:` | `Question` | `?` | | `ColonColon` | `::` | `QuestionQuestion` | `??` | ## Operators | Token | Spelling | Group | Token | Spelling | Group | | ----------------------- | -------- | ---------- | ----------------------------- | -------- | ---------- | | `Plus` | `+` | Arithmetic | `Equal` | `==` | Comparison | | `Minus` | `-` | Arithmetic | `BangEqual` | `!=` | Comparison | | `Star` | `*` | Arithmetic | `Less` | `<` | Comparison | | `Slash` | `/` | Arithmetic | `LessEqual` | `<=` | Comparison | | `Percent` | `%` | Arithmetic | `Greater` | `>` | Comparison | | `PlusPlus` | `++` | Arithmetic | `GreaterEqual` | `>=` | Comparison | | `MinusMinus` | `--` | Arithmetic | `MoveArrow` | `<-` | Assignment | | `Amp` | `&` | Bitwise | `Assign` | `=` | Assignment | | `Pipe` | `|` | Bitwise | `PlusAssign` | `+=` | Assignment | | `Caret` | `^` | Bitwise | `MinusAssign` | `-=` | Assignment | | `Tilde` | `~` | Bitwise | `StarAssign` | `*=` | Assignment | | `LessLess` | `<<` | Bitwise | `SlashAssign` | `/=` | Assignment | | `GreaterGreater` | `>>` | Bitwise | `PercentAssign` | `%=` | Assignment | | `GreaterGreaterGreater` | `>>>` | Bitwise | `AmpAssign` | `&=` | Assignment | | `AmpAmp` | `&&` | Logical | `PipeAssign` | `|=` | Assignment | | `PipePipe` | `||` | Logical | `CaretAssign` | `^=` | Assignment | | `Bang` | `!` | Logical | `LessLessAssign` | `<<=` | Assignment | | | | | `GreaterGreaterAssign` | `>>=` | Assignment | | | | | `GreaterGreaterGreaterAssign` | `>>>=` | Assignment | [Operators and Punctuation](https://rux-lang.dev/docs/lang/lexical/operators) says what each one means. ## Special tokens | Token | Meaning | | ------------ | --------------------------------------------------------------------------------------------------------------------------------------------- | | `DocComment` | A documentation comment, `/// …` or `/** … */`, kept so the parser can attach it to the next declaration. Ordinary comments produce no token. | | `EndOfFile` | Appended after the last token of every file | | `Unknown` | A character that starts no token, kept so the error can quote it | | `NewLine` | Defined but never produced: line breaks are whitespace | ## See also - [Source Files](https://rux-lang.dev/docs/lang/lexical/source-files) — how the lexer reads a file - [Keywords](https://rux-lang.dev/docs/lang/lexical/keywords) and [Literals](https://rux-lang.dev/docs/lang/lexical/literals) - [Operators and Punctuation](https://rux-lang.dev/docs/lang/lexical/operators) # Rux Compiled Unit A **Rux Compiled Unit** (RCU, `.rcu`) is the object format of the Rux compiler. Each back end — x86-64 and AArch64 — encodes its instructions itself and stores them, with symbols and relocations, in one RCU per compiled source file. The Rux linker reads the units of a build and writes the target's container: a PE image on Windows, ELF on Linux and FreeBSD, Mach-O on macOS, or a relocatable object or static archive in the target's own format. No external assembler, compiler or linker takes part. A normal build keeps its units in memory. `rux build --emit rcu` also writes them out, as `Temp/Obj/<file>.rcu`, with a readable dump of each in `Temp/Rcu/<file>.rcu.txt` (see [`rux build`](https://rux-lang.dev/docs/cli/build)). ```mermaid flowchart LR src["`Src/*.rux`"] --> fe["front end<br/>HIR, LIR"] fe --> x64["x86-64 back end"] fe --> a64["AArch64 back end"] x64 --> rcu["RCU units"] a64 --> rcu rcu --> link["Rux linker"] link --> out["PE, ELF or Mach-O"] ``` ## File layout All multi-byte integers are **little-endian**, and every field sits at the exact offset listed — there is no implicit padding. The regions follow one another in this order: ```text ┌──────────────────────────────────────────┐ offset 0 │ File header 32 bytes │ ├──────────────────────────────────────────┤ offset 32 │ Section table section_count × 40 │ ├──────────────────────────────────────────┤ 32 + section_count × 40 │ Symbol table symbol_count × 20 │ ├──────────────────────────────────────────┤ │ For each section, in table order: │ │ raw data (aligned to section) │ │ relocations (aligned to 4) │ ├──────────────────────────────────────────┤ │ String table string_table_size │ ├──────────────────────────────────────────┤ │ Rux metadata 64 bytes (aligned to 8) │ when present └──────────────────────────────────────────┘ ``` Every gap introduced by alignment is filled with `0x00`. A reader needs only the header to find everything else. ## File header | Offset | Size | Type | Field | Meaning | | ------ | ---- | ------- | ------------------- | ---------------------------------------------------------------- | | 0 | 4 | `u8[4]` | `magic` | `52 43 55 00` — `"RCU\0"` | | 4 | 2 | `u16` | `version` | `(major << 8) | minor`; this format is 1.0, `0x0100` | | 6 | 1 | `u8` | `arch` | target architecture — see below | | 7 | 1 | `u8` | `flags` | bit 0 `F_HAS_METADATA`; bits 1–7 are `0` | | 8 | 2 | `u16` | `section_count` | entries in the section table | | 10 | 2 | `u16` | `_reserved` | `0` | | 12 | 4 | `u32` | `symbol_count` | entries in the symbol table | | 16 | 4 | `u32` | `string_table_off` | file offset of the string table | | 20 | 4 | `u32` | `string_table_size` | its size in bytes | | 24 | 4 | `u32` | `metadata_offset` | file offset of the metadata block, or `0` when there is none | | 28 | 4 | `u32` | `checksum` | CRC-32C of the whole file, computed with these four bytes as `0` | | `arch` | Architecture | | ------ | ---------------------- | | `0x00` | unknown | | `0x01` | x86-64, little-endian | | `0x02` | AArch64, little-endian | The architecture byte names the processor only. Operating system and calling convention are not recorded: the instruction bytes were generated for one target, and the linker is told which one it is linking for. A unit is only meaningful to a link for the same architecture, and the linker rejects any other. A reader must reject a file whose magic differs, and should reject one whose major version is newer than it understands. ## Section table `section_count` entries of 40 bytes, starting at offset 32. | Offset | Size | Type | Field | Meaning | | ------ | ---- | --------- | -------------- | ---------------------------------------------------------- | | 0 | 8 | `char[8]` | `name` | ASCII name, at most 7 characters, padded with `\0` | | 8 | 4 | `u32` | `type` | section type | | 12 | 4 | `u32` | `flags` | section flags | | 16 | 4 | `u32` | `raw_offset` | file offset of the section's bytes, aligned to `alignment` | | 20 | 4 | `u32` | `raw_size` | number of bytes stored | | 24 | 4 | `u32` | `virtual_size` | size in memory: `raw_size`, or `1` for an empty section | | 28 | 2 | `u16` | `alignment` | required alignment, a power of two | | 30 | 2 | `u16` | `reloc_count` | relocation entries for this section | | 32 | 4 | `u32` | `reloc_offset` | file offset of those entries, or `0` when there are none | | 36 | 4 | `u32` | `_reserved` | `0` | An empty section still has a `raw_offset` — the aligned position its bytes would start at. | `type` | Constant | Contents | | ------ | ------------ | ------------------------------------------- | | `0` | `SEC_NULL` | an unused entry | | `1` | `SEC_TEXT` | machine code | | `2` | `SEC_DATA` | initialized writable data | | `3` | `SEC_RODATA` | read-only data: literals, constant tables | | `4` | `SEC_BSS` | zero-initialized data, with no bytes stored | | `5` | `SEC_META` | Rux-specific metadata | | Bit | Constant | Meaning | | --- | ------------ | ------------------------------- | | 0 | `SF_ALLOC` | occupies memory at run time | | 1 | `SF_EXEC` | executable | | 2 | `SF_READ` | readable | | 3 | `SF_WRITE` | writable | | 4 | `SF_MERGE` | identical entries may be merged | | 5 | `SF_STRINGS` | holds NUL-terminated strings | Both back ends emit the same three sections, always in this order: | Index | Name | Type | Flags | Alignment | Contents | | ----- | --------- | ------------ | ------------------------------- | --------- | -------------------------------------- | | 0 | `.text` | `SEC_TEXT` | `SF_ALLOC | SF_EXEC | SF_READ` | 16 | functions, including `asm func` bodies | | 1 | `.rodata` | `SEC_RODATA` | `SF_ALLOC | SF_READ` | 8 | string literals and constant data | | 2 | `.data` | `SEC_DATA` | `SF_ALLOC | SF_READ | SF_WRITE` | 8 | writable data | ## Symbol table `symbol_count` entries of 20 bytes, starting right after the section table. | Offset | Size | Type | Field | Meaning | | ------ | ---- | ----- | --------------- | ------------------------------------------------------------------------------------------------------------------------- | | 0 | 4 | `u32` | `name_off` | string-table offset of the name | | 4 | 4 | `u32` | `value` | offset within the section; the value itself for an absolute symbol | | 8 | 4 | `u32` | `size` | size in bytes, `0` when unknown | | 12 | 2 | `u16` | `section_idx` | owning section; `0xFFFF` for an external symbol, `0xFFFE` for an absolute one | | 14 | 1 | `u8` | `kind` | symbol kind | | 15 | 1 | `u8` | `visibility` | symbol binding | | 16 | 4 | `u32` | `type_name_off` | string-table offset of a type spelling — a function's result type, such as `"int32"`, or a constant's type; `0` when none | | `kind` | Constant | Meaning | | ------ | ----------------- | ---------------------------------------------- | | `0` | `SYM_UNKNOWN` | unclassified | | `1` | `SYM_FUNC` | a function defined in this unit | | `2` | `SYM_DATA` | writable data defined in this unit | | `3` | `SYM_CONST` | read-only data defined in this unit | | `4` | `SYM_SECTION` | a section | | `5` | `SYM_FILE` | a source file name | | `6` | `SYM_EXTERN_FUNC` | a function this unit calls but does not define | | `7` | `SYM_EXTERN_DATA` | data this unit uses but does not define | An external symbol has `section_idx = 0xFFFF` and `value = 0`; it is a reference to a definition in another unit of the link or, for an `extern` declaration, to a shared library. | `visibility` | Constant | Meaning | | ------------ | -------------- | ---------------------------------------------------------------------------------------------------------------------------------- | | `0` | `VIS_LOCAL` | a package-private definition | | `1` | `VIS_GLOBAL` | a public definition of a dependency, linkable across units but not part of the artifact's interface; also every external reference | | `2` | `VIS_WEAK` | a definition another unit's global definition overrides | | `3` | `VIS_EXPORTED` | a public definition of the package being built — what a library artifact publishes | The linker binds each reference to exactly one definition and reports a duplicate or a missing one. An executable's root is `Main`; a library's roots are its exported definitions. ## Relocations Each section's relocations are an array of 16-byte entries at `reloc_offset`. | Offset | Size | Type | Field | Meaning | | ------ | ---- | ----- | ---------------- | ----------------------------------------------- | | 0 | 4 | `u32` | `section_offset` | where in the section the field to patch begins | | 4 | 4 | `u32` | `symbol_index` | the symbol whose address is used | | 8 | 2 | `u16` | `type` | relocation type | | 10 | 2 | `u16` | `_reserved` | `0` | | 12 | 4 | `i32` | `addend` | a signed constant added to the symbol's address | In the formulas, `S` is the symbol's address, `A` the addend and `P` the address of the patched field. Types below 16 patch a whole little-endian field and are architecture-neutral; types from 16 patch bit fields of one AArch64 instruction word and keep the names of their ELF counterparts. | Type | Name | Patches | Value | | --------- | --------------------------- | ----------------------------- | ------------------------------------------------------------------------------------------------- | | `0` | `NONE` | nothing | — | | `1` | `ABS_64` | 64-bit field | `S + A` | | `2` | `ABS_32` | 32-bit field | `S + A`, which must fit in 32 bits | | `3` | `REL_32` | 32-bit field | `S + A − (P + 4)`, a signed 32-bit displacement — x86-64 `call`, `jmp`, `jcc`, `[rip + …]` | | `16` | `AARCH64_CALL26` | `bl` imm26 | `(S + A − P) >> 2` | | `17` | `AARCH64_JUMP26` | `b` imm26 | `(S + A − P) >> 2` | | `18` | `AARCH64_CONDBR19` | `b.cond`, `cbz`, `cbnz` imm19 | `(S + A − P) >> 2` | | `19` | `AARCH64_TSTBR14` | `tbz`, `tbnz` imm14 | `(S + A − P) >> 2` | | `20` | `AARCH64_ADR_PREL_PG_HI21` | `adrp` immhi\:immlo | `(page(S + A) − page(P)) >> 12`, `page(x) = x & ~0xFFF` | | `21` | `AARCH64_ADD_ABS_LO12_NC` | `add` imm12 | `(S + A) & 0xFFF` | | `22` | `AARCH64_LDST_ABS_LO12_NC` | load/store imm12 | `((S + A) & 0xFFF) >> scale`, where `scale` is the access size; the address must be aligned to it | | `23`–`26` | `AARCH64_MOVW_UABS_G0`…`G3` | `movz`/`movk` imm16 | bits 0–15, 16–31, 32–47 or 48–63 of `S + A` | | `27` | `AARCH64_PREL32` | 32-bit field | `S + A − P`, signed | | `28` | `AARCH64_PREL64` | 64-bit field | `S + A − P` | A displacement that does not fit its field, or a misaligned load/store target, is a link error that names the symbol. ## String table A flat block of NUL-terminated UTF-8 strings. Offset `0` is always the empty string, so a `0` offset anywhere means "no name". Each distinct string is stored once. The writer interns, in this order: the source path, the package name, each symbol's name and type spelling, and the section names. Symbol and section names are printable ASCII; the source path may be any UTF-8. ## Metadata When `F_HAS_METADATA` is set, a 64-byte block sits at `metadata_offset`, aligned to 8. The compiler writes it into every unit. | Offset | Size | Type | Field | Meaning | | ------ | ---- | -------- | ------------------ | --------------------------------------------------------------------------- | | 0 | 4 | `u8[4]` | `magic` | `4D 45 54 41` — `"META"` | | 4 | 4 | `u32` | `block_size` | `64` | | 8 | 4 | `u32` | `source_path_off` | string-table offset of the source file's path | | 12 | 4 | `u32` | `package_name_off` | string-table offset of the package name | | 16 | 8 | `u64` | `build_timestamp` | the build's start, in Unix seconds — the same instant as `#build.timestamp` | | 24 | 4 | `u32` | `rux_version` | the compiler version, `(major << 16) | (minor << 8) | patch` | | 28 | 4 | `u32` | `compiler_flags` | reserved; written as `0` | | 32 | 32 | `u8[32]` | `source_hash` | reserved for a SHA-256 of the source; written as zeros | ## Checksum `checksum` is a CRC-32C — the Castagnoli polynomial, reflected form `0x82F63B78`, initial value and final XOR `0xFFFFFFFF` — over every byte of the file, with the checksum field itself counted as four zero bytes. It is computed last, after every other field is written. It is deliberately not the IEEE CRC-32 of ZIP, so the two are not interchangeable. ## Example `Src/Main.rux` of a package called `Math`: ```rux func Add(a: int32, b: int32) -> int32 { return a + b; } func Main() -> int { return Add(3, 4) as int; } ``` `rux build --emit rcu --target linux-x86_64` writes `Temp/Obj/Main.rcu`, whose dump begins: ```text ; RCU Rux Compiled Unit v1.0 ; Architecture: x86-64 ; Package: Math ; Rux version: 0.4.0 Sections: 3 [ 0] .text flags:AER align:16 data:239B relocs:1 [ 1] .rodata flags:AR align:8 data:0B relocs:0 [ 2] .data flags:ARW align:8 data:0B relocs:0 Symbols: 2 [ 0] Add .text+0x0000 size=150 FUNC LOCAL "int32" [ 1] Main .text+0x0096 size=89 FUNC LOCAL "int" Relocations (.text): [ 0] off=0x00CE sym[0]=Add REL_32 addend=0 ``` The one relocation is the `call Add` inside `Main`: four placeholder bytes at `.text + 0xCE` that the linker replaces with `Add − (P + 4)`. Built for `linux-aarch64` instead, the same call is a `bl` patched by an `AARCH64_CALL26` relocation. With a source path of 120 bytes, the file is laid out as follows: | Offset | Region | Size | | ------- | ---------------------------------- | --------------------------------------------------------------------------------------- | | `0x000` | header | 32 | | `0x020` | section table, 3 entries | 120 | | `0x098` | symbol table, 2 entries | 40 | | `0x0C0` | `.text` bytes (aligned to 16) | 239 | | `0x1B0` | `.text` relocations (aligned to 4) | 16 | | `0x1C0` | `.rodata`, `.data` (empty) | 0 — both `raw_offset`s are `0x1C0` | | `0x1C0` | string table | 166: `\0`, the path, `Math`, `Add`, `int32`, `Main`, `int`, `.text`, `.rodata`, `.data` | | `0x268` | metadata (aligned to 8) | 64 | | `0x2A8` | end of file | | and its header reads: ```text 52 43 55 00 magic "RCU\0" 00 01 version 0x0100 01 arch x86-64 01 flags F_HAS_METADATA 03 00 section_count 3 00 00 _reserved 02 00 00 00 symbol_count 2 C0 01 00 00 string_table_off 0x1C0 A6 00 00 00 string_table_size 166 68 02 00 00 metadata_offset 0x268 xx xx xx xx checksum CRC-32C, computed last ``` ## See also - [Assembly](https://rux-lang.dev/docs/lang/ffi/assembly) — `asm func` bodies, whose symbols become relocations - [`rux build`](https://rux-lang.dev/docs/cli/build) — `--emit rcu` and the other inspection outputs - [Linking](https://rux-lang.dev/docs/lang/ffi/linking) — external symbols bound to shared libraries # Rux Language Reference This reference describes the Rux language exactly as **rux 0.4.0** implements it: every type, expression, statement and declaration, the rules the compiler enforces and the messages it prints when a rule is broken. Every example on these pages compiles with rux 0.4.0. It is written for looking things up. To learn the language from the beginning, follow [Learn Rux](https://rux-lang.dev/docs/learn) — a course of short, runnable lessons — and come back here for the full rules. The [Introduction](https://rux-lang.dev/docs/lang/introduction) explains how the chapters are organised and the grammar notation they use. ## The basics ::u-page-grid :::u-page-card --- description: Design goals, a first program, and how to read this reference. icon: i-lucide-book-open title: Introduction to: https://rux-lang.dev/docs/lang/introduction variant: subtle --- ::: :::u-page-card --- description: Source files, comments, identifiers, keywords, literals and operator tokens. icon: i-lucide-text title: Lexical structure to: https://rux-lang.dev/docs/lang/lexical/source-files variant: subtle --- ::: :::u-page-card --- description: Integers, floating point, booleans, characters, text and type aliases. icon: i-lucide-shapes title: Types to: https://rux-lang.dev/docs/lang/types/overview variant: subtle --- ::: :::u-page-card --- description: let, var and const, initialisation and destructuring. icon: i-lucide-tag title: Bindings to: https://rux-lang.dev/docs/lang/bindings/overview variant: subtle --- ::: :::u-page-card --- description: Every operator, its precedence, and casts with as. icon: i-lucide-plus title: Expressions to: https://rux-lang.dev/docs/lang/expressions/overview variant: subtle --- ::: :::u-page-card --- description: if, the four loops, labelled break and continue, and return. icon: i-lucide-git-branch title: Statements to: https://rux-lang.dev/docs/lang/statements/overview variant: subtle --- ::: :::u-page-card --- description: match, exhaustiveness, and every pattern form. icon: i-lucide-scan-search title: Patterns to: https://rux-lang.dev/docs/lang/patterns/match variant: subtle --- ::: :: ## Functions and data ::u-page-grid :::u-page-card --- description: Declarations, parameters, overloading, function types and Main. icon: i-lucide-square-function title: Functions to: https://rux-lang.dev/docs/lang/functions/declaration variant: subtle --- ::: :::u-page-card --- description: Structs, methods with typed receivers, constructors and extensions. icon: i-lucide-box title: Structures to: https://rux-lang.dev/docs/lang/structs/overview variant: subtle --- ::: :::u-page-card --- description: Scalar enums with a backing type and explicit values. icon: i-lucide-list-ordered title: Enumerations to: https://rux-lang.dev/docs/lang/enums/overview variant: subtle --- ::: :::u-page-card --- description: Tagged unions whose cases carry their own data. icon: i-lucide-split title: Variants to: https://rux-lang.dev/docs/lang/variants/overview variant: subtle --- ::: :::u-page-card --- description: Untagged overlays of several types in one place. icon: i-lucide-layers title: Unions to: https://rux-lang.dev/docs/lang/unions/overview variant: subtle --- ::: :::u-page-card --- description: Anonymous products, the unit type and structural equality. icon: i-lucide-parentheses title: Tuples to: https://rux-lang.dev/docs/lang/tuples/overview variant: subtle --- ::: :::u-page-card --- description: Fixed-length T[N], repeat literals and bounds checks. icon: i-lucide-brackets title: Arrays to: https://rux-lang.dev/docs/lang/arrays/overview variant: subtle --- ::: :::u-page-card --- description: Read-only T[..] and writable var T[..] views. icon: i-lucide-scissors title: Slices to: https://rux-lang.dev/docs/lang/slices/overview variant: subtle --- ::: :::u-page-card --- description: The six range forms and where they are used. icon: i-lucide-move-horizontal title: Ranges to: https://rux-lang.dev/docs/lang/ranges/overview variant: subtle --- ::: :: ## Absence and failure ::u-page-grid :::u-page-card --- description: T? and none, ?? fallbacks and ? propagation. icon: i-lucide-circle-dashed title: Optionals to: https://rux-lang.dev/docs/lang/optionals/overview variant: subtle --- ::: :::u-page-card --- description: Fallibles T ! E, fail, catch, propagation and panics. icon: i-lucide-triangle-alert title: Errors to: https://rux-lang.dev/docs/lang/errors/overview variant: subtle --- ::: :::u-page-card --- description: A | B values, typed patterns and the is test. icon: i-lucide-combine title: Sum types to: https://rux-lang.dev/docs/lang/sums/overview variant: subtle --- ::: :: ## Memory and ownership ::u-page-grid :::u-page-card --- description: Borrowing with &T and &var T, and the exclusivity rule. icon: i-lucide-link title: References to: https://rux-lang.dev/docs/lang/references/overview variant: subtle --- ::: :::u-page-card --- description: "*T and *var T, @ and *, null, arithmetic and slicing." icon: i-lucide-mouse-pointer-2 title: Pointers to: https://rux-lang.dev/docs/lang/pointers/overview variant: subtle --- ::: :::u-page-card --- description: Copies and moves, destructors and defer. icon: i-lucide-key-round title: Ownership to: https://rux-lang.dev/docs/lang/ownership/overview variant: subtle --- ::: :::u-page-card --- description: sizeof, alignof, padding and the layout of native forms. icon: i-lucide-ruler title: Memory layout to: https://rux-lang.dev/docs/lang/memory/layout variant: subtle --- ::: :: ## Abstraction ::u-page-grid :::u-page-card --- description: Declarations, interface values, core interfaces, operators, indexers and iteration. icon: i-lucide-plug title: Interfaces to: https://rux-lang.dev/docs/lang/interfaces/overview variant: subtle --- ::: :::u-page-card --- description: Generic functions, types and methods, and bounds. icon: i-lucide-variable title: Generics to: https://rux-lang.dev/docs/lang/generics/overview variant: subtle --- ::: :::u-page-card --- description: Packages and modules, imports and pub visibility. icon: i-lucide-package title: Modules to: https://rux-lang.dev/docs/lang/modules/overview variant: subtle --- ::: :: ## Compile time and platform ::u-page-grid :::u-page-card --- description: "when, the #target, #build, #compiler, #source and #config context, intrinsics and diagnostics." icon: i-lucide-cpu title: Compile time to: https://rux-lang.dev/docs/lang/comptime/overview variant: subtle --- ::: :::u-page-card --- description: "#Link, #Abi, #NoReturn, #Warn, #Error, #Allow, #Format and #Test." icon: i-lucide-at-sign title: Attributes to: https://rux-lang.dev/docs/lang/attributes/overview variant: subtle --- ::: :::u-page-card --- description: extern declarations, linking libraries and inline assembly. icon: i-lucide-cable title: Foreign Function Interface to: https://rux-lang.dev/docs/lang/ffi/overview variant: subtle --- ::: :: ## Appendix - [Primitive types](https://rux-lang.dev/docs/lang/appendix/primitives) — every primitive type and alias in one table. - [Tokens](https://rux-lang.dev/docs/lang/appendix/tokens) — every token the lexer produces. - [Rux Compiled Unit](https://rux-lang.dev/docs/lang/appendix/rcu) — the compiler's native object format. Package manifests, dependencies and publishing are covered in [Packaging](https://rux-lang.dev/docs/packaging), and the standard packages in the [API Reference](https://rux-lang.dev/docs/api). # Global options ## Purpose Global options configure command-independent CLI behavior and may appear before or after the command name. ## Synopsis ```sh rux [global-options] <command> [command-options] [operands] ``` Both `--option value` and `--option=value` are accepted for options that take a value. Only `rux run` accepts `--`; every following token is passed unchanged to the child program. ## Behavior `-q`/`--quiet` and `-v`/`--verbose` conflict. Help and version exit 0. Unknown options, missing values, invalid color values, conflicts, and incorrect operand counts exit 2 and are written to stderr. Help is available as `rux help`, `rux help <command>`, or command-level `-h`/`--help`. Close command and option spellings receive a suggestion. ## Options | Option | Description | | ----------------------------- | --------------------------------------------------- | | `--color <auto|always|never>` | Control colored console output | | `-h, --help` | Show help information | | `--manifest <path>` | Use the specified manifest file instead of Rux.toml | | `-q, --quiet` | Do not show log messages | | `-v, --verbose` | Use verbose output | | `-V, --version` | Show version information | ### Color `--color` accepts exactly `auto`, `always`, or `never`. An explicit CLI value overrides the environment. In auto mode, stdout and stderr terminal attachment are detected independently. ### Manifest `--manifest <path>` selects a specific manifest instead of searching upward for `Rux.toml`. ## Output and exit status Primary output and structured JSON use stdout. Progress, warnings, and errors use stderr. Success, help, and version exit 0; invalid CLI usage exits 2; operational and compiler failures exit 1. ## Examples ```sh rux --manifest examples/Rux.toml check rux build --color=never rux --quiet test rux help build rux help --json ``` ## Environment variables - A non-empty `NO_COLOR` disables color in auto mode. - `TERM=dumb` disables color in auto mode. - An explicit `--color always` or `--color never` overrides both variables. ## Related commands - [`rux help`](https://rux-lang.dev/docs/cli/help) - [`rux version`](https://rux-lang.dev/docs/cli/version) # rux add ## Purpose Add a brand new external dependency link directly into the package configuration file. ## Synopsis ```sh rux add [namespace]/[package] rux add [namespace]/[package]@[requirement] rux add [package] --path [path] ``` ## Behavior Registry dependencies require a namespaced identity such as `Rux/Io`; an optional `@requirement` constrains the resolved version. `--path` adds a local dependency instead. A requirement an installed package already satisfies, as the standard `Rux/*` packages installed with the compiler do, is added without contacting the registry; any other is checked against the registry first. The command updates `Rux.toml` only once the package is found. ## Arguments | Argument | Required | Description | | --------- | -------- | ------------------------------------------------------ | | `package` | Yes | A namespaced package identity and optional requirement | ## Options | Option | Description | | ------------------ | -------------------------------------------------- | | `--path <path>` | Add a local path-based dependency | | `--registry <url>` | Registry API base URL to check the package against | Global options may appear before or after the command. See [Global options](https://rux-lang.dev/docs/cli/global). ## Output and exit status Primary results are written to stdout. Progress, warnings, and errors are written to stderr. Success exits 0, invalid command-line usage exits 2, and compiler, validation, filesystem, network, or generation failures exit 1 unless stated otherwise above. ## Examples ```sh rux add Rux/Io rux add Rux/Io@^0.1.0 rux add Json --path ../Json ``` ## Environment variables `RUX_REGISTRY_URL` sets the default registry when `--registry` is absent. The global color environment behavior is described under [Global options](https://rux-lang.dev/docs/cli/global#environment-variables). ## Related commands - [`rux install`](https://rux-lang.dev/docs/cli/install) - [`rux remove`](https://rux-lang.dev/docs/cli/remove) - [`rux update`](https://rux-lang.dev/docs/cli/update) # rux build ## Purpose Build the current package ## Synopsis ```sh rux build [options] ``` ## Behavior Builds the normal package artifact and may additionally write inspection output selected by repeatable or comma-separated `--emit`. `--debug` and `--release` are mutually exclusive. Frontend target selection is supported, but linking a foreign target is rejected until that backend is available end to end. A build that is not up to date compiles only the source files that changed, on one thread per logical core unless `--jobs` caps them; the artifact is the same for every `--jobs` value. `--disable-pass` switches off one optional optimization pass for diagnosis, and an unknown or inactive pass name is rejected. Executable, SharedLibrary, and StaticLibrary packages build their conventional native artifact. A Windows SharedLibrary additionally writes its `.lib` import library. SourceLibrary packages can be checked but cannot be built directly. ### `--emit` values | Kind | Additional output | | --------- | ------------------------------------------------------------------------------------------------------------------------------- | | `tokens` | Token streams in `Temp/Tokens/` | | `ast` | Parsed syntax trees in `Temp/Ast/` | | `sema` | Semantic-analysis dump in `Temp/Sema/sema.txt` | | `hir` | High-level IR in `Temp/Hir/hir.txt` | | `lir` | Low-level IR in `Temp/Lir/lir.txt` | | `passes` | The HIR and LIR before and after each optimization pass, in a directory per invocation under `Temp/Optimization/` | | `asm` | Target assembly in `Temp/Asm/` | | `rcu` | RCU objects in `Temp/Obj/` and text dumps in `Temp/Rcu/` | | `symbols` | Section headers and a `.symtab` in an ELF image, so profilers such as `perf` name Rux functions; PE and Mach-O images ignore it | The option is repeatable and accepts comma-separated values, so `--emit ast --emit sema` and `--emit ast,sema` are equivalent. ## Arguments This command accepts no operands. ## Options | Option | Description | | ------------------------- | ------------------------------------------------------------------------------------------------------------- | | `--all` | Build all 16 target/profile cells; incompatible with --target, --debug, --release, --emit, and --disable-pass | | `--debug` | Build with debug symbols (unoptimized output) | | `--define <name[=value]>` | Set or override a config compile-time value | | `--disable-pass <name>` | Disable an optional optimization pass for diagnosis; repeat for multiple passes | | `--emit <kind[,kind...]>` | Additionally emit tokens, ast, sema, hir, lir, passes, asm, or rcu inspection output, or image symbols | | `--jobs <N>` | Compile on up to N threads (default: one per logical core); the output is the same for every N | | `--no-cache` | Compile even when an earlier build of the same inputs is still up to date | | `--release` | Build with release profile (optimized, no debug info) | | `--stats` | Print build timing, source, optimization, and performance statistics | | `--target <triple>` | Build for the specified target platform (e.g. linux-x86\_64, linux-aarch64) | | `-q, --quiet` | Suppress non-essential output (only errors are shown) | | `-v, --verbose` | Enable verbose output for detailed build information | Global options may appear before or after the command. See [Global options](https://rux-lang.dev/docs/cli/global). ## Output and exit status The artifact is written below configured `[Build].Output` using the selected profile. Inspection output is written below `Temp/` and does not replace the normal artifact. A successful build records what it read under `Temp/Cache`, and the next identical build reuses the artifact when nothing changed, reporting `(up to date)`; `--no-cache` always compiles. Success exits 0, invalid command-line usage exits 2, and compiler, validation, filesystem, network, or generation failures exit 1 unless stated otherwise above. ## Examples ```sh rux build rux build --all --stats rux build --debug rux build --release --target linux-x86_64 rux build --stats rux build --verbose --release rux build --emit ast,sema ``` ## Environment variables `SOURCE_DATE_EPOCH` fixes compiler timestamps for reproducible builds. The global color environment behavior is described under [Global options](https://rux-lang.dev/docs/cli/global#environment-variables). ## Related commands - [`rux check`](https://rux-lang.dev/docs/cli/check) - [`rux run`](https://rux-lang.dev/docs/cli/run) - [`rux clean`](https://rux-lang.dev/docs/cli/clean) # rux check ## Purpose Parse and analyze the source workspace files for syntactic or semantic safety flaws without emitting compilation binaries. ## Synopsis ```sh rux check [options] ``` ## Behavior Runs lexing, parsing, dependency loading, conditional-compilation folding, and semantic analysis without linking. Any supported target may be checked, including a foreign target. `--define` values override `[Build.Defines]`. A package whose last check reported nothing and whose inputs are unchanged is skipped; `--no-cache` checks it anyway. At a workspace root every member is checked, side by side. ## Arguments This command accepts no operands. ## Options | Option | Description | | ------------------------- | ------------------------------------------------------------------------------------ | | `--define <name[=value]>` | Set or override a config compile-time value | | `--json` | Output diagnostics in JSON format | | `--no-cache` | Check every package even when an earlier check found nothing and is still up to date | | `--target <triple>` | Check code health for a specific target platform | Global options may appear before or after the command. See [Global options](https://rux-lang.dev/docs/cli/global). ## Output and exit status Text diagnostics go to stderr. With `--json`, stdout receives one complete JSON document with a success flag and an escaped diagnostics array, including on failure. Success exits 0, invalid command-line usage exits 2, and compiler, validation, filesystem, network, or generation failures exit 1 unless stated otherwise above. ## Examples ```sh rux check rux check --json rux check --target windows-x86_64 ``` ## Environment variables This command defines no command-specific environment variables. The global color environment behavior is described under [Global options](https://rux-lang.dev/docs/cli/global#environment-variables). ## Related commands - [`rux build`](https://rux-lang.dev/docs/cli/build) - [`rux lint`](https://rux-lang.dev/docs/cli/lint) - [`rux doc`](https://rux-lang.dev/docs/cli/doc) # rux clean ## Purpose Purge compiled code modules, system logs, and cached local build tracking states from the environment workspace. ## Synopsis ```sh rux clean [options] ``` ## Behavior Removes the directory named by `[Build].Output` and the package `Temp/` directory. `--temp` preserves configured build artifacts and removes only `Temp/`. ## Arguments This command accepts no operands. ## Options | Option | Description | | -------- | ------------------------------------------------- | | `--temp` | Remove only the temporary build directory (Temp/) | Global options may appear before or after the command. See [Global options](https://rux-lang.dev/docs/cli/global). ## Output and exit status Primary results are written to stdout. Progress, warnings, and errors are written to stderr. Success exits 0, invalid command-line usage exits 2, and compiler, validation, filesystem, network, or generation failures exit 1 unless stated otherwise above. ## Examples ```sh rux clean rux clean --temp ``` ## Environment variables This command defines no command-specific environment variables. The global color environment behavior is described under [Global options](https://rux-lang.dev/docs/cli/global#environment-variables). ## Related commands - [`rux build`](https://rux-lang.dev/docs/cli/build) # rux doc ## Purpose Generate package documentation ## Synopsis ```sh rux doc [options] ``` ## Behavior Runs the same folded, semantically checked frontend as `rux check`, then documents public modules, types, functions, constants, fields, variants, interface members, externs, and public extension methods. `--document-private-items` includes private items. Consecutive outer `///` comments attach when no blank line intervenes and support safe Markdown; raw HTML is escaped and unsafe link schemes are omitted. Foreign supported targets and repeated `--define` values select the API that is generated. ## Arguments This command accepts no operands. ## Options | Option | Description | | -------------------------- | ----------------------------------------------------------------- | | `--define <name[=value]>` | Set or override a config compile-time value | | `--document-private-items` | Include private declarations and members | | `--format <html|json>` | Write an HTML site (default) or one JSON API snapshot per package | | `-o, --output <dir>` | Write the generated site to this directory | | `--open` | Open the generated documentation index in a browser | | `--target <triple>` | Document APIs enabled for a supported target | Global options may appear before or after the command. See [Global options](https://rux-lang.dev/docs/cli/global). ## Output and exit status The default is `[Build].Output/Docs` (normally `Bin/Docs`). `--format json` writes one versioned JSON API snapshot per package, such as `Bin/Docs/App.json`, instead of an HTML site. A workspace gets a landing page and one member section; dependencies are excluded. Generation is deterministic and self-contained. Rux writes through a temporary directory, marks managed output, and refuses to replace a non-empty unmarked directory. `--open` launches the generated index only after success. Success exits 0, invalid command-line usage exits 2, and compiler, validation, filesystem, network, or generation failures exit 1 unless stated otherwise above. ## Examples ```sh rux doc rux doc --open rux doc --format json --output Docs/Api ``` ## Environment variables This command defines no command-specific environment variables. The global color environment behavior is described under [Global options](https://rux-lang.dev/docs/cli/global#environment-variables). ## Related commands - [`rux check`](https://rux-lang.dev/docs/cli/check) - [`rux build`](https://rux-lang.dev/docs/cli/build) # rux fmt ## Purpose Format all \*.rux source files and \*.toml manifests ## Synopsis ```sh rux fmt [options] ``` ## Behavior Formats both `Src/**/*.rux` and `Rux.toml` by default. `--source-only` and `--manifest-only` are mutually exclusive. `--check` reports drift without writing files. ## Arguments This command accepts no operands. ## Options | Option | Description | | ----------------- | ----------------------------------------------------------- | | `--check` | Check file formatting status without modifying source files | | `--manifest-only` | Format only the manifest configuration file (Rux.toml) | | `--source-only` | Format only Rux source files | Global options may appear before or after the command. See [Global options](https://rux-lang.dev/docs/cli/global). ## Output and exit status Primary results are written to stdout. Progress, warnings, and errors are written to stderr. Success exits 0, invalid command-line usage exits 2, and compiler, validation, filesystem, network, or generation failures exit 1 unless stated otherwise above. ## Examples ```sh rux fmt rux fmt --check rux fmt --manifest-only ``` ## Environment variables This command defines no command-specific environment variables. The global color environment behavior is described under [Global options](https://rux-lang.dev/docs/cli/global#environment-variables). ## Related commands - [`rux check`](https://rux-lang.dev/docs/cli/check) - [`rux lint`](https://rux-lang.dev/docs/cli/lint) # rux help ## Purpose Show help information ## Synopsis ```sh rux help ``` ## Behavior Without an operand, lists all commands and global options. With a command operand, prints command help. `--json` emits schema version 1 with stable program, command, usage, argument, option, example, and documentation URL data; build timestamps are intentionally absent. ## Arguments | Argument | Required | Description | | --------- | -------- | -------------------------------------- | | `command` | No | The command whose help should be shown | ## Options | Option | Description | | -------- | -------------------------------------------- | | `--json` | Print the versioned command contract as JSON | Global options may appear before or after the command. See [Global options](https://rux-lang.dev/docs/cli/global). ## Output and exit status Help and JSON are written to stdout. Success exits 0, invalid command-line usage exits 2, and compiler, validation, filesystem, network, or generation failures exit 1 unless stated otherwise above. ## Examples ```sh rux help ``` ## Environment variables This command defines no command-specific environment variables. The global color environment behavior is described under [Global options](https://rux-lang.dev/docs/cli/global#environment-variables). ## Related commands - [`rux version`](https://rux-lang.dev/docs/cli/version) # rux info ## Purpose Show information about the current or an installed Rux package ## Synopsis ```sh rux info rux info [namespace]/[package] rux info [namespace]/[package]@[requirement] ``` ## Behavior Without an operand, reads the current manifest. With a namespaced identity, selects the highest installed version matching the requirement and consults the registry only to explain a cache miss. Package identities remain namespace-qualified. ## Arguments | Argument | Required | Description | | --------- | -------- | ------------------------------------------------------ | | `package` | No | A namespaced package identity and optional requirement | ## Options | Option | Description | | ------------------ | ---------------------------------------------------------- | | `--json` | Output package metadata in JSON format | | `--registry <url>` | Registry API base URL to look an uninstalled package up on | Global options may appear before or after the command. See [Global options](https://rux-lang.dev/docs/cli/global). ## Output and exit status Human-readable metadata goes to stdout. `--json` writes one complete, fully escaped JSON document on success or failure. Success exits 0, invalid command-line usage exits 2, and compiler, validation, filesystem, network, or generation failures exit 1 unless stated otherwise above. ## Examples ```sh rux info rux info Rux/Io rux info Rux/Io@0.1.0 rux info --json ``` ## Environment variables `RUX_REGISTRY_URL` sets the lookup registry when `--registry` is absent. The global color environment behavior is described under [Global options](https://rux-lang.dev/docs/cli/global#environment-variables). ## Related commands - [`rux list`](https://rux-lang.dev/docs/cli/list) - [`rux install`](https://rux-lang.dev/docs/cli/install) # rux init ## Purpose Initialize a Rux package in the current directory ## Synopsis ```sh rux init [options] ``` ## Behavior Creates a manifest and starter source in the current directory. `--executable`, `--shared`, `--static`, and `--source` are mutually exclusive; Executable is the default. `--namespace` prepares a registry identity. ## Arguments This command accepts no operands. ## Options | Option | Description | | ------------------ | ----------------------------------------------------------- | | `--executable` | Create an Executable package with an entry point (default) | | `--shared` | Create a SharedLibrary package | | `--static` | Create a StaticLibrary package | | `--source` | Create a SourceLibrary package compiled into its dependents | | `--namespace <ns>` | Set the registry namespace required to publish | Global options may appear before or after the command. See [Global options](https://rux-lang.dev/docs/cli/global). ## Output and exit status Primary results are written to stdout. Progress, warnings, and errors are written to stderr. Success exits 0, invalid command-line usage exits 2, and compiler, validation, filesystem, network, or generation failures exit 1 unless stated otherwise above. ## Examples ```sh rux init rux init --executable rux init --shared --namespace Rux rux init --static rux init --source ``` ## Environment variables This command defines no command-specific environment variables. The global color environment behavior is described under [Global options](https://rux-lang.dev/docs/cli/global#environment-variables). ## Related commands - [`rux new`](https://rux-lang.dev/docs/cli/new) # rux install ## Purpose Install dependencies ## Synopsis ```sh rux install rux install [namespace]/[package] rux install [namespace]/[package]@[requirement] ``` ## Behavior Without an operand, installs registry dependencies from the current package or every workspace member. With a namespaced identity, installs that package without adding it to the manifest. Resolution honors requirements, target conditions, transitive dependencies, yank state, `MinRux`, published SHA-256 checksums, and exact-version cache directories. ## Arguments | Argument | Required | Description | | --------- | -------- | ------------------------------------------------------ | | `package` | No | A namespaced package identity and optional requirement | ## Options | Option | Description | | ------------------- | ---------------------------------------------------- | | `--registry <url>` | Registry API base URL to resolve and download from | | `--target <triple>` | Install dependencies applicable to a target platform | Global options may appear before or after the command. See [Global options](https://rux-lang.dev/docs/cli/global). ## Output and exit status Primary results are written to stdout. Progress, warnings, and errors are written to stderr. Success exits 0, invalid command-line usage exits 2, and compiler, validation, filesystem, network, or generation failures exit 1 unless stated otherwise above. ## Examples ```sh rux install rux install Rux/Io rux install Rux/Io@^0.1.0 rux install --target windows-x86_64 rux install --registry http://localhost:8080 ``` ## Environment variables `RUX_REGISTRY_URL` sets the registry when `--registry` is absent. `LOCALAPPDATA` on Windows or `HOME` elsewhere determines the user package cache. The global color environment behavior is described under [Global options](https://rux-lang.dev/docs/cli/global#environment-variables). ## Related commands - [`rux add`](https://rux-lang.dev/docs/cli/add) - [`rux update`](https://rux-lang.dev/docs/cli/update) - [`rux uninstall`](https://rux-lang.dev/docs/cli/uninstall) # rux lint ## Purpose Run source-level diagnostics without emitting build artifacts ## Synopsis ```sh rux lint [options] ``` ## Behavior Runs fast source-level lint rules for the package or every workspace member without building an artifact. Use `rux check` when full semantic validation is required. ## Arguments This command accepts no operands. ## Options This command has no command-specific options. Global options still apply. Global options may appear before or after the command. See [Global options](https://rux-lang.dev/docs/cli/global). ## Output and exit status Primary results are written to stdout. Progress, warnings, and errors are written to stderr. Success exits 0, invalid command-line usage exits 2, and compiler, validation, filesystem, network, or generation failures exit 1 unless stated otherwise above. ## Examples ```sh rux lint rux lint --verbose ``` ## Environment variables This command defines no command-specific environment variables. The global color environment behavior is described under [Global options](https://rux-lang.dev/docs/cli/global#environment-variables). ## Related commands - [`rux check`](https://rux-lang.dev/docs/cli/check) - [`rux fmt`](https://rux-lang.dev/docs/cli/fmt) # rux list ## Purpose List packages in the manifest file ## Synopsis ```sh rux list [options] ``` ## Behavior Lists manifest dependencies and the installed versions that satisfy them. `--global` lists every exact version in the user cache. ## Arguments This command accepts no operands. ## Options | Option | Description | | ---------- | --------------------------------------------------------------------------- | | `--global` | List packages in the global environment cache instead of the local manifest | Global options may appear before or after the command. See [Global options](https://rux-lang.dev/docs/cli/global). ## Output and exit status Primary results are written to stdout. Progress, warnings, and errors are written to stderr. Success exits 0, invalid command-line usage exits 2, and compiler, validation, filesystem, network, or generation failures exit 1 unless stated otherwise above. ## Examples ```sh rux list rux list --global ``` ## Environment variables `LOCALAPPDATA` on Windows or `HOME` elsewhere determines the user package cache. The global color environment behavior is described under [Global options](https://rux-lang.dev/docs/cli/global#environment-variables). ## Related commands - [`rux info`](https://rux-lang.dev/docs/cli/info) - [`rux install`](https://rux-lang.dev/docs/cli/install) - [`rux uninstall`](https://rux-lang.dev/docs/cli/uninstall) # rux login ## Purpose Authenticate to a Rux package registry ## Synopsis ```sh rux login [options] ``` ## Behavior Reads a registry token from stdin so it does not enter shell history or the process list, verifies it when the registry supports verification, and stores it per registry with owner-only permissions. ## Arguments This command accepts no operands. ## Options | Option | Description | | ------------------ | ---------------------------------------- | | `--registry <url>` | Registry API base URL to authenticate to | Global options may appear before or after the command. See [Global options](https://rux-lang.dev/docs/cli/global). ## Output and exit status Primary results are written to stdout. Progress, warnings, and errors are written to stderr. Success exits 0, invalid command-line usage exits 2, and compiler, validation, filesystem, network, or generation failures exit 1 unless stated otherwise above. ## Examples ```sh rux login rux login --registry http://localhost:8080 ``` ## Environment variables `RUX_REGISTRY_URL` selects the registry when `--registry` is absent. `RUX_TOKEN` overrides a stored token for commands that authenticate. The global color environment behavior is described under [Global options](https://rux-lang.dev/docs/cli/global#environment-variables). ## Related commands - [`rux logout`](https://rux-lang.dev/docs/cli/logout) - [`rux publish`](https://rux-lang.dev/docs/cli/publish) # rux logout ## Purpose Forget the token stored for a Rux package registry ## Synopsis ```sh rux logout [options] ``` ## Behavior Removes only the stored token associated with the selected registry. It does not change the `RUX_TOKEN` environment variable or credentials for other registries. ## Arguments This command accepts no operands. ## Options | Option | Description | | ------------------ | --------------------------------------------- | | `--registry <url>` | Registry API base URL to forget the token for | Global options may appear before or after the command. See [Global options](https://rux-lang.dev/docs/cli/global). ## Output and exit status Primary results are written to stdout. Progress, warnings, and errors are written to stderr. Success exits 0, invalid command-line usage exits 2, and compiler, validation, filesystem, network, or generation failures exit 1 unless stated otherwise above. ## Examples ```sh rux logout rux logout --registry http://localhost:8080 ``` ## Environment variables `RUX_REGISTRY_URL` selects the registry when `--registry` is absent. The global color environment behavior is described under [Global options](https://rux-lang.dev/docs/cli/global#environment-variables). ## Related commands - [`rux login`](https://rux-lang.dev/docs/cli/login) # rux new ## Purpose Create a new Rux package in a new directory ## Synopsis ```sh rux new [name] [options] ``` ## Behavior Creates a new directory containing a manifest and starter source. `--executable`, `--shared`, `--static`, and `--source` are mutually exclusive; Executable is the default. `--path` selects the parent directory and `--namespace` sets the registry namespace. ## Arguments | Argument | Required | Description | | -------- | -------- | ------------------------------ | | `name` | Yes | The package or dependency name | ## Options | Option | Description | | ------------------ | ----------------------------------------------------------- | | `--executable` | Create an Executable package with an entry point (default) | | `--shared` | Create a SharedLibrary package | | `--static` | Create a StaticLibrary package | | `--source` | Create a SourceLibrary package compiled into its dependents | | `--namespace <ns>` | Set the registry namespace required to publish | | `--path <dir>` | Create the workspace in a specific directory | Global options may appear before or after the command. See [Global options](https://rux-lang.dev/docs/cli/global). ## Output and exit status Primary results are written to stdout. Progress, warnings, and errors are written to stderr. Success exits 0, invalid command-line usage exits 2, and compiler, validation, filesystem, network, or generation failures exit 1 unless stated otherwise above. ## Examples ```sh rux new App rux new App --executable rux new Io --shared --namespace Rux rux new Math --static rux new Json --source ``` ## Environment variables This command defines no command-specific environment variables. The global color environment behavior is described under [Global options](https://rux-lang.dev/docs/cli/global#environment-variables). ## Related commands - [`rux init`](https://rux-lang.dev/docs/cli/init) # rux pack ## Purpose Build the .ruxpkg archive that 'rux publish' uploads ## Synopsis ```sh rux pack [options] ``` ## Behavior Validates the publication profile and creates a deterministic `.ruxpkg` containing `Rux.toml`, `Src/`, and declared readme and license files. Workspaces and path dependencies cannot be packed. ## Arguments This command accepts no operands. ## Options | Option | Description | | --------------------- | ------------------------------------ | | `-o, --output <path>` | Write the archive to a specific path | Global options may appear before or after the command. See [Global options](https://rux-lang.dev/docs/cli/global). ## Output and exit status The default archive is `<Name>-<Version>.ruxpkg` below configured build output. `-o` and `--output` select an explicit path. Success exits 0, invalid command-line usage exits 2, and compiler, validation, filesystem, network, or generation failures exit 1 unless stated otherwise above. ## Examples ```sh rux pack rux pack --output Dist/Math.ruxpkg ``` ## Environment variables This command defines no command-specific environment variables. The global color environment behavior is described under [Global options](https://rux-lang.dev/docs/cli/global#environment-variables). ## Related commands - [`rux publish`](https://rux-lang.dev/docs/cli/publish) # rux publish ## Purpose Upload the package archive to a Rux package registry ## Synopsis ```sh rux publish [options] ``` ## Behavior Applies the same validation and packing rules as `rux pack`, then uploads an immutable version. `--dry-run` stops after validation and archive creation. Authentication tokens are never accepted as command-line options. ## Arguments This command accepts no operands. ## Options | Option | Description | | ------------------ | ------------------------------------------------ | | `--registry <url>` | Registry API base URL to publish to | | `--dry-run` | Validate and build the archive without uploading | Global options may appear before or after the command. See [Global options](https://rux-lang.dev/docs/cli/global). ## Output and exit status Primary results are written to stdout. Progress, warnings, and errors are written to stderr. Success exits 0, invalid command-line usage exits 2, and compiler, validation, filesystem, network, or generation failures exit 1 unless stated otherwise above. ## Examples ```sh rux publish rux publish --dry-run rux publish --registry http://localhost:8080 ``` ## Environment variables `RUX_REGISTRY_URL` sets the registry when `--registry` is absent. `RUX_TOKEN` takes precedence over a token stored by `rux login`. The global color environment behavior is described under [Global options](https://rux-lang.dev/docs/cli/global#environment-variables). ## Related commands - [`rux pack`](https://rux-lang.dev/docs/cli/pack) - [`rux login`](https://rux-lang.dev/docs/cli/login) # rux remove ## Purpose Remove a dependency from the manifest ## Synopsis ```sh rux remove [name] ``` ## Behavior Removes the dependency with the given import name from `Rux.toml`. It does not remove cached package versions; use `rux uninstall` for cache cleanup. ## Arguments | Argument | Required | Description | | -------- | -------- | ------------------------------ | | `name` | Yes | The package or dependency name | ## Options This command has no command-specific options. Global options still apply. Global options may appear before or after the command. See [Global options](https://rux-lang.dev/docs/cli/global). ## Output and exit status Primary results are written to stdout. Progress, warnings, and errors are written to stderr. Success exits 0, invalid command-line usage exits 2, and compiler, validation, filesystem, network, or generation failures exit 1 unless stated otherwise above. ## Examples ```sh rux remove Json rux remove Random ``` ## Environment variables This command defines no command-specific environment variables. The global color environment behavior is described under [Global options](https://rux-lang.dev/docs/cli/global#environment-variables). ## Related commands - [`rux add`](https://rux-lang.dev/docs/cli/add) - [`rux uninstall`](https://rux-lang.dev/docs/cli/uninstall) # rux run ## Purpose Build and execute a runnable target ## Synopsis ```sh rux run [options] [-- args...] ``` ## Behavior Builds an Executable package, then runs it. SharedLibrary, StaticLibrary, and SourceLibrary packages cannot run. `--define` overrides compile-time configuration and `--release` selects the release profile. As with `rux build`, an up-to-date artifact is reused unless `--no-cache` is given. Only arguments after `--` are passed to the child program. ## Arguments This command accepts no operands. ## Options | Option | Description | | ------------------------- | ------------------------------------------------------------------------- | | `--define <name[=value]>` | Set or override a config compile-time value | | `--no-cache` | Compile even when an earlier build of the same inputs is still up to date | | `--release` | Build with release profile | Global options may appear before or after the command. See [Global options](https://rux-lang.dev/docs/cli/global). ## Output and exit status Compiler progress and diagnostics use the usual streams. After a successful build, the command returns the child program's exit code. Success exits 0, invalid command-line usage exits 2, and compiler, validation, filesystem, network, or generation failures exit 1 unless stated otherwise above. ## Examples ```sh rux run rux run --release rux run -- --port 8080 ``` ## Environment variables `SOURCE_DATE_EPOCH` fixes compiler timestamps for reproducible builds. The global color environment behavior is described under [Global options](https://rux-lang.dev/docs/cli/global#environment-variables). ## Related commands - [`rux build`](https://rux-lang.dev/docs/cli/build) - [`rux test`](https://rux-lang.dev/docs/cli/test) # rux test ## Purpose Run package unit tests ## Synopsis ```sh rux test [options] [-- <test arguments>...] ``` ## Behavior Discovers the executable packages under `Tests/` and every package whose sources mark functions `#Test()`, builds them with test mode enabled, and runs them; a package of `#Test()` functions with no `Main` gets a generated runner. Arguments after `--` go to every test program, whose runner reads each plain argument as a name filter and runs the tests any of them matches: `rux test -- Parser Words` runs the tests whose names contain `Parser` or `Words`, and `--exact`, `--skip`, `--list` and `--quiet` refine that. A package with no test the filters match is reported as skipped, and the run fails when no package had one, so a misspelt name never passes with nothing run. Given arguments, each package's report is shown even when it passed, which is how `rux test -- --list` lists the tests. Up to `--jobs` test packages run at once, one per logical core by default. Workspaces include root and member test trees. `--define` and `--release` apply consistently to every test target. ## Arguments This command accepts no operands. ## Options | Option | Description | | ------------------------- | ------------------------------------------------------------------------- | | `--jobs <N>` | Run up to N test packages concurrently (default: one per logical core) | | `--define <name[=value]>` | Set or override a config compile-time value | | `--no-cache` | Compile every test package even when an earlier build is still up to date | | `--release` | Build with release profile | | `--target <triple>` | Build and run the tests for the specified target platform | Global options may appear before or after the command. See [Global options](https://rux-lang.dev/docs/cli/global). ## Output and exit status A summary counting test packages is written to stdout; compiler diagnostics and failed test details identify unsuccessful targets. The command returns 1 when any build or test fails, or when filters matched no test in any package. Success exits 0, invalid command-line usage exits 2, and compiler, validation, filesystem, network, or generation failures exit 1 unless stated otherwise above. ## Examples ```sh rux test rux test --release rux test -- Parser rux test -- --exact Parser::ReadsNumbers ``` ## Environment variables This command defines no command-specific environment variables. The global color environment behavior is described under [Global options](https://rux-lang.dev/docs/cli/global#environment-variables). ## Related commands - [`rux check`](https://rux-lang.dev/docs/cli/check) - [`rux run`](https://rux-lang.dev/docs/cli/run) # rux uninstall ## Purpose Uninstall dependencies from the local cache ## Synopsis ```sh rux uninstall rux uninstall [namespace]/[package] rux uninstall [namespace]/[package]@[requirement] rux uninstall [options] ``` ## Behavior Without an operand, removes cached versions of dependencies declared by the current manifest. A namespaced identity removes all matching versions, or only versions matching an `@requirement`. `--global` is mutually exclusive with an operand and clears the package cache. ## Arguments | Argument | Required | Description | | --------- | -------- | ------------------------------------------------------ | | `package` | No | A namespaced package identity and optional requirement | ## Options | Option | Description | | ---------- | ------------------------------------------------------- | | `--global` | Uninstall every package in the global environment cache | Global options may appear before or after the command. See [Global options](https://rux-lang.dev/docs/cli/global). ## Output and exit status Primary results are written to stdout. Progress, warnings, and errors are written to stderr. Success exits 0, invalid command-line usage exits 2, and compiler, validation, filesystem, network, or generation failures exit 1 unless stated otherwise above. ## Examples ```sh rux uninstall rux uninstall Rux/Json rux uninstall Rux/Json@0.1.0 rux uninstall --global ``` ## Environment variables `LOCALAPPDATA` on Windows or `HOME` elsewhere determines the user package cache. The global color environment behavior is described under [Global options](https://rux-lang.dev/docs/cli/global#environment-variables). ## Related commands - [`rux install`](https://rux-lang.dev/docs/cli/install) - [`rux list`](https://rux-lang.dev/docs/cli/list) # rux update ## Purpose Update dependencies ## Synopsis ```sh rux update [options] ``` ## Behavior Re-resolves manifest dependencies and installs the newest versions allowed by their requirements and target conditions. `--global` updates every cached identity. Older exact versions remain cached until `rux uninstall` removes them. ## Arguments This command accepts no operands. ## Options | Option | Description | | ------------------- | --------------------------------------------------- | | `--global` | Update all entries in the global environment cache | | `--registry <url>` | Registry API base URL to resolve and download from | | `--target <triple>` | Update dependencies applicable to a target platform | Global options may appear before or after the command. See [Global options](https://rux-lang.dev/docs/cli/global). ## Output and exit status Primary results are written to stdout. Progress, warnings, and errors are written to stderr. Success exits 0, invalid command-line usage exits 2, and compiler, validation, filesystem, network, or generation failures exit 1 unless stated otherwise above. ## Examples ```sh rux update rux update --global rux update --target linux-aarch64 rux update --registry http://localhost:8080 ``` ## Environment variables `RUX_REGISTRY_URL` sets the registry when `--registry` is absent. `LOCALAPPDATA` on Windows or `HOME` elsewhere determines the user package cache. The global color environment behavior is described under [Global options](https://rux-lang.dev/docs/cli/global#environment-variables). ## Related commands - [`rux install`](https://rux-lang.dev/docs/cli/install) - [`rux uninstall`](https://rux-lang.dev/docs/cli/uninstall) # rux version ## Purpose Show information about the Rux toolchain version ## Synopsis ```sh rux version ``` ## Behavior Prints the compiler's source version. Human-readable version output may include build date and time; the stable help JSON contract contains only the semantic version. ## Arguments This command accepts no operands. ## Options This command has no command-specific options. Global options still apply. Global options may appear before or after the command. See [Global options](https://rux-lang.dev/docs/cli/global). ## Output and exit status Version information is written to stdout and the command exits 0. Success exits 0, invalid command-line usage exits 2, and compiler, validation, filesystem, network, or generation failures exit 1 unless stated otherwise above. ## Examples ```sh rux version rux -V rux --version ``` ## Environment variables This command defines no command-specific environment variables. The global color environment behavior is described under [Global options](https://rux-lang.dev/docs/cli/global#environment-variables). ## Related commands - [`rux help`](https://rux-lang.dev/docs/cli/help) # CLI Reference The Rux compiler is the source of truth for this reference. The checked-in contract was generated by `rux 0.4.0` using help schema version 1. ## Command syntax ```sh rux [global-options] <command> [command-options] [operands] ``` Global options may appear before or after the command. Value options accept separated and equals forms. Only [`rux run`](https://rux-lang.dev/docs/cli/run) treats tokens after `--` as child-program arguments. ## Commands | Command | Purpose | | ---------------------------------------------------------- | ----------------------------------------------------- | | [`rux add`](https://rux-lang.dev/docs/cli/add) | Add a dependency to the manifest | | [`rux build`](https://rux-lang.dev/docs/cli/build) | Build the current package | | [`rux check`](https://rux-lang.dev/docs/cli/check) | Check package source code for errors without building | | [`rux clean`](https://rux-lang.dev/docs/cli/clean) | Remove build artifacts | | [`rux doc`](https://rux-lang.dev/docs/cli/doc) | Generate package documentation | | [`rux fmt`](https://rux-lang.dev/docs/cli/fmt) | Format source files and manifests | | [`rux help`](https://rux-lang.dev/docs/cli/help) | Show help information | | [`rux info`](https://rux-lang.dev/docs/cli/info) | Show package metadata and manifest information | | [`rux init`](https://rux-lang.dev/docs/cli/init) | Initialize a Rux package in the current directory | | [`rux install`](https://rux-lang.dev/docs/cli/install) | Install dependencies | | [`rux lint`](https://rux-lang.dev/docs/cli/lint) | Lint package source files | | [`rux list`](https://rux-lang.dev/docs/cli/list) | List dependencies | | [`rux login`](https://rux-lang.dev/docs/cli/login) | Store a registry token for publishing | | [`rux logout`](https://rux-lang.dev/docs/cli/logout) | Remove a stored registry token | | [`rux new`](https://rux-lang.dev/docs/cli/new) | Create a new Rux package | | [`rux pack`](https://rux-lang.dev/docs/cli/pack) | Build the publishable package archive | | [`rux publish`](https://rux-lang.dev/docs/cli/publish) | Publish the package to the registry | | [`rux remove`](https://rux-lang.dev/docs/cli/remove) | Remove a dependency from the manifest | | [`rux run`](https://rux-lang.dev/docs/cli/run) | Build and run the main executable | | [`rux test`](https://rux-lang.dev/docs/cli/test) | Run all test targets | | [`rux uninstall`](https://rux-lang.dev/docs/cli/uninstall) | Uninstall dependencies | | [`rux update`](https://rux-lang.dev/docs/cli/update) | Update dependencies | | [`rux version`](https://rux-lang.dev/docs/cli/version) | Show version information | ## Streams and exit status Primary output and JSON use stdout. Progress, warnings, and errors use stderr. Success, help, and version exit 0; invalid CLI usage exits 2; compiler or operational failures exit 1. [`rux run`](https://rux-lang.dev/docs/cli/run) returns the child program's exit code after a successful build. ## Structured help `rux help --json` returns the full stable contract. `rux help <command> --json` returns one command. Both use `schemaVersion: 1` and omit build timestamps. ## Start here - [Global options](https://rux-lang.dev/docs/cli/global) - [Build a package](https://rux-lang.dev/docs/cli/build) - [Check without linking](https://rux-lang.dev/docs/cli/check) - [Generate API documentation](https://rux-lang.dev/docs/cli/doc) - [Package and publish](https://rux-lang.dev/docs/packaging) # Package Types Manifest Version 1 accepts exactly four case-sensitive package types: | Type | Manifest value | `rux build` | `rux run` | Native artifact | | -------------- | ----------------- | ----------- | --------- | --------------- | | Executable | `"Executable"` | Yes | Yes | See below | | Shared library | `"SharedLibrary"` | Yes | No | See below | | Static library | `"StaticLibrary"` | Yes | No | See below | | Source library | `"SourceLibrary"` | No | No | None | `Program`, `Library`, and `Source` are retired spellings and are invalid; there are no compatibility aliases. An **Executable** must define `Main()`. Its artifact is `Name.exe` on Windows and `Name` on ELF targets and macOS. A **SharedLibrary** exports its public symbols. It produces `Name.dll` and the `Name.lib` import library on Windows, `libName.so` on ELF targets, or `libName.dylib` on macOS. A **StaticLibrary** preserves unresolved external references for the final native link. It produces `Name.lib` on Windows or `libName.a` on ELF targets and macOS. A **SourceLibrary** is checked on its own and compiled directly into whichever package depends on it. It has no standalone build or run artifact. ::note Rux 0.4.0 still consumes every Rux dependency from source. Declaring a local dependency as `SharedLibrary` or `StaticLibrary` does not make the consuming package link its binary artifact yet. :: The compile-time `#build.outputKind` value is `OutputKind::Executable`, `SharedLibrary`, `StaticLibrary`, or `SourceLibrary` when a package is checked on its own. Source compiled as a dependency observes the consuming package's output kind. For Rux 0.4.0, only **SourceLibrary** packages can be packed or published to a registry. Shared and static libraries are local native artifacts in this release. # Yanking Yanking withdraws a published version from **new** dependency resolution while leaving it available to builds that already depend on it. It is the way to retire a release that turned out to be broken, insecure, or published by mistake. ## What yanking does and does not do | Yanking **does** | Yanking **does not** | | -------------------------------------------------------- | ---------------------------------------- | | Stop resolvers choosing the version for a new dependency | Delete the release or its files | | Mark the version on the package page | Break builds that already resolved to it | | Take effect immediately | Remove the version from the index | A yanked version stays downloadable, and the registry keeps serving its metadata and archive. That is deliberate: a lockfile or a CI pipeline pinned to it keeps working instead of failing the moment you withdraw the release. Yanked versions stay in the resolver index for the same reason — an existing build must still be able to identify what it pinned. ::warning Yanking is not deletion and not a security control. The bytes remain public. If you published a credential, treat it as compromised and rotate it — yanking does not take it back. :: ## Yanking a version Open the package from your [dashboard](https://rux-lang.dev/packages/-/dashboard) and yank the version there. You need `owner` or `maintainer` [membership](https://rux-lang.dev/docs/packaging/namespaces#sharing-a-namespace) of the package's namespace, and — for the API — a token with the [`yank` scope](https://rux-lang.dev/docs/packaging/tokens#scopes). Unyanking restores the version to normal resolution. Both directions are idempotent: yanking an already-yanked version changes nothing and is not recorded twice. ::note There is no `rux yank` command yet. Yanking is done from the registry, or through the `PATCH /v1/packages/{namespace}/{package}/{version}` API with a `yank`-scoped token. :: ## When to yank Yank when a release actively harms the people who install it — a security problem, corrupted contents, a build that cannot possibly work, or an accidental publish. Do not yank simply because a newer version exists. Ordinary supersession is what [version requirements](https://rux-lang.dev/docs/packaging/dependencies#version-requirements) are for, and yanking healthy releases makes a package's history harder to depend on. ## After yanking Publish a fixed version. Because published versions are [immutable](https://rux-lang.dev/docs/packaging/versioning#immutability), the fix is always a new release rather than a correction of the old one — usually a patch bump, or a minor bump if the fix changed the API. Say what happened in your changelog and, for anything security-related, in the repository's advisories. A yank marks a version in the registry; it does not explain itself to the people who were using it. # Directory Layout Every package follows a predictable directory layout. The exact contents depend on the [package type](https://rux-lang.dev/docs/packaging/types). ## Executables An Executable package builds from `Src/Main.rux`, which defines `Main()`: ```text App/ ├── Rux.toml # Package manifest ├── Src/ # Source files │ ├── Main.rux # Contains the Main entry point │ └── ... # Other folders or source files ├── Bin/ # Created by the compiler │ ├── Debug/ # Debug build output │ └── Release/ # Release build output ├── Temp/ # Intermediate build files ├── README.md # Brief Markdown description ├── LICENSE.md # License of the package └── .gitignore # Excludes /Bin and /Temp from the repository ``` `Bin/` and `Temp/` are generated by the toolchain and should be listed in `.gitignore`. The root may also hold other directories such as `Art`, `Docs`, `Icons`, or `Images`. `README.md` and `LICENSE.md` are the conventional targets of the [manifest](https://rux-lang.dev/docs/packaging/manifest)'s `ReadmeFile` and `LicenseFile` fields, which is what makes them show up on the package's registry page. ## Native libraries SharedLibrary and StaticLibrary packages use the same layout without an entry point. Scaffolding creates `Src/Lib.rux`: ```text Math/ ├── Rux.toml # Package manifest ├── Src/ # Source files │ ├── Lib.rux # Library declarations and public symbols │ └── ... # Other folders or source files ├── Bin/ # Created by the compiler │ ├── Debug/ # Debug build output │ └── Release/ # Release build output ├── Temp/ # Intermediate build files ├── README.md # Brief Markdown description ├── LICENSE.md # License of the package └── .gitignore # Excludes /Bin and /Temp from the repository ``` The output filename follows the platform conventions listed under [Package Types](https://rux-lang.dev/docs/packaging/types). ## Source libraries SourceLibrary packages cannot be built directly. They are compiled into other projects as [dependencies](https://rux-lang.dev/docs/packaging/dependencies), so they have no `Bin/` output: ```text Core/ ├── Rux.toml # Package manifest ├── Src/ # Source files │ ├── Lib.rux # Source-library declarations │ └── ... # Other folders or source files ├── README.md # Brief Markdown description ├── LICENSE.md # License of the package └── .gitignore # Excludes some items if necessary ``` # Package Manifest Every Rux package is described by a `Rux.toml` file at its root. It carries the package's identity, metadata, build settings, and dependencies, and it is required for anything that takes part in the build system or a workspace. ```toml [Manifest] Version = 1 MinRux = "0.4.0" [Package] Namespace = "Acme" Name = "Widget" Version = "1.2.3" Type = "SourceLibrary" Description = "A widget for every occasion" Authors = ["Your Name <name@mail.com>"] License = "MIT" [Dependencies] Io = { Namespace = "Rux", Version = "^1.0.0" } ``` The file is UTF-8 and uses a deliberately small subset of [TOML](https://toml.io){rel=""nofollow""}: basic quoted strings, integers, booleans, arrays of quoted strings, the dependency inline table, comments, and the tables documented on this page. Section names, field names, and enum values are **PascalCase**, and parsing is case-sensitive. ::warning Manifest Version 1 is strict. Unknown sections and unknown fields are **errors**, not warnings — a typo fails the build instead of silently changing it. Duplicate keys, wrong value types, missing required fields, and invalid identities are rejected the same way, each with the file, line, and column of the offending token. :: ## `[Manifest]` The schema header. Every manifest starts with one. | Field | Presence | Contract | | --------- | ------------------------------------- | ------------------------------------------------------ | | `Version` | Required | Integer schema version; `1` is the only accepted value | | `MinRux` | Optional locally, required to publish | Semantic version, at least `0.4.0` | `MinRux` is the oldest compiler release that can build the package. A compiler older than the declared minimum refuses to build it. Leaving it out keeps `rux new` and `rux init` free of a field only publication needs. ::note `[Manifest].Version` is the schema version of the file. `[Package].Version` is your package's own release number. They are unrelated. :: ## `[Package]` Identity and metadata. ```toml [Package] Namespace = "Acme" Name = "Widget" Version = "1.2.3" Type = "SharedLibrary" Description = "A widget for every occasion" Authors = ["Your Name <name@mail.com>"] Keywords = ["Widget", "Ui"] License = "MIT" LicenseFile = "LICENSE.md" Repository = "https://github.com/acme/widget" Homepage = "https://acme.dev" ReadmeFile = "README.md" ``` | Field | Presence | Contract | | ------------- | ------------------------------------- | ----------------------------------------------------------------------------------------- | | `Namespace` | Optional locally, required to publish | One [identity segment](https://rux-lang.dev/docs/packaging/namespaces) | | `Name` | Required | One identity segment | | `Version` | Required | Strict [Semantic Version](https://rux-lang.dev/docs/packaging/versioning), no leading `v` | | `Type` | Required | Exactly `Executable`, `SharedLibrary`, `StaticLibrary`, or `SourceLibrary` | | `Description` | Optional | Short summary | | `Authors` | Optional | Array of strings | | `Keywords` | Optional | Array of identity segments, unique after normalization | | `License` | Optional | SPDX expression | | `LicenseFile` | Optional | Package-relative path | | `Repository` | Optional | Absolute `http`/`https` URL with a host and no credentials | | `Homepage` | Optional | Absolute `http`/`https` URL with a host and no credentials | | `ReadmeFile` | Optional | Package-relative path | [`Type`](https://rux-lang.dev/docs/packaging/types) decides what the package produces and which commands accept it. `Authors` must be an array — the older scalar spelling is invalid. The two licence fields are independent, and setting both is the norm. `License` is what machines read — it is the field a dependency-tree licence audit and the registry's filters work from. `LicenseFile` is what people read: it points at the licence text shipped inside the package, so it carries the copyright holder and year that an SPDX identifier cannot express, it is covered by the release checksum, and it stays readable offline. The conventional target is the `LICENSE.md` in the standard [package layout](https://rux-lang.dev/docs/packaging/layout). A licence with no SPDX identifier uses SPDX's own `LicenseRef-` form alongside the file: ```toml [Package] License = "LicenseRef-Acme-Commercial" LicenseFile = "LICENSE.md" ``` ## `[Dependencies]` Each key is the name you import the dependency under; each value is an inline table. ```toml [Dependencies] Io = { Namespace = "Rux", Version = "^1.0.0" } Json = { Namespace = "Acme", Package = "FastJson", Version = ">=2.0.0, <3.0.0", TargetOS = ["Linux", "MacOS"] } Util = { Path = "../Util", TargetOS = ["Windows"] } ``` | Form | Requires | Notes | | -------- | ---------------------- | -------------------------------------------------------------------------- | | Registry | `Namespace`, `Version` | Resolved from the [registry](https://rux-lang.dev/docs/packaging/registry) | | Path | `Path` | A local directory; cannot carry `Namespace`/`Version` | Either form may set `Package` when the dependency's own name differs from the import name; it defaults to the import name. Two dependencies cannot produce the same import name after normalization. Either form may also set a non-empty, duplicate-free `TargetOS` allow-list. The dependency applies only when the selected target operating system appears in the list. Omitting `TargetOS` makes it unconditional. Values are case-sensitive and exactly `Windows`, `Linux`, `MacOS`, `FreeBSD`, `OpenBSD`, `NetBSD`, `DragonFlyBSD`, or `Illumos`. ::warning A path dependency makes a manifest **unpublishable** — the directory it names exists only on your machine. See [Dependencies](https://rux-lang.dev/docs/packaging/dependencies) for the full requirement syntax. :: ## `[Build]` Optional build settings. ```toml [Build] Output = "Dist" [Build.Defines] Channel = "Nightly" CheckedArithmetic = true Retries = 3 ``` `Output` is a package-relative path and defaults to `Bin`. `[Build.Defines]` is an optional table of string, boolean, and integer values exposed to [compile-time configuration](https://rux-lang.dev/docs/lang/comptime/context) through `#config`, and overridable per build with `--define NAME[=VALUE]`. ## Workspaces A workspace manifest groups member packages instead of describing one: ```toml [Manifest] Version = 1 [Workspace] Packages = [ "Packages/Math", "Packages/Memory", ] ``` `Packages` is a non-empty, duplicate-free array of explicit relative paths — no globs, no parent traversal. `[Workspace]` and `[Package]` are mutually exclusive; a manifest has exactly one of them. A workspace declares no dependencies or build settings and cannot be published. ## Paths Manifest paths are UTF-8, relative, and `/`-separated. Backslashes, absolute roots, empty components, and `.` components are invalid. A field whose name ends in `File` names a path **inside** the package — it must exist in the published archive, and like workspace paths it rejects `..`. Dependency and output paths may begin with `..` components, but parent traversal cannot follow a normal component. ## Validation profiles The rules applied depend on the operation, not on anything stored in the file. | Profile | Applies to | Accepts | | --------------- | ------------------------------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------- | | **Local** | `build`, `check`, `run`, `test`, … | Package and workspace manifests; `Namespace` and `MinRux` optional; path dependencies allowed | | **Publication** | [`pack`](https://rux-lang.dev/docs/cli/pack), [`publish`](https://rux-lang.dev/docs/cli/publish) | Package manifests only; `Namespace` and `MinRux` required; path dependencies rejected | Both `rux pack` and `rux publish` apply the publication profile before doing any other work, so a manifest that cannot be published is reported locally rather than by the registry. ## Canonical form `rux fmt --manifest-only`, `rux add`, `rux remove`, `rux new`, and `rux init` all write the same order: `[Manifest]`, then `[Package]` or `[Workspace]`, then `[Dependencies]`, `[Build]`, and `[Build.Defines]`. Only recognized fields are written. Metadata arrays and `TargetOS` values keep their order; dependency and define keys use a stable deterministic order. In a dependency inline table, `TargetOS` follows `Version` or `Path`. Changing a dependency with `rux add` preserves its existing target condition. ## Limits All limits count UTF-8 bytes. | Resource | Limit | | --------------------------------- | -------: | | Manifest source | 65,536 | | Dependencies / workspace packages | 256 each | | Defines per table | 128 | | Authors / keywords | 32 each | | Description | 2,048 | | Author | 256 | | URL or path | 2,048 | | SPDX expression / version range | 512 | | Semantic version | 256 | | Identity segment | 64 | # Dependencies Dependencies are other packages your project builds against. They are declared in the [`[Dependencies]`](https://rux-lang.dev/docs/packaging/manifest#dependencies) table of `Rux.toml` and managed with the `rux` command-line tool. ## Declaring a dependency Each key is the name you import the dependency under, and each value is an inline table: ```toml [Dependencies] Io = { Namespace = "Rux", Version = "^1.0.0" } Json = { Namespace = "Acme", Package = "FastJson", Version = ">=2.0.0, <3.0.0" } Windows = { Namespace = "Rux", Version = "0.1.0", TargetOS = ["Windows"] } Bsd = { Path = "../Bsd", TargetOS = ["DragonFlyBSD", "FreeBSD", "NetBSD", "OpenBSD"] } ``` A **registry** dependency needs a `Namespace` and a `Version`. A **path** dependency needs a `Path` and cannot carry either. Both may set `Package` when the dependency's own name differs from the import name. Both forms may set `TargetOS` to a non-empty allow-list. The dependency participates in builds and resolution only when the selected target OS appears in the list. Omitting it means every target. The exact supported names are `Windows`, `Linux`, `MacOS`, `FreeBSD`, `OpenBSD`, `NetBSD`, `DragonFlyBSD`, and `Illumos`; duplicates and other spellings are invalid. An active import of a dependency that excludes the selected build target is an error. Imports removed by `when #target.os` are inactive and therefore allowed, so platform packages should guard their imports with the same target condition as their dependency entry. ::warning A path dependency is fine for local development but makes the manifest **unpublishable**. Replace it with a registry dependency before you [publish](https://rux-lang.dev/docs/packaging/publishing). :: ## Adding and removing `rux add` writes the entry for you: ```sh # Registry dependency, any stable version rux add Acme/Widget # Registry dependency with a requirement rux add Acme/Widget@^0.1.0 # Local path dependency rux add Util --path ../Util ``` Omitting the requirement writes `*`. A registry dependency needs a namespace — `rux add Widget` alone is rejected with `registry dependency 'Widget' must include a namespace`, because the bare name does not identify a package in the registry. ::note \*\*Standard packages are declared by hand.\*\*The packages in the `Rux` namespace ship with the toolchain and are not served by the registry, so `rux add Rux/Io` fails with a registry 404. Write their line into `Rux.toml` yourself: `Io = { Namespace = "Rux", Version = "*" }`. :: Remove one with [`rux remove`](https://rux-lang.dev/docs/cli/remove): ```sh rux remove Json ``` ## Version requirements A requirement is a comma-separated **intersection** of comparators; whitespace around them is insignificant. | Requirement | Matches | | ----------------- | -------------------------------------------- | | `*`, `x`, `X` | Any stable version; cannot be combined | | `=1.2.3` | Exactly that version | | `>=1.2.0, <2.0.0` | Both bounds at once | | `^1.2.3` | `>=1.2.3, <2.0.0` | | `^0.2.3` | `>=0.2.3, <0.3.0` | | `^0.0.3` | `>=0.0.3, <0.0.4` | | `~1.2.3` | `>=1.2.3, <1.3.0` | | `1.2.3` | Same as `^1.2.3` — a bare operand is a caret | Operands may be partial (`^1.0`, `2`) or use a trailing component wildcard (`1.2.*`). A numeric component cannot follow a wildcard, and a prerelease or build suffix needs a complete `major.minor.patch` operand. Requirements reject OR expressions, hyphen ranges, space-separated comparators, more than three numeric components, and more than 32 comparators. A prerelease is only eligible when some comparator names the same `major.minor.patch` and carries a prerelease operand of its own, so `^1.0.0` never selects `2.0.0-beta.1`. See [Versioning](https://rux-lang.dev/docs/packaging/versioning) for how versions are ordered. ## Installing and updating Download everything the manifest declares: ```sh rux install ``` Install for another supported target without changing hosts: ```sh rux install --target windows-x86_64 ``` Update to the latest compatible versions: ```sh # Packages listed in Rux.toml rux update # Everything in the local store rux update --global # Resolve and update for Linux rux update --target linux-x86_64 ``` Both commands default to the host target. Before resolution they discard root requirements and transitive edges whose `TargetOS` excludes the selected target, so filtered dependencies cannot create version conflicts or downloads. Naming a package explicitly with `rux install` still installs that root package; only its conditional transitive edges are filtered. ## Package storage Downloaded packages live in a shared, per-user store separate from any project: | Platform | Location | | ------------- | ----------------------------- | | Windows | `%LOCALAPPDATA%\Rux\Packages` | | Linux / macOS | `~/.rux/packages` | Each package occupies its own subdirectory named after the package. The store is managed by [`rux install`](https://rux-lang.dev/docs/cli/install) and [`rux update`](https://rux-lang.dev/docs/cli/update) and should not be edited by hand; use [`rux uninstall`](https://rux-lang.dev/docs/cli/uninstall) to remove entries. ## Workspaces Inside a [workspace](https://rux-lang.dev/docs/packaging/manifest#workspaces), a registry dependency that matches a member package by normalized identity resolves to that member instead of the registry. That is what lets the packages in one repository depend on each other in publishable registry form while still building entirely from the local tree. # The Registry The Rux registry hosts published packages. It is browsable at [rux-lang.dev/packages](https://rux-lang.dev/packages) and served programmatically from `https://api.rux-lang.dev`. Reading from it — browsing, searching, downloading, installing — needs no account. ## Finding a package The [registry home](https://rux-lang.dev/packages) is the catalog. Search matches package names, namespaces, descriptions and keywords; an empty query browses everything. Narrow the results by namespace, keyword or package type, and order them by relevance, name, total or recent downloads, most recently updated, or most recently added. Search is literal rather than fuzzy. Punctuation and wildcard characters are treated as text, so `http-client` searches for that phrase instead of being read as a pattern. Packages also carry [keywords](https://rux-lang.dev/packages/-/keywords), which are a good way into a subject area when you do not yet know what a package is called. ## The package page Each package has a page at `/packages/<namespace>/<package>` showing: - every published **version**, newest first, with [yanked](https://rux-lang.dev/docs/packaging/yanking) releases marked; - the **manifest metadata** of the selected release — description, authors, keywords, license, repository and homepage links, and the minimum Rux version it needs; - its **dependencies** and the packages that **depend on it**; - the **README** as published, and the **license file** when the manifest names one; - the **SHA-256 checksum** and byte size of the release archive; and - **download statistics** over the last thirty days and all time. Everything shown comes from the release that was uploaded. The registry does not edit or re-render what you publish. ## Installing from the registry Add a dependency by its qualified identity and install it: ```sh rux add Acme/Widget@^1.0.0 rux install ``` `rux add` records the entry in `Rux.toml`; [`rux install`](https://rux-lang.dev/docs/cli/install) downloads it and everything it depends on into the shared [package store](https://rux-lang.dev/docs/packaging/dependencies#package-storage). See [Dependencies](https://rux-lang.dev/docs/packaging/dependencies) for requirement syntax and updating. ## Identity is case-insensitive Registry lookup lowercases ASCII letters and folds `_` to `-`, so `Rux/My_Pkg` and `rux/my-pkg` are the same package. Tools and pages preserve the spelling an author chose for display. This is described in full under [Namespaces](https://rux-lang.dev/docs/packaging/namespaces). ## Availability The registry is a live service, so registry-backed commands need network access. A package already in your local store builds offline; workspace members resolve locally and never consult the registry at all. # Namespaces A published package is identified by two parts: a **namespace** and a **name**. The namespace is the account or organisation that owns the package, so `Rux/Io` and `Acme/Io` are different packages that happen to share a name. ```toml [Package] Namespace = "Acme" Name = "Widget" ``` Together they form the identity used everywhere — `Acme/Widget` on the command line, in a dependency entry, and in the registry URL. ::note `Namespace` is optional locally. A package without one is **local-only**: it builds, runs, and can be depended on by path, but it cannot be published. `rux new` and `rux init` take an optional `--namespace <Namespace>` when you already know where a package will live. :: ## Identity segments Namespaces, package names, keywords, and dependency import names all use the same grammar. A segment is 1 to 64 bytes of ASCII alphanumeric characters separated by single `-` or `_` characters. It cannot start or end with a separator, and it cannot contain two separators in a row. | Valid | Invalid | Why | | -------- | --------- | ---------------------- | | `Rux` | `-Pkg` | Leading separator | | `My_Pkg` | `Pkg-` | Trailing separator | | `my-pkg` | `My__Pkg` | Adjacent separators | | `7zip` | `My.Pkg` | `.` is not a separator | ## Normalization Lookup and uniqueness lowercase ASCII letters and fold `_` to `-`. `Rux/My_Pkg` and `rux/my-pkg` therefore identify the same package, and only one of them can be claimed. Tools preserve the spelling you wrote for display, so a package published as `Acme/FastJson` keeps its capitals on its page and in `Rux.toml` while resolving as `acme/fastjson`. Registry URLs use the normalized form. Keywords follow the same rule and must stay unique after normalization, so `["Http", "HTTP"]` is rejected as a duplicate. ## Claiming a namespace Sign in to the registry with GitHub and claim one from your [dashboard](https://rux-lang.dev/packages/-/dashboard). Claiming makes you its first **owner**. Because normalized spellings collide, `Foo_Bar` and `foo-bar` cannot be claimed separately. A namespace you own is the only place you can publish. Attempting to publish into a namespace that does not exist, or one you are not a member of, is rejected — see [Publishing](https://rux-lang.dev/docs/packaging/publishing#when-publishing-fails). ## Sharing a namespace A namespace has two roles: | Role | Can | | ------------ | -------------------------------------------------------------------------------- | | `owner` | Publish, yank, invite and remove members, change roles, and manage the namespace | | `maintainer` | Publish and yank | Owners invite an existing registry user by GitHub login from the namespace page in the dashboard. Invitations expire after seven days, and only one unresolved invitation can exist for a user and namespace at a time. The invitee accepts or declines from their own dashboard; an owner can revoke an invitation before it is accepted. A namespace always keeps at least one owner. Removing the last one is refused, and so is deleting an account that is the final owner of any namespace — promote or add another owner first. # API Tokens An API token lets the `rux` command line act on your registry account without a browser. Publishing needs one; browsing and installing do not. ## Creating a token Sign in to the registry with GitHub, then open [Dashboard → Tokens](https://rux-lang.dev/packages/-/dashboard/tokens) and create one. A token has: - a **display name**, so you can tell your tokens apart later; - one to three **scopes**; and - an optional **expiry** — 30, 90, or 365 days, a date you choose, or never. ::warning The credential is shown **once**, in the response to creating it. The registry stores only a SHA-256 hash and a short display prefix, so a lost token cannot be recovered — revoke it and create another. :: ## Scopes A token carries only the permissions you give it. Choose the narrowest set that does the job. | Scope | Allows | | ----------- | ------------------------------------------------------------------------------ | | `publish` | Publishing new package versions | | `yank` | [Yanking and unyanking](https://rux-lang.dev/docs/packaging/yanking) a version | | `namespace` | Managing namespaces, members, and invitations | A token with the wrong scope is rejected with a clear error rather than partially succeeding. Scopes do not grant namespace membership: a `publish` token can only publish into namespaces its owner already belongs to. ## Using a token On your own machine, hand the token to [`rux login`](https://rux-lang.dev/docs/cli/login) once and every later [`rux publish`](https://rux-lang.dev/docs/cli/publish) picks it up: ```sh rux login ``` You are prompted for the token, and your typing is not echoed. It is stored per registry in a file only your account can read — `%LOCALAPPDATA%\Rux\Credentials.toml` on Windows, `~/.rux/credentials.toml` elsewhere — and [`rux logout`](https://rux-lang.dev/docs/cli/logout) removes it again. There is deliberately **no `--token` flag**, and `rux login` reads the token from standard input rather than an argument for the same reason: a credential on the command line ends up in shell history and in the process list, where other users on the machine can read it. ### In CI Set `RUX_TOKEN` instead. It overrides any stored token, so a job is never shadowed by a file left behind on a self-hosted runner. ::code-group ```sh [Linux / macOS] export RUX_TOKEN='rux_pat_...' rux publish ``` ```powershell [Windows] $env:RUX_TOKEN = 'rux_pat_...' rux publish ``` :: Store the token as an encrypted secret and expose it as `RUX_TOKEN` for the publishing step only. ::note Prefer `rux login` to exporting `RUX_TOKEN` from your shell profile. An exported variable is inherited by **every** process your shell starts and shows up in `env` dumps pasted into bug reports; the credentials file is read by `rux` alone, and only when it publishes. :: ## Managing tokens The tokens page lists every token you have created, newest first, including expired and revoked ones. It shows each token's display name, prefix, scopes, creation time, last use, expiry, and status — `active`, `expired`, or `revoked`. It never shows a credential again. Revoke a token the moment you suspect it has leaked. Revocation takes effect immediately, and revoked tokens stay in the list as history. Revoking is not the same as [`rux logout`](https://rux-lang.dev/docs/cli/logout), which only forgets the token on the machine you run it on — a leaked token has to be revoked here. Releases published with a revoked token are unaffected: publication is permanent and independent of the credential that made it. ## Deleting your account Deleting your registry account revokes every session and token you hold and clears your GitHub identity. Packages you published stay published — see [Yanking](https://rux-lang.dev/docs/packaging/yanking) for what can and cannot be withdrawn. # Publishing Publishing uploads a package release to the [registry](https://rux-lang.dev/docs/packaging/registry), where anyone can depend on it. A published version is permanent. ## Before you publish Publication applies stricter rules than a local build. Your manifest must: - declare a [`Namespace`](https://rux-lang.dev/docs/packaging/namespaces) you own or maintain; - declare `MinRux`, the oldest compiler release that can build the package; - describe a package, not a [workspace](https://rux-lang.dev/docs/packaging/manifest#workspaces); and - carry **no path dependencies** — every dependency must resolve from the registry. - use `Type = "SourceLibrary"`; Rux 0.4.0 does not publish native binary artifacts. ```toml [Manifest] Version = 1 MinRux = "0.4.0" [Package] Namespace = "Acme" Name = "Widget" Version = "1.0.0" Type = "SourceLibrary" ``` You also need an [API token](https://rux-lang.dev/docs/packaging/tokens) with the `publish` scope. Store it once with [`rux login`](https://rux-lang.dev/docs/cli/login): ```sh rux login ``` In CI, set `RUX_TOKEN` instead — it overrides any stored token. Nothing about publishing builds or checks your package, so run [`rux check`](https://rux-lang.dev/docs/cli/check) first. ::warning Both `rux pack` and `rux publish` accept only SourceLibrary packages in Rux 0.4.0. They reject Executable, SharedLibrary, and StaticLibrary before credential lookup, archive creation, filesystem output, or network access. Binary distribution and binary dependency consumption will be enabled only by a later coordinated compiler and registry release. :: ## The package archive A release is a single `.ruxpkg` file — a ZIP archive containing: | Entry | Included when | | ------------ | ----------------------------------------------- | | `Rux.toml` | Always, at the archive root | | `Src/**` | Always; at least one `Src/**/*.rux` is required | | `README.md` | `Package.ReadmeFile` names it | | `LICENSE.md` | `Package.LicenseFile` names it | Build one without uploading anything: ```sh rux pack ``` It is written to your build output directory as `<Name>-<Version>.ruxpkg`, or wherever `--output` says. Entries are sorted and carry a fixed timestamp, so packing the same tree twice produces byte-identical archives. Limits: 5 MiB for the archive, 10 MiB expanded, 2 MiB for any single file, 64 KiB for the manifest, and 1,024 entries. ## Publishing a release Validate first — this does everything except upload, and needs no token: ```sh rux publish --dry-run ``` Then publish: ```sh rux publish ``` ```text Packed Acme/Widget 1.0.0 (12 files, 24.1 KiB) Uploading to https://api.rux-lang.dev Published Acme/Widget 1.0.0 ``` The release appears immediately at `/packages/acme/widget`. ## Publishing a new version Bump `Package.Version` and publish again. An existing version cannot be replaced — see [Versioning](https://rux-lang.dev/docs/packaging/versioning) for how to choose the next number, and [Yanking](https://rux-lang.dev/docs/packaging/yanking) if you need to withdraw one. ## When publishing fails Problems in your manifest or archive are reported locally, before anything is uploaded. The registry reports the rest. | Message | Cause and fix | | ----------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------- | | `publication requires [Package].Namespace` | Add a `Namespace` to the manifest | | `publication requires [Manifest].MinRux` | Add `MinRux`, at least `0.4.0` | | `dependency '…' uses Path = "…"` | Replace the path dependency with a registry one | | `a workspace cannot be published` | Run the command from a member package | | `[Package].Type = "…" cannot be published by Rux 0.4.0; this release publishes only Type = "SourceLibrary"` | Change the package to `SourceLibrary`; native artifacts are local-only in 0.4.0 | | `no credential for …` | Run [`rux login`](https://rux-lang.dev/docs/cli/login), or set `RUX_TOKEN` | | `namespace '…' is not claimed` | [Claim it](https://rux-lang.dev/docs/packaging/namespaces#claiming-a-namespace) first | | `does not own or maintain namespace '…'` | Ask an owner to invite you | | `lacks the 'publish' scope` | Create a token with the right [scope](https://rux-lang.dev/docs/packaging/tokens#scopes) | | `version … is already published` | Bump `Package.Version` — published versions are immutable | ## Publishing to another registry `rux publish` targets the official registry by default. `--registry <url>` or the `RUX_REGISTRY_URL` environment variable points it somewhere else, which is how you exercise the whole flow against a local registry before releasing for real. ```sh rux login --registry http://localhost:8080 rux publish --registry http://localhost:8080 ``` Credentials are stored per registry, so logging in to a local registry never sends it the token you use for the official one. # Versioning Every release carries a version in `Package.Version`. Rux uses strict [Semantic Versioning 2.0.0](https://semver.org){rel=""nofollow""}, without a leading `v`. ```toml [Package] Version = "1.2.3" ``` ## What the numbers mean `MAJOR.MINOR.PATCH`, incremented by the kind of change you made: | Part | Increment when | | ------- | ------------------------------------------------------------- | | `MAJOR` | You made an incompatible change to your public API | | `MINOR` | You added functionality that existing code keeps working with | | `PATCH` | You fixed something without changing the API | Below `1.0.0` the leading zero absorbs the meaning: a `0.x` release may break compatibility on a minor bump, which is why `^0.2.3` only allows `<0.3.0`. See [version requirements](https://rux-lang.dev/docs/packaging/dependencies#version-requirements). ## Prereleases A prerelease suffix marks a version as not yet ready: ```toml Version = "2.0.0-alpha.1" ``` Prereleases sort **before** their release — `2.0.0-alpha.1` precedes `2.0.0` — and are never selected by an ordinary requirement. A resolver picks one only when a comparator names the same `major.minor.patch` and carries a prerelease of its own, so `^1.0.0` will never quietly upgrade you to `2.0.0-beta.1`. ## Build metadata A `+` suffix carries build metadata: ```toml Version = "1.0.0+linux" ``` Metadata is **ignored when ordering** versions but is **part of publication identity**. `1.0.0+linux` and `1.0.0+windows` are two distinct releases that compare as equal for requirement matching. Most packages never need this; reach for it only when one logical version genuinely ships as several artifacts. ## Immutability **A published version can never be replaced.** Publishing a version that already exists is rejected: ```text error: version 1.0.0 of Acme/Widget is already published; published versions are immutable, so publish a new version ``` Immutability is what makes a build reproducible: a dependency resolved today resolves to the same bytes next year. It also means a mistake ships. If you published something broken, publish a fixed patch release and [yank](https://rux-lang.dev/docs/packaging/yanking) the bad one — there is no way to overwrite or delete it. Because build metadata is part of identity, `1.0.0+fix` counts as a different version from `1.0.0` and will be accepted. Do not use that as a substitute for a patch bump: resolvers treat the two as equal precedence, so which one a build selects is not something you control. ## Choosing MinRux `Manifest.MinRux` is the oldest compiler release that can build your package, and it is required to publish. Set it to the earliest version you have actually tested against, not to whatever you happen to have installed — a compiler older than the declared minimum refuses to build the package at all. Raising `MinRux` in a new release is a compatibility change for anyone on an older toolchain, so treat it like any other breaking change when choosing the version number. # Packaging A **package** is the unit Rux builds, ships, and depends on. Every package is a directory with a [`Rux.toml` manifest](https://rux-lang.dev/docs/packaging/manifest) at its root and its sources under `Src/`. That is true whether the package never leaves your machine or ends up on the public registry. This section follows a package through its whole life: describing it, depending on other packages, finding it, and publishing it for other people to use. ## Local packaging Everything here works offline, with no account and no registry. | Page | Covers | | ---------------------------------------------------------------- | ---------------------------------------------------------- | | [Package Types](https://rux-lang.dev/docs/packaging/types) | Executable, shared, static, and source libraries | | [Directory Layout](https://rux-lang.dev/docs/packaging/layout) | Where sources, build output, and metadata live | | [Package Manifest](https://rux-lang.dev/docs/packaging/manifest) | Every field of `Rux.toml`, and the rules each one follows | | [Dependencies](https://rux-lang.dev/docs/packaging/dependencies) | Declaring, resolving, and updating what your package needs | ## The registry The public registry at [rux-lang.dev/packages](https://rux-lang.dev/packages) hosts published packages. Reading from it needs no account; publishing to it does. | Page | Covers | | ------------------------------------------------------------ | ------------------------------------------------------------- | | [The Registry](https://rux-lang.dev/docs/packaging/registry) | Browsing, searching, and installing published packages | | [Namespaces](https://rux-lang.dev/docs/packaging/namespaces) | Package identity, claiming a namespace, and sharing ownership | | [API Tokens](https://rux-lang.dev/docs/packaging/tokens) | Credentials that let the CLI act on your behalf | | [Publishing](https://rux-lang.dev/docs/packaging/publishing) | Preparing a package and uploading a release | | [Versioning](https://rux-lang.dev/docs/packaging/versioning) | Semantic Versioning, immutability, and version requirements | | [Yanking](https://rux-lang.dev/docs/packaging/yanking) | Withdrawing a release without breaking existing builds | ## From a new package to a published one The short version of the whole section: ```sh rux new Widget --source --namespace Acme # Create a publishable package rux add Acme/Json # Depend on something rux check # Make sure it compiles rux pack # Inspect the archive rux publish --dry-run # Validate without uploading rux publish # Release it ``` Each step has its own page here, and every command has a page in the [CLI reference](https://rux-lang.dev/docs/cli). ::note Publishing has two requirements a local package does not: a [`Namespace`](https://rux-lang.dev/docs/packaging/namespaces) and a `MinRux` version. Both are described in the [manifest reference](https://rux-lang.dev/docs/packaging/manifest). :: # Core Core language intrinsics. ## Installation Add `Core` to the `[Dependencies]` table of your package's `Rux.toml`: ```toml [Dependencies] Core = { Namespace = "Rux", Version = "0.1.0" } ``` Standard packages are declared by hand: the registry does not serve them, so `rux add Rux/Core` cannot add them. ## Guide Core declares primitive associated constants, diagnostics, value protocols, and compile-time context. Core is optional. Scalar types, arithmetic, arrays, inferred string literals, and range syntax work without it. Every primitive type is built into the compiler; Core extends them, and importing a primitive from Core imports its associated constants. Slice and range fields are compiler-owned. A replacement package can provide the same extensions and intrinsic declarations; the compiler assigns no privilege to the name or manifest identity of Core. ### What it provides - **Compile-time context** — [`#target`](https://rux-lang.dev/docs/api/core/target#target-constant) (os, arch, abi, endian, pointer width, data model, object format, triple, `HasFeature`), [`#build`](https://rux-lang.dev/docs/api/core/build#build-constant), [`#compiler`](https://rux-lang.dev/docs/api/core/compiler#compiler-constant), [`#source`](https://rux-lang.dev/docs/api/core/source#source-constant), and [`#config`](https://rux-lang.dev/docs/api/core/config#config-constant), together with the enums they are typed by: [`OperatingSystem`](https://rux-lang.dev/docs/api/core/target#operating-system), [`Architecture`](https://rux-lang.dev/docs/api/core/target#architecture), [`ApplicationBinaryInterface`](https://rux-lang.dev/docs/api/core/target#application-binary-interface), [`Endianness`](https://rux-lang.dev/docs/api/core/target#endianness), [`DataModel`](https://rux-lang.dev/docs/api/core/target#data-model), [`ObjectFormat`](https://rux-lang.dev/docs/api/core/target#object-format), [`BuildMode`](https://rux-lang.dev/docs/api/core/build#build-mode), [`OptimizationMode`](https://rux-lang.dev/docs/api/core/build#optimization-mode), [`OutputKind`](https://rux-lang.dev/docs/api/core/build#output-kind), [`TargetFeature`](https://rux-lang.dev/docs/api/core/target#target-feature). - **Atomic** — [`AtomicLoad`](https://rux-lang.dev/docs/api/core/atomic#atomic-load), [`AtomicStore`](https://rux-lang.dev/docs/api/core/atomic#atomic-store), [`AtomicExchange`](https://rux-lang.dev/docs/api/core/atomic#atomic-exchange), [`AtomicCompareExchange`](https://rux-lang.dev/docs/api/core/atomic#atomic-compare-exchange) and [`AtomicFetchAdd`](https://rux-lang.dev/docs/api/core/atomic#atomic-fetch-add)/`Sub`/`And`/`Or`/`Xor` act on one integer of 8 to 64 bits, `bool` or pointer so that no other thread sees them half done, and [`Fence`](https://rux-lang.dev/docs/api/core/atomic#fence) and [`SpinHint`](https://rux-lang.dev/docs/api/core/atomic#spin-hint) order and pace a thread without touching memory. Each takes a [`MemoryOrder`](https://rux-lang.dev/docs/api/core/atomic#memory-order) written at the call as a case such as `MemoryOrder::Acquire`, and the compiler refuses the orders an operation cannot have. On x86-64 they are plain moves, `xchg` and `lock`-prefixed instructions; on AArch64, `ldar`/`stlr` and exclusive-access loops. `Rux/Atomic` wraps them in a type. - **Startup** — [`ProcessStartFrame`](https://rux-lang.dev/docs/api/core/startup#process-start-frame) is the address the kernel started an ELF program at, where its argument count, argument and environment pointers and auxiliary vector are; it is null on Windows and macOS, which supply the command line through system calls, and in a shared library. `Rux/Process` reads arguments and the environment through it. - **Diagnostics** — [`Assert`](https://rux-lang.dev/docs/api/core/diagnostics#assert), [`DebugAssert`](https://rux-lang.dev/docs/api/core/diagnostics#debug-assert), and [`Panic`](https://rux-lang.dev/docs/api/core/diagnostics#panic) report and terminate; [`#Error`](https://rux-lang.dev/docs/api/core/diagnostics#error) and [`#Warn`](https://rux-lang.dev/docs/api/core/diagnostics#warn) reject or flag an unsupported configuration while compiling and produce no runtime code. A release build removes [`DebugAssert`](https://rux-lang.dev/docs/api/core/diagnostics#debug-assert) checks without evaluating their arguments. After the location, the report names the functions that led to the failure, one `from Name` line each, read from the stack's frame records; a release build that inlined a function names its caller instead. Neither [`Assert`](https://rux-lang.dev/docs/api/core/diagnostics#assert) nor [`Panic`](https://rux-lang.dev/docs/api/core/diagnostics#panic) unwinds, so no destructor runs on the way out — anything that must be released on a failing path belongs to a caller that saw the failure, which is what a native fallible `T ! E` is for. - **Native outcome questions** — [`Succeeded`](https://rux-lang.dev/docs/api/core/outcomes#succeeded) and [`Failed`](https://rux-lang.dev/docs/api/core/outcomes#failed) answer which channel a native fallible `T ! E` holds without unwrapping it. Native forms have no methods of their own, so these are ordinary generic functions; each takes the outcome by value, so a call's result is asked directly and a named outcome with a move-only payload is passed as `<-outcome`. - **Ordering** — the result of a three-way comparison, with [`IsLess`](https://rux-lang.dev/docs/api/core/ordering#is-less), [`IsEqual`](https://rux-lang.dev/docs/api/core/ordering#is-equal), [`IsGreater`](https://rux-lang.dev/docs/api/core/ordering#is-greater), the derived [`IsLessOrEqual`](https://rux-lang.dev/docs/api/core/ordering#is-less-or-equal) and [`IsGreaterOrEqual`](https://rux-lang.dev/docs/api/core/ordering#is-greater-or-equal), and [`Reverse`](https://rux-lang.dev/docs/api/core/ordering#reverse). Absence and failure are not library types: they are the native optional `T?` and fallible `T ! E`, with the native unit `()` for an operation with nothing to report. - **Interfaces for generic code** — [`Equatable`](https://rux-lang.dev/docs/api/core/equatable) and [`Comparable`](https://rux-lang.dev/docs/api/core/comparable) borrow their `Self`-typed operands through non-null references, [`Hashable`](https://rux-lang.dev/docs/api/core/hashable) gives the 64-bit summary a table keys on, and [`Iterator`](https://rux-lang.dev/docs/api/core/iterator)/[`Iterable`](https://rux-lang.dev/docs/api/core/iterable) name the iteration protocol the compiler drives by shape. [`Sendable`](https://rux-lang.dev/docs/api/core/sendable) is the marker the compiler decides for a value that may move to another thread: every type satisfies it except a reference and one holding a type declared `#Unsendable()`. Resource types prohibit copying with a bodyless canonical `=` and release themselves with `~Type`. Bounds such as `func Sort<T: Comparable>(...)` resolve `Self` to each type argument without dynamic dispatch. - **Lazy adaptors** — [`Map`](https://rux-lang.dev/docs/api/core/adaptors#map), [`Filter`](https://rux-lang.dev/docs/api/core/adaptors#filter), [`Take`](https://rux-lang.dev/docs/api/core/adaptors#take), [`Skip`](https://rux-lang.dev/docs/api/core/adaptors#skip), [`Enumerate`](https://rux-lang.dev/docs/api/core/adaptors#enumerate), [`Zip`](https://rux-lang.dev/docs/api/core/adaptors#zip) and [`Chain`](https://rux-lang.dev/docs/api/core/adaptors#chain) wrap any [`Cursor<T>`](https://rux-lang.dev/docs/api/core/adaptors#cursor) — a type whose `Next` returns `T?`, such as a container's iterator, [`Walk`](https://rux-lang.dev/docs/api/core/adaptors#walk) over a slice, or another adaptor — and compute each item only when it is asked for. Their item types are deduced from the wrapped cursor, so `Take(Filter(Map(Walk(items), Square), IsEven), 3)` needs no type arguments. - **Integer arithmetic** — [`AddChecked`](https://rux-lang.dev/docs/api/core/arithmetic#add-checked), [`SubChecked`](https://rux-lang.dev/docs/api/core/arithmetic#sub-checked), and [`MulChecked`](https://rux-lang.dev/docs/api/core/arithmetic#mul-checked) report whether the true answer was representable and write the machine's answer either way; [`AddWrapping`](https://rux-lang.dev/docs/api/core/arithmetic#add-wrapping), [`SubWrapping`](https://rux-lang.dev/docs/api/core/arithmetic#sub-wrapping), and [`MulWrapping`](https://rux-lang.dev/docs/api/core/arithmetic#mul-wrapping) name the wrapping that `+`, `-`, and `*` already do; [`AddSaturating`](https://rux-lang.dev/docs/api/core/arithmetic#add-saturating), [`SubSaturating`](https://rux-lang.dev/docs/api/core/arithmetic#sub-saturating), and [`MulSaturating`](https://rux-lang.dev/docs/api/core/arithmetic#mul-saturating) clamp to whichever limit the true answer ran past. [`MaximumOf`](https://rux-lang.dev/docs/api/core/arithmetic#maximum-of) and [`MinimumOf`](https://rux-lang.dev/docs/api/core/arithmetic#minimum-of) report a type's limits. All are generic over the integer type and work at every width, signed and unsigned, deriving a type's zero, signedness, and limits from one operand rather than being written out per width. The operation comes first in each name because [`CheckedAdd`](https://rux-lang.dev/docs/api/core/arithmetic#checked-add), [`CheckedSub`](https://rux-lang.dev/docs/api/core/arithmetic#checked-sub), and [`CheckedMul`](https://rux-lang.dev/docs/api/core/arithmetic#checked-mul) already name the compiler's [`uint64`](https://rux-lang.dev/docs/api/core/integers#uint64) intrinsics, which are emitted inline and are what allocation-size arithmetic is written with. - **Bit operations** — [`CountOnes`](https://rux-lang.dev/docs/api/core/bits#count-ones), [`CountZeros`](https://rux-lang.dev/docs/api/core/bits#count-zeros), [`LeadingZeros`](https://rux-lang.dev/docs/api/core/bits#leading-zeros), [`TrailingZeros`](https://rux-lang.dev/docs/api/core/bits#trailing-zeros), [`LeadingOnes`](https://rux-lang.dev/docs/api/core/bits#leading-ones), [`TrailingOnes`](https://rux-lang.dev/docs/api/core/bits#trailing-ones), [`RotateLeft`](https://rux-lang.dev/docs/api/core/bits#rotate-left), [`RotateRight`](https://rux-lang.dev/docs/api/core/bits#rotate-right), [`ReverseBits`](https://rux-lang.dev/docs/api/core/bits#reverse-bits), [`ReverseBytes`](https://rux-lang.dev/docs/api/core/bits#reverse-bytes), [`BitAt`](https://rux-lang.dev/docs/api/core/bits#bit-at), [`BitWidthOf`](https://rux-lang.dev/docs/api/core/bits#bit-width-of), [`IsPowerOfTwo`](https://rux-lang.dev/docs/api/core/bits#is-power-of-two), and [`ShiftRightLogical`](https://rux-lang.dev/docs/api/core/bits#shift-right-logical). All are generic over the integer type and right at every width, signed and unsigned: `>>` copies the sign bit down on a signed type, so everything that reads a value's bits as bits goes through [`ShiftRightLogical`](https://rux-lang.dev/docs/api/core/bits#shift-right-logical), which brings zeros in either way. - **Byte order** — [`ToLittleEndian`](https://rux-lang.dev/docs/api/core/byte-order#to-little-endian), [`FromLittleEndian`](https://rux-lang.dev/docs/api/core/byte-order#from-little-endian), [`ToBigEndian`](https://rux-lang.dev/docs/api/core/byte-order#to-big-endian), and [`FromBigEndian`](https://rux-lang.dev/docs/api/core/byte-order#from-big-endian) convert a value already in a register; [`StoreLittleEndian`](https://rux-lang.dev/docs/api/core/byte-order#store-little-endian), [`StoreBigEndian`](https://rux-lang.dev/docs/api/core/byte-order#store-big-endian), [`LoadLittleEndian`](https://rux-lang.dev/docs/api/core/byte-order#load-little-endian), and [`LoadBigEndian`](https://rux-lang.dev/docs/api/core/byte-order#load-big-endian) move one through raw bytes at any alignment, which is what a file or wire format needs. [`TargetIsLittleEndian`](https://rux-lang.dev/docs/api/core/byte-order#target-is-little-endian) reports this target's own order, established from its storage rather than from a list of known targets. - **Checked conversion** — [`ConvertChecked`](https://rux-lang.dev/docs/api/core/conversion#convert-checked) reports whether a primitive value survived the conversion and writes the machine's answer either way; [`ConvertWrapping`](https://rux-lang.dev/docs/api/core/conversion#convert-wrapping) names the wrapping `as` already does, and [`ConvertSaturating`](https://rux-lang.dev/docs/api/core/conversion#convert-saturating) clamps to the destination's range. Every check is a round trip in the source type, plus one test for the pair a round trip cannot see — a value and its conversion that disagree in sign, which is how `-1` reaches [`uint64`](https://rux-lang.dev/docs/api/core/integers#uint64). [`IsSignedType`](https://rux-lang.dev/docs/api/core/conversion#is-signed-type) reports whether a type has values below zero. - **Float classification** — [`IsNaN`](https://rux-lang.dev/docs/api/core/float-classification#is-nan), [`IsZero`](https://rux-lang.dev/docs/api/core/float-classification#is-zero), [`IsInfinite`](https://rux-lang.dev/docs/api/core/float-classification#is-infinite), [`IsFinite`](https://rux-lang.dev/docs/api/core/float-classification#is-finite), [`IsNegativeZero`](https://rux-lang.dev/docs/api/core/float-classification#is-negative-zero), [`IsSignNegative`](https://rux-lang.dev/docs/api/core/float-classification#is-sign-negative), [`IsSignPositive`](https://rux-lang.dev/docs/api/core/float-classification#is-sign-positive), and [`SignOf`](https://rux-lang.dev/docs/api/core/float-classification#sign-of). All are arithmetic rather than bit inspection, so one implementation serves every float width including the software-lowered ones, whose storage carries padding no generic function could locate a sign bit inside of. The sign of a zero, which comparison cannot see, is read from the infinity it divides into. - **Primitive associated constants** — `Bits`, `Bytes`, `Min`, `Max` and the floating-point set (`Lowest`, `MinPositive`, `Epsilon`, `Infinity`, `NaN`) for every integer width and every character width from [`char8`](https://rux-lang.dev/docs/api/core/characters#char8) to [`char512`](https://rux-lang.dev/docs/api/core/characters#char512), width metadata for every boolean width from [`bool8`](https://rux-lang.dev/docs/api/core/booleans#bool8) to [`bool512`](https://rux-lang.dev/docs/api/core/booleans#bool512), and the finite and special constant set for every float width from [`float8`](https://rux-lang.dev/docs/api/core/floating-point#float8) to [`float512`](https://rux-lang.dev/docs/api/core/floating-point#float512). The scalar widths from [`char32`](https://rux-lang.dev/docs/api/core/characters#char32) to [`char512`](https://rux-lang.dev/docs/api/core/characters#char512) share one range, U+0000 to U+10FFFF, however many bytes they occupy. The string widths expose none: a string is a view over code units rather than a value with a width, so a width or a limit would describe neither it nor the units. ### Primitive constants and imports ```rux import Core::int8; func Main() -> int { let minimum = int8::Min; let message: char8[..] = "hello"; return message.length as int + minimum as int; } ``` [`int8`](https://rux-lang.dev/docs/api/core/integers#int8) is built into the compiler, so it names the scalar type without an import; `import Core::int8;` imports Core's `extend int8` block, which is what makes [`int8::Min`](https://rux-lang.dev/docs/api/core/integers#int8-min) available. The built-in aliases import their canonical widths: `import Core::byte;` gives `byte::Max`, the same constant as [`uint8::Max`](https://rux-lang.dev/docs/api/core/integers#uint8-max), and `import Core::bool;` gives `bool::Bits`. Loading a dependency that imports it does not import its APIs into the caller. The same rule applies between source files. Core declares no primitive type: each primitive file holds one documented `extend` block. Core defines integer and character limits, width metadata, and finite floating constants using ordinary constant expressions. Native integer metadata uses `sizeof`, so it follows the compilation target. The float limits of [`float8`](https://rux-lang.dev/docs/api/core/floating-point#float8) and [`float16`](https://rux-lang.dev/docs/api/core/floating-point#float16) are literals — [`float8`](https://rux-lang.dev/docs/api/core/floating-point#float8), the E4M3 format, tops out at 240 and [`float16`](https://rux-lang.dev/docs/api/core/floating-point#float16) at 65504 — while `Infinity` and `NaN` at every width, and every limit of [`float80`](https://rux-lang.dev/docs/api/core/floating-point#float80), [`float128`](https://rux-lang.dev/docs/api/core/floating-point#float128), [`float256`](https://rux-lang.dev/docs/api/core/floating-point#float256) and [`float512`](https://rux-lang.dev/docs/api/core/floating-point#float512), are bodyless `intrinsic const` declarations whose values the compiler supplies from the format itself. ### Sequence views and ranges The language supplies read-only `T[..]` and writable `var T[..]` views. Neither annotation needs a Core import. Their `.data` and `.length` fields are compiler-owned. A view owns no storage, and copying it copies two words. Its backing storage must remain alive while it is used. ```rux func Sum(values: int[..]) -> int { var total = 0; for value in values { total += value; } return total; } func Fill(values: var int[..], value: int) { for index in 0..values.length { values[index] = value; } } func Main() -> int { var storage: int[3] = [1, 2, 3]; let view = storage[..]; Fill(view, 4); return Sum(view) - 12; } ``` A writable view weakens to a read-only one implicitly; a read-only view cannot be strengthened. Binding a view with `let` does not freeze its pointee. `[]` constructs an empty view when a slice type is expected. Use `pointer[..length]` to view raw storage, and `view[start..end]` to select a subview. Pointer ranges require an end because pointers carry no length. These operations use element counts rather than byte counts. Ranges are written `int..int`, `int..=int`, `int..`, `..int`, `..=int`, and `..` in annotations. Their `.start` and `.end` fields exist only when the corresponding bound exists, with no declaration or import required. Literal text is `char8[..]`, `char16[..]`, or `char32[..]`; the prefixes are `c8`, `c16`, and `c32`, and an unprefixed literal uses UTF-8. The descriptor length counts code units, excluding the trailing NUL in literal storage. Text can be passed directly to a function taking the corresponding read-only character slice. Slicing can split an encoded scalar, so validated-text operations belong in Text and Unicode. A literal cannot become a writable view. Core diagnostic messages and compile-time context text use `char8[..]`. External functions taking raw pointers receive `"literal".data`. Concrete slice extensions can add methods for one element type; reusable generic algorithms use ordinary generic functions. ### Ownership and borrowing Core methods borrow ordinary values with `&T` and mutable receivers with `&var T`; callers pass the value directly and the compiler creates the short-lived borrow. Named move-only values require `<-` when ownership crosses a binding, call, assignment, return, or consuming receiver. Copyable Core values use generated structural copying. Canonical constructors are type calls such as `SemanticVersion(1, 2, 3)`, and descriptive factories retain their names. Raw pointers remain where absence, storage, or address arithmetic is part of the contract: slice fields, nullable `TryInto*` outputs, unchecked checked-arithmetic/conversion destinations, byte-order buffers, and zeroization. [`Assert`](https://rux-lang.dev/docs/api/core/diagnostics#assert) and [`Panic`](https://rux-lang.dev/docs/api/core/diagnostics#panic) failures have the same UTF-8, LF-terminated layout on every supported target: ```text Assertion failed: message at Function (path:line:column) ``` [`Panic`](https://rux-lang.dev/docs/api/core/diagnostics#panic) uses `Panic: message` on the first line. The location uses a package-relative path when the source belongs to the package root, and qualified method or module names are retained. ### Example ```rux import Core::{ #target, #Error }; when #target.os { .Windows, .Linux, .macOS, .FreeBSD => {}, else => #Error("Unsupported operating system") } ``` ```rux import Core::{ Assert, SemanticVersion }; func Major(version: &SemanticVersion) -> uint { return version.major; } func Main() -> int { let version = SemanticVersion(1, 2, 3); let answer: int32? = .Some(42i32); Assert(Major(version) == 1u, "borrowed version"); Assert((answer ?? 0i32) == 42i32, "present optional value"); return 0; } ``` ## Index ### Interfaces | Name | Summary | | -------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | [`Cursor`](https://rux-lang.dev/docs/api/core/adaptors#cursor) | Anything that yields items of type `T` one at a time through [`Next`](https://rux-lang.dev/docs/api/core/adaptors#cursor-next), which `for` and every adaptor here drive. | | [`Comparable`](https://rux-lang.dev/docs/api/core/comparable) | Ordering: which of two values of one type comes first. | | [`Equatable`](https://rux-lang.dev/docs/api/core/equatable) | Equality: whether two values of one type stand for the same thing. | | [`Hashable`](https://rux-lang.dev/docs/api/core/hashable) | Hashing: the 64-bit summary a table uses to find a value quickly. | | [`Iterator`](https://rux-lang.dev/docs/api/core/iterator) | A cursor that yields a sequence of items one at a time. | | [`Iterable`](https://rux-lang.dev/docs/api/core/iterable) | A value that can hand out an [`Iterator`](https://rux-lang.dev/docs/api/core/iterator) over its contents. | | [`Sendable`](https://rux-lang.dev/docs/api/core/sendable) | A type whose values may move to another thread: the bound a thread's context and result are written with. | ### Types | Name | Summary | | ------------------------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------- | | [`SliceCursor<T>`](https://rux-lang.dev/docs/api/core/adaptors#slice-cursor) | A cursor over the elements of a slice, by copy. | | [`Mapped<I, T, U>`](https://rux-lang.dev/docs/api/core/adaptors#mapped) | The items of a cursor, each passed through a function. | | [`Filtered<I, T>`](https://rux-lang.dev/docs/api/core/adaptors#filtered) | The items of a cursor that pass a test. | | [`Taken<I, T>`](https://rux-lang.dev/docs/api/core/adaptors#taken) | At most a number of items from the front of a cursor. | | [`Skipped<I, T>`](https://rux-lang.dev/docs/api/core/adaptors#skipped) | The items of a cursor after a number of them. | | [`Indexed<T>`](https://rux-lang.dev/docs/api/core/adaptors#indexed) | An item and its position, counting from zero. | | [`Enumerated<I, T>`](https://rux-lang.dev/docs/api/core/adaptors#enumerated) | The items of a cursor with their positions. | | [`Pair<A, B>`](https://rux-lang.dev/docs/api/core/adaptors#pair) | One item from each of two cursors. | | [`Zipped<I, J, A, B>`](https://rux-lang.dev/docs/api/core/adaptors#zipped) | The items of two cursors side by side. | | [`Chained<I, J, T>`](https://rux-lang.dev/docs/api/core/adaptors#chained) | The items of one cursor and then of another. | | [`MemoryOrder`](https://rux-lang.dev/docs/api/core/atomic#memory-order) | Which other memory operations may be reordered across an atomic one. | | [`BuildMode`](https://rux-lang.dev/docs/api/core/build#build-mode) | The high-level mode of the active build profile. | | [`OptimizationMode`](https://rux-lang.dev/docs/api/core/build#optimization-mode) | What the active build asked the optimizer to favor. | | [`OutputKind`](https://rux-lang.dev/docs/api/core/build#output-kind) | The kind of artifact the active build produces. | | [`Build`](https://rux-lang.dev/docs/api/core/build) | Properties of the active build profile and its output. | | [`SemanticVersion`](https://rux-lang.dev/docs/api/core/semantic-version) | A semantic version, as its three numeric core components. | | [`Compiler`](https://rux-lang.dev/docs/api/core/compiler) | Properties of the compiler performing the build. | | [`Config`](https://rux-lang.dev/docs/api/core/config) | The set of user-defined build values. | | [`Ordering`](https://rux-lang.dev/docs/api/core/ordering) | The answer a three-way comparison gives: which side is smaller, or that neither is. | | [`bool128`](https://rux-lang.dev/docs/api/core/booleans#bool128) | One of two values, stored in 128 bits. | | [`bool16`](https://rux-lang.dev/docs/api/core/booleans#bool16) | One of two values, stored in 16 bits. | | [`bool256`](https://rux-lang.dev/docs/api/core/booleans#bool256) | One of two values, stored in 256 bits. | | [`bool32`](https://rux-lang.dev/docs/api/core/booleans#bool32) | One of two values, stored in 32 bits. | | [`bool512`](https://rux-lang.dev/docs/api/core/booleans#bool512) | One of two values, stored in 512 bits. | | [`bool64`](https://rux-lang.dev/docs/api/core/booleans#bool64) | One of two values, stored in 64 bits. | | [`bool8`](https://rux-lang.dev/docs/api/core/booleans#bool8) | One of two values, stored in 8 bits. | | [`char128`](https://rux-lang.dev/docs/api/core/characters#char128) | One Unicode scalar value, in sixteen bytes. | | [`char16`](https://rux-lang.dev/docs/api/core/characters#char16) | One UTF-16 code unit. | | [`char256`](https://rux-lang.dev/docs/api/core/characters#char256) | One Unicode scalar value, in thirty-two bytes. | | [`char32`](https://rux-lang.dev/docs/api/core/characters#char32) | One Unicode scalar value. | | [`char512`](https://rux-lang.dev/docs/api/core/characters#char512) | One Unicode scalar value, in sixty-four bytes. | | [`char64`](https://rux-lang.dev/docs/api/core/characters#char64) | One Unicode scalar value, in eight bytes. | | [`char8`](https://rux-lang.dev/docs/api/core/characters#char8) | One UTF-8 code unit. | | [`float128`](https://rux-lang.dev/docs/api/core/floating-point#float128) | An IEEE 754 binary128 floating-point number. | | [`float16`](https://rux-lang.dev/docs/api/core/floating-point#float16) | An IEEE 754 binary16 floating-point number. | | [`float256`](https://rux-lang.dev/docs/api/core/floating-point#float256) | An IEEE 754 binary256 floating-point number. | | [`float32`](https://rux-lang.dev/docs/api/core/floating-point#float32) | An IEEE 754 binary32 floating-point number. | | [`float512`](https://rux-lang.dev/docs/api/core/floating-point#float512) | A binary512 floating-point number in the IEEE 754 interchange-format progression. | | [`float64`](https://rux-lang.dev/docs/api/core/floating-point#float64) | An IEEE 754 binary64 floating-point number. | | [`float8`](https://rux-lang.dev/docs/api/core/floating-point#float8) | An eight-bit E4M3 floating-point number with IEEE 754 infinities and NaNs. | | [`float80`](https://rux-lang.dev/docs/api/core/floating-point#float80) | An x87 extended-precision floating-point number. | | [`int`](https://rux-lang.dev/docs/api/core/integers#int) | A target pointer-sized signed integer. | | [`int128`](https://rux-lang.dev/docs/api/core/integers#int128) | A signed integer in 128 bits, two's complement. | | [`int16`](https://rux-lang.dev/docs/api/core/integers#int16) | A signed integer in 16 bits, two's complement. | | [`int256`](https://rux-lang.dev/docs/api/core/integers#int256) | A signed integer in 256 bits, two's complement. | | [`int32`](https://rux-lang.dev/docs/api/core/integers#int32) | A signed integer in 32 bits, two's complement. | | [`int512`](https://rux-lang.dev/docs/api/core/integers#int512) | A signed integer in 512 bits, two's complement. | | [`int64`](https://rux-lang.dev/docs/api/core/integers#int64) | A signed integer in 64 bits, two's complement. | | [`int8`](https://rux-lang.dev/docs/api/core/integers#int8) | A signed integer in 8 bits, two's complement. | | [`uint`](https://rux-lang.dev/docs/api/core/integers#uint) | A target pointer-sized unsigned integer. | | [`uint128`](https://rux-lang.dev/docs/api/core/integers#uint128) | An unsigned integer in 128 bits. | | [`uint16`](https://rux-lang.dev/docs/api/core/integers#uint16) | An unsigned integer in 16 bits. | | [`uint256`](https://rux-lang.dev/docs/api/core/integers#uint256) | An unsigned integer in 256 bits. | | [`uint32`](https://rux-lang.dev/docs/api/core/integers#uint32) | An unsigned integer in 32 bits. | | [`uint512`](https://rux-lang.dev/docs/api/core/integers#uint512) | An unsigned integer in 512 bits. | | [`uint64`](https://rux-lang.dev/docs/api/core/integers#uint64) | An unsigned integer in 64 bits. | | [`uint8`](https://rux-lang.dev/docs/api/core/integers#uint8) | An unsigned integer in 8 bits. | | [`Source`](https://rux-lang.dev/docs/api/core/source) | The location of the expression that reads it. | | [`OperatingSystem`](https://rux-lang.dev/docs/api/core/target#operating-system) | An operating system a build can target. | | [`Architecture`](https://rux-lang.dev/docs/api/core/target#architecture) | A processor architecture a build can target. | | [`ApplicationBinaryInterface`](https://rux-lang.dev/docs/api/core/target#application-binary-interface) | The calling and layout conventions a target's code follows. | | [`TargetFeature`](https://rux-lang.dev/docs/api/core/target#target-feature) | A processor feature a target may be built with. | | [`Endianness`](https://rux-lang.dev/docs/api/core/target#endianness) | The order a target stores a multi-byte value's bytes in. | | [`DataModel`](https://rux-lang.dev/docs/api/core/target#data-model) | The widths a target's C environment assigns to `long` and to a pointer. | | [`ObjectFormat`](https://rux-lang.dev/docs/api/core/target#object-format) | The object-file format a target's compiled code is emitted in. | | [`Target`](https://rux-lang.dev/docs/api/core/target) | Properties of the machine the build targets. | ### Functions | Name | Summary | | ------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------- | | [`Walk<T>`](https://rux-lang.dev/docs/api/core/adaptors#walk) | A cursor over the elements of `items`, so a slice can feed the adaptors. | | [`Map<I, T, U>`](https://rux-lang.dev/docs/api/core/adaptors#map) | Each item of `source` passed through `transform`, as it is asked for. | | [`Filter<I, T>`](https://rux-lang.dev/docs/api/core/adaptors#filter) | The items of `source` for which `keep` holds. | | [`Take<I, T>`](https://rux-lang.dev/docs/api/core/adaptors#take) | The first `count` items of `source`, or all of them if it has fewer. | | [`Skip<I, T>`](https://rux-lang.dev/docs/api/core/adaptors#skip) | The items of `source` after its first `count`. | | [`Enumerate<I, T>`](https://rux-lang.dev/docs/api/core/adaptors#enumerate) | Each item of `source` with its position, counting from zero. | | [`Zip<I, J, A, B>`](https://rux-lang.dev/docs/api/core/adaptors#zip) | The items of `first` and `second` in pairs, as long as both last. | | [`Chain<I, J, T>`](https://rux-lang.dev/docs/api/core/adaptors#chain) | The items of `first` followed by the items of `second`. | | [`MaximumOf<T>`](https://rux-lang.dev/docs/api/core/arithmetic#maximum-of) | The largest value the integer type of `sample` can hold. | | [`MinimumOf<T>`](https://rux-lang.dev/docs/api/core/arithmetic#minimum-of) | The smallest value the integer type of `sample` can hold. | | [`AddChecked<T>`](https://rux-lang.dev/docs/api/core/arithmetic#add-checked) | Adds two integers and reports whether the true sum is representable. | | [`SubChecked<T>`](https://rux-lang.dev/docs/api/core/arithmetic#sub-checked) | Subtracts one integer from another and reports whether the true difference is representable. | | [`MulChecked<T>`](https://rux-lang.dev/docs/api/core/arithmetic#mul-checked) | Multiplies two integers and reports whether the true product is representable. | | [`AddWrapping<T>`](https://rux-lang.dev/docs/api/core/arithmetic#add-wrapping) | Adds two integers, wrapping around the type's range. | | [`SubWrapping<T>`](https://rux-lang.dev/docs/api/core/arithmetic#sub-wrapping) | Subtracts one integer from another, wrapping around the type's range. | | [`MulWrapping<T>`](https://rux-lang.dev/docs/api/core/arithmetic#mul-wrapping) | Multiplies two integers, wrapping around the type's range. | | [`AddSaturating<T>`](https://rux-lang.dev/docs/api/core/arithmetic#add-saturating) | Adds two integers, clamping to the type's range instead of wrapping. | | [`SubSaturating<T>`](https://rux-lang.dev/docs/api/core/arithmetic#sub-saturating) | Subtracts one integer from another, clamping to the type's range instead of wrapping. | | [`MulSaturating<T>`](https://rux-lang.dev/docs/api/core/arithmetic#mul-saturating) | Multiplies two integers, clamping to the type's range instead of wrapping. | | [`AtomicLoad<T>`](https://rux-lang.dev/docs/api/core/atomic#atomic-load) | Reads the value at `address` atomically. | | [`AtomicStore<T>`](https://rux-lang.dev/docs/api/core/atomic#atomic-store) | Writes `value` to `address` atomically. | | [`AtomicExchange<T>`](https://rux-lang.dev/docs/api/core/atomic#atomic-exchange) | Writes `value` to `address` and returns what was there, as one atomic step. | | [`AtomicCompareExchange<T>`](https://rux-lang.dev/docs/api/core/atomic#atomic-compare-exchange) | Writes `desired` to `address` if it holds `expected`, and returns what it held, as one atomic step. | | [`AtomicFetchAdd<T>`](https://rux-lang.dev/docs/api/core/atomic#atomic-fetch-add) | Adds `value` to the integer at `address` and returns what was there, as one atomic step. | | [`AtomicFetchSub<T>`](https://rux-lang.dev/docs/api/core/atomic#atomic-fetch-sub) | Subtracts `value` from the integer at `address` and returns what was there, as one atomic step. | | [`AtomicFetchAnd<T>`](https://rux-lang.dev/docs/api/core/atomic#atomic-fetch-and) | Combines the value at `address` with `value` by bitwise and, and returns what was there, as one atomic step. | | [`AtomicFetchOr<T>`](https://rux-lang.dev/docs/api/core/atomic#atomic-fetch-or) | Combines the value at `address` with `value` by bitwise or, and returns what was there, as one atomic step. | | [`AtomicFetchXor<T>`](https://rux-lang.dev/docs/api/core/atomic#atomic-fetch-xor) | Combines the value at `address` with `value` by bitwise exclusive or, and returns what was there, as one atomic step. | | [`Fence`](https://rux-lang.dev/docs/api/core/atomic#fence) | Orders this thread's memory operations without touching memory. | | [`SpinHint`](https://rux-lang.dev/docs/api/core/atomic#spin-hint) | Tells the processor that the thread is waiting in a loop for another thread. | | [`BitWidthOf<T>`](https://rux-lang.dev/docs/api/core/bits#bit-width-of) | The number of bits in the integer type of `sample`. | | [`ShiftRightLogical<T>`](https://rux-lang.dev/docs/api/core/bits#shift-right-logical) | Shifts an integer right, bringing zeros in at the top whatever its signedness. | | [`BitAt<T>`](https://rux-lang.dev/docs/api/core/bits#bit-at) | Whether the bit at `index` is set, counting from the least significant bit. | | [`CountOnes<T>`](https://rux-lang.dev/docs/api/core/bits#count-ones) | The number of set bits. | | [`CountZeros<T>`](https://rux-lang.dev/docs/api/core/bits#count-zeros) | The number of clear bits. | | [`LeadingZeros<T>`](https://rux-lang.dev/docs/api/core/bits#leading-zeros) | The number of clear bits above the highest set bit. | | [`TrailingZeros<T>`](https://rux-lang.dev/docs/api/core/bits#trailing-zeros) | The number of clear bits below the lowest set bit. | | [`LeadingOnes<T>`](https://rux-lang.dev/docs/api/core/bits#leading-ones) | The number of set bits above the highest clear bit. | | [`TrailingOnes<T>`](https://rux-lang.dev/docs/api/core/bits#trailing-ones) | The number of set bits below the lowest clear bit. | | [`RotateLeft<T>`](https://rux-lang.dev/docs/api/core/bits#rotate-left) | Rotates an integer's bits toward the most significant end, wrapping the ones that run off. | | [`RotateRight<T>`](https://rux-lang.dev/docs/api/core/bits#rotate-right) | Rotates an integer's bits toward the least significant end, wrapping the ones that run off. | | [`ReverseBits<T>`](https://rux-lang.dev/docs/api/core/bits#reverse-bits) | The value with its bits in the opposite order: bit zero becomes the highest bit and back again. | | [`ReverseBytes<T>`](https://rux-lang.dev/docs/api/core/bits#reverse-bytes) | The value with its bytes in the opposite order, leaving the bits within each byte where they were. | | [`IsPowerOfTwo<T>`](https://rux-lang.dev/docs/api/core/bits#is-power-of-two) | Whether the value has exactly one bit set. | | [`CheckedAdd`](https://rux-lang.dev/docs/api/core/arithmetic#checked-add) | Adds two unsigned 64-bit values and reports whether the true sum is representable. | | [`CheckedSub`](https://rux-lang.dev/docs/api/core/arithmetic#checked-sub) | Subtracts one unsigned 64-bit value from another and reports whether the true difference is representable. | | [`CheckedMul`](https://rux-lang.dev/docs/api/core/arithmetic#checked-mul) | Multiplies two unsigned 64-bit values and reports whether the true product is representable. | | [`IsSignedType<T>`](https://rux-lang.dev/docs/api/core/conversion#is-signed-type) | Whether the integer type of `sample` has values below zero. | | [`ConvertChecked<From, To>`](https://rux-lang.dev/docs/api/core/conversion#convert-checked) | Converts a primitive value to another primitive type and reports whether the true value was representable. | | [`ConvertWrapping<From, To>`](https://rux-lang.dev/docs/api/core/conversion#convert-wrapping) | Converts a primitive value to another primitive type, keeping whatever fits. | | [`ConvertSaturating<From, To>`](https://rux-lang.dev/docs/api/core/conversion#convert-saturating) | Converts a primitive value to an integer type, clamping to that type's range instead of wrapping. | | [`Assert`](https://rux-lang.dev/docs/api/core/diagnostics#assert) | Terminates the program unless `condition` holds. | | [`DebugAssert`](https://rux-lang.dev/docs/api/core/diagnostics#debug-assert) | Terminates the program unless `condition` holds, in builds that keep debug assertions. | | [`Panic`](https://rux-lang.dev/docs/api/core/diagnostics#panic) | Terminates the program, reporting `message`. | | [`#Error`](https://rux-lang.dev/docs/api/core/diagnostics#error) | Rejects the build where it is written, reporting `message`. | | [`#Warn`](https://rux-lang.dev/docs/api/core/diagnostics#warn) | Reports `message` as a compilation warning where it is written, without rejecting the build. | | [`TargetIsLittleEndian`](https://rux-lang.dev/docs/api/core/byte-order#target-is-little-endian) | Whether this target stores an integer's least significant byte first. | | [`ToLittleEndian<T>`](https://rux-lang.dev/docs/api/core/byte-order#to-little-endian) | The value's bytes as a little-endian value would hold them. | | [`FromLittleEndian<T>`](https://rux-lang.dev/docs/api/core/byte-order#from-little-endian) | The value a little-endian bit pattern stands for on this target. | | [`ToBigEndian<T>`](https://rux-lang.dev/docs/api/core/byte-order#to-big-endian) | The value's bytes as a big-endian value would hold them. | | [`FromBigEndian<T>`](https://rux-lang.dev/docs/api/core/byte-order#from-big-endian) | The value a big-endian bit pattern stands for on this target. | | [`StoreLittleEndian<T>`](https://rux-lang.dev/docs/api/core/byte-order#store-little-endian) | Writes an integer to raw bytes, least significant byte first. | | [`StoreBigEndian<T>`](https://rux-lang.dev/docs/api/core/byte-order#store-big-endian) | Writes an integer to raw bytes, most significant byte first. | | [`LoadLittleEndian<T>`](https://rux-lang.dev/docs/api/core/byte-order#load-little-endian) | Reads an integer from raw bytes holding it least significant byte first. | | [`LoadBigEndian<T>`](https://rux-lang.dev/docs/api/core/byte-order#load-big-endian) | Reads an integer from raw bytes holding it most significant byte first. | | [`IsNaN<T>`](https://rux-lang.dev/docs/api/core/float-classification#is-nan) | Whether the value is not a number. | | [`IsZero<T>`](https://rux-lang.dev/docs/api/core/float-classification#is-zero) | Whether the value is either zero. | | [`IsInfinite<T>`](https://rux-lang.dev/docs/api/core/float-classification#is-infinite) | Whether the value is an infinity, of either sign. | | [`IsFinite<T>`](https://rux-lang.dev/docs/api/core/float-classification#is-finite) | Whether the value is an ordinary number: neither a NaN nor an infinity. | | [`IsNegativeZero<T>`](https://rux-lang.dev/docs/api/core/float-classification#is-negative-zero) | Whether the value is the zero that carries a minus sign. | | [`IsSignNegative<T>`](https://rux-lang.dev/docs/api/core/float-classification#is-sign-negative) | Whether the value carries a minus sign. | | [`IsSignPositive<T>`](https://rux-lang.dev/docs/api/core/float-classification#is-sign-positive) | Whether the value carries a plus sign. | | [`SignOf<T>`](https://rux-lang.dev/docs/api/core/float-classification#sign-of) | The value's sign as one of `-1`, `+1`, or the zero it started from. | | [`Succeeded<T, E>`](https://rux-lang.dev/docs/api/core/outcomes#succeeded) | Whether `outcome` holds a success. | | [`Failed<T, E>`](https://rux-lang.dev/docs/api/core/outcomes#failed) | Whether `outcome` holds a failure. | | [`ProcessStartFrame`](https://rux-lang.dev/docs/api/core/startup#process-start-frame) | The address the kernel started the program at, on targets where that is where the arguments are. | | [`Zeroize`](https://rux-lang.dev/docs/api/core/zeroize) | Overwrites a byte range with zeros, and is never removed however unread those bytes are afterwards. | ### Constants | Name | Summary | | ---------------------------------------------------------------------------- | --------------------------------------------------------------- | | [`#build`](https://rux-lang.dev/docs/api/core/build#build-constant) | The active build, as a compile-time value. | | [`#compiler`](https://rux-lang.dev/docs/api/core/compiler#compiler-constant) | The compiler performing the build, as a compile-time value. | | [`#config`](https://rux-lang.dev/docs/api/core/config#config-constant) | The build's user-defined values, as a compile-time value. | | [`#source`](https://rux-lang.dev/docs/api/core/source#source-constant) | The reading expression's own location, as a compile-time value. | | [`#target`](https://rux-lang.dev/docs/api/core/target#target-constant) | The machine being compiled for, as a compile-time value. | # Comparable Ordering: which of two values of one type comes first. ```rux pub interface Comparable { func Compare(other: &Self) -> Ordering; } ``` The bound a generic writes when it needs to sort, search a sorted sequence, or find an extreme. `Self` in the signature is the implementing type, so a value is only ever ordered against another of its own type. An implementation must be a total order: exactly one of less, equal or greater holds for any pair; reversing the operands reverses the answer; and the relation is transitive, for the ordering and for the equality it reports. A type with a value that compares unordered against everything, the way a floating-point NaN does, cannot promise this and should not implement it. Algorithms that sort or search assume all three and may otherwise loop, drop elements, or read past their bounds. A type implementing both this and [`Equatable`](https://rux-lang.dev/docs/api/core/equatable) must keep them agreeable: [`Compare`](https://rux-lang.dev/docs/api/core/comparable#compare) reports `Equal` exactly when [`Equals`](https://rux-lang.dev/docs/api/core/equatable#equals) reports true. ## Requirements ### `Compare` ```rux func Compare(other: &Self) -> Ordering ``` Compares this value against `other`. Borrows both operands and takes ownership of neither. The reference guarantees that `other` is present. Returns `Less` when this value comes first, `Greater` when `other` does, and `Equal` when neither does. Cannot fail: a total order places every pair. | Name | Type | Description | | ------- | ------- | ---------------------------- | | `other` | `&Self` | the value to compare against | **Returns**: how this value orders against `other` [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Comparable.rux#L25){rel=""nofollow""} # Equatable Equality: whether two values of one type stand for the same thing. ```rux pub interface Equatable { func Equals(other: &Self) -> bool; } ``` The bound a generic writes when it needs to compare its element type — a search, a deduplication, a hash table's key. `Self` in the signature is the implementing type, so an `Equatable` value is only ever compared against another of its own type and never against an unrelated one. An implementation must be an equivalence: a value equals itself, equality reads the same in either order, and two values each equal to a third are equal to each other. A type that cannot promise all three — one with a value that does not equal itself, the way a floating-point NaN does not — should not implement this, and callers relying on it are entitled to assume it holds. A type that also implements [`Hashable`](https://rux-lang.dev/docs/api/core/hashable) must keep the two agreeable: equal values hash the same. ## Requirements ### `Equals` ```rux func Equals(other: &Self) -> bool ``` Reports whether this value and `other` are equal. Borrows both operands and takes ownership of neither, so comparing costs nothing and leaves both usable. The reference guarantees that `other` is present. Cannot fail: every pair of values of the type is either equal or not. | Name | Type | Description | | ------- | ------- | ---------------------------- | | `other` | `&Self` | the value to compare against | **Returns**: whether the two are equal [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Equatable.rux#L23){rel=""nofollow""} # Hashable Hashing: the 64-bit summary a table uses to find a value quickly. ```rux pub interface Hashable { func Hash() -> uint64; } ``` The bound a generic writes when it keys a hash table or a set on its element type. The one rule an implementation must keep is agreement with equality: two values that are equal must hash the same. The converse is not required, and unequal values sharing a hash is an ordinary collision rather than a fault. Hashing the same value twice in one program run must give the same answer, so an implementation must read only the value itself — not an address, not a counter, not the clock. A hash is not a checksum and not a digest: it is not stable across program runs, across compiler versions, or across targets, and nothing that outlives the process should be keyed on one. `Rux/Hash` supplies the named, documented algorithms for that, and `Rux/Crypto` the ones that must resist an adversary. ## Requirements ### `Hash` ```rux func Hash() -> uint64 ``` The hash of this value. Borrows the value and takes ownership of nothing, so hashing leaves it usable. Cannot fail. Every value of the type has a hash, and the same value always gives the same one within a run. **Returns**: this value's hash [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Hashable.rux#L23){rel=""nofollow""} # Iterable A value that can hand out an [`Iterator`](https://rux-lang.dev/docs/api/core/iterator) over its contents. ```rux pub interface Iterable {} ``` As with [`Iterator`](https://rux-lang.dev/docs/api/core/iterator), the compiler matches this by shape: a `for` loop accepts any type with a `func Iterate()` that returns an iterator, and calls it once at the top of the loop. The returned type differs per container, so the method cannot be written here either. `extend MyContainer : Iterable` records the intent and names the protocol; iterating does not require it. Arrays, slices and ranges are iterated directly by the compiler and implement nothing. The iterator handed out borrows the container, so the container must outlive it and must not be modified while it is alive. See [`Iterator`](https://rux-lang.dev/docs/api/core/iterator). # Iterator A cursor that yields a sequence of items one at a time. ```rux pub interface Iterator {} ``` The compiler drives iteration by shape rather than through this interface: a `for` loop accepts any type with a `func Next(self: &var Self) -> Item?`, which advances the cursor and reports either the next item or, with `none`, that the sequence has ended. The item type is whatever that optional carries, and it differs per iterator, so the method is not written here; the generic [`Cursor<T>`](https://rux-lang.dev/docs/api/core/adaptors#cursor) names it for bounds, which is how the adaptors take an iterator. What this interface adds is the name. `extend MyCursor : Iterator` records that a type means to be an iterator and documents which of its methods carry the protocol, and a bound written `<T: Iterator>` says what a generic expects of its argument. Neither is required to iterate, and a bound on it grants no operations, so a generic that needs to advance a cursor itself should take the concrete iterator type. An iterator is consumed as it is read: `Next` mutates it, and an iterator that has reported `none` keeps reporting `none`. Nothing here promises an iterator can be restarted or copied. An iterator borrows whatever it walks over. Modifying that container while an iterator over it is alive — growing a vector, rehashing a map, freeing the storage — leaves the iterator pointing at storage that has moved or gone, and reading it afterwards is undefined. Finish with the iterator before touching the container. # Sendable A type whose values may move to another thread: the bound a thread's context and result are written with. ```rux pub interface Sendable {} ``` Every type satisfies it except a reference and a type that is or holds one declared `#Unsendable()`, which is how a type whose state is not safe to share across threads, such as `Rc`, keeps to the thread that made it. # Iterator adaptors Lazy adaptors over any iterator — map, filter, skip, take, enumerate, zip and chain — and walking a slice. ## `Cursor` ```rux pub interface Cursor { func Next(self: &var Self) -> T?; } ``` Anything that yields items of type `T` one at a time through [`Next`](https://rux-lang.dev/docs/api/core/adaptors#cursor-next), which `for` and every adaptor here drive. A type conforms by having the method, whether or not it says `extend X : Cursor<T>`. Only usable as a bound. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Adaptors.rux#L13){rel=""nofollow""} **Requirements** ### `Next` ```rux func Next(self: &var Self) -> T? ``` The next item, or `none` once there are no more. **Returns**: the item [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Adaptors.rux#L17){rel=""nofollow""} ## `SliceCursor<T>` ```rux pub struct SliceCursor<T> { // private fields } ``` A cursor over the elements of a slice, by copy. `Copy`. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Adaptors.rux#L23){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | ---------------- | | `T` | the element type | **Methods** ### `Next` ```rux pub func Next(self: &var SliceCursor<T>) -> T? ``` The next element, or `none` after the last. **Returns**: the element [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Adaptors.rux#L32){rel=""nofollow""} ## `Walk<T>` ```rux pub func Walk<T>(items: T[..]) -> SliceCursor<T> ``` A cursor over the elements of `items`, so a slice can feed the adaptors. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Adaptors.rux#L44){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | ---------------- | | `T` | the element type | **Parameters** | Name | Type | Description | | ------- | ------- | ------------------------------------------- | | `items` | `T[..]` | the elements, which must outlive the cursor | **Returns**: the cursor ## `Mapped<I, T, U>` ```rux pub struct Mapped<I: Cursor<T>, T, U> { // private fields } ``` The items of a cursor, each passed through a function. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Adaptors.rux#L53){rel=""nofollow""} **Type parameters** | Name | Description | | -------------- | ------------------------------- | | `I: Cursor<T>` | the wrapped cursor | | `T` | what it yields | | `U` | what the function makes of each | **Methods** ### `Next` ```rux pub func Next(self: &var Mapped<I, T, U>) -> U? ``` The next item, transformed. **Returns**: the item [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Adaptors.rux#L62){rel=""nofollow""} ## `Map<I, T, U>` ```rux pub func Map<I: Cursor<T>, T, U>( source: I, transform: func(T) -> U ) -> Mapped<I, T, U> ``` Each item of `source` passed through `transform`, as it is asked for. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Adaptors.rux#L76){rel=""nofollow""} **Type parameters** | Name | Description | | -------------- | ----------------------------------- | | `I: Cursor<T>` | the wrapped cursor | | `T` | what it yields | | `U` | what `transform` makes of each item | **Parameters** | Name | Type | Description | | ----------- | -------------- | ----------------------- | | `source` | `I` | the cursor to wrap | | `transform` | `func(T) -> U` | what to do to each item | **Returns**: the adaptor ## `Filtered<I, T>` ```rux pub struct Filtered<I: Cursor<T>, T> { // private fields } ``` The items of a cursor that pass a test. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Adaptors.rux#L84){rel=""nofollow""} **Type parameters** | Name | Description | | -------------- | ------------------ | | `I: Cursor<T>` | the wrapped cursor | | `T` | what it yields | **Methods** ### `Next` ```rux pub func Next(self: &var Filtered<I, T>) -> T? ``` The next item that passes the test. **Returns**: the item [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Adaptors.rux#L93){rel=""nofollow""} ## `Filter<I, T>` ```rux pub func Filter<I: Cursor<T>, T>( source: I, keep: func(T) -> bool ) -> Filtered<I, T> ``` The items of `source` for which `keep` holds. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Adaptors.rux#L109){rel=""nofollow""} **Type parameters** | Name | Description | | -------------- | ------------------ | | `I: Cursor<T>` | the wrapped cursor | | `T` | what it yields | **Parameters** | Name | Type | Description | | -------- | ----------------- | ---------------------------- | | `source` | `I` | the cursor to wrap | | `keep` | `func(T) -> bool` | the test each item must pass | **Returns**: the adaptor ## `Taken<I, T>` ```rux pub struct Taken<I: Cursor<T>, T> { // private fields } ``` At most a number of items from the front of a cursor. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Adaptors.rux#L117){rel=""nofollow""} **Type parameters** | Name | Description | | -------------- | ------------------ | | `I: Cursor<T>` | the wrapped cursor | | `T` | what it yields | **Methods** ### `Next` ```rux pub func Next(self: &var Taken<I, T>) -> T? ``` The next item, or `none` once the count is reached; the wrapped cursor is not asked again after that. **Returns**: the item [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Adaptors.rux#L126){rel=""nofollow""} ## `Take<I, T>` ```rux pub func Take<I: Cursor<T>, T>( source: I, count: uint ) -> Taken<I, T> ``` The first `count` items of `source`, or all of them if it has fewer. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Adaptors.rux#L140){rel=""nofollow""} **Type parameters** | Name | Description | | -------------- | ------------------ | | `I: Cursor<T>` | the wrapped cursor | | `T` | what it yields | **Parameters** | Name | Type | Description | | -------- | ------ | ---------------------- | | `source` | `I` | the cursor to wrap | | `count` | `uint` | how many items at most | **Returns**: the adaptor ## `Skipped<I, T>` ```rux pub struct Skipped<I: Cursor<T>, T> { // private fields } ``` The items of a cursor after a number of them. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Adaptors.rux#L148){rel=""nofollow""} **Type parameters** | Name | Description | | -------------- | ------------------ | | `I: Cursor<T>` | the wrapped cursor | | `T` | what it yields | **Methods** ### `Next` ```rux pub func Next(self: &var Skipped<I, T>) -> T? ``` The next item, passing over the skipped ones the first time it is asked. **Returns**: the item [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Adaptors.rux#L157){rel=""nofollow""} ## `Skip<I, T>` ```rux pub func Skip<I: Cursor<T>, T>( source: I, count: uint ) -> Skipped<I, T> ``` The items of `source` after its first `count`. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Adaptors.rux#L173){rel=""nofollow""} **Type parameters** | Name | Description | | -------------- | ------------------ | | `I: Cursor<T>` | the wrapped cursor | | `T` | what it yields | **Parameters** | Name | Type | Description | | -------- | ------ | --------------------------- | | `source` | `I` | the cursor to wrap | | `count` | `uint` | how many items to pass over | **Returns**: the adaptor ## `Indexed<T>` ```rux pub struct Indexed<T> { pub index: uint; pub item: T; } ``` An item and its position, counting from zero. `Copy` when the item is. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Adaptors.rux#L180){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | ------------- | | `T` | the item type | **Fields** | Name | Type | Description | | ------- | ------ | ------------------------------------ | | `index` | `uint` | Where the item came in the sequence. | | `item` | `T` | The item. | ## `Enumerated<I, T>` ```rux pub struct Enumerated<I: Cursor<T>, T> { // private fields } ``` The items of a cursor with their positions. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Adaptors.rux#L191){rel=""nofollow""} **Type parameters** | Name | Description | | -------------- | ------------------ | | `I: Cursor<T>` | the wrapped cursor | | `T` | what it yields | **Methods** ### `Next` ```rux pub func Next(self: &var Enumerated<I, T>) -> Indexed<T>? ``` The next item with its position. **Returns**: the item and its position [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Adaptors.rux#L200){rel=""nofollow""} ## `Enumerate<I, T>` ```rux pub func Enumerate<I: Cursor<T>, T>(source: I) -> Enumerated<I, T> ``` Each item of `source` with its position, counting from zero. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Adaptors.rux#L213){rel=""nofollow""} **Type parameters** | Name | Description | | -------------- | ------------------ | | `I: Cursor<T>` | the wrapped cursor | | `T` | what it yields | **Parameters** | Name | Type | Description | | -------- | ---- | ------------------ | | `source` | `I` | the cursor to wrap | **Returns**: the adaptor ## `Pair<A, B>` ```rux pub struct Pair<A, B> { pub first: A; pub second: B; } ``` One item from each of two cursors. `Copy` when both are. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Adaptors.rux#L221){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | -------------------- | | `A` | the first item type | | `B` | the second item type | **Fields** | Name | Type | Description | | -------- | ---- | -------------------------------- | | `first` | `A` | The item from the first cursor. | | `second` | `B` | The item from the second cursor. | ## `Zipped<I, J, A, B>` ```rux pub struct Zipped<I: Cursor<A>, J: Cursor<B>, A, B> { // private fields } ``` The items of two cursors side by side. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Adaptors.rux#L234){rel=""nofollow""} **Type parameters** | Name | Description | | -------------- | ---------------------- | | `I: Cursor<A>` | the first cursor | | `J: Cursor<B>` | the second cursor | | `A` | what the first yields | | `B` | what the second yields | **Methods** ### `Next` ```rux pub func Next(self: &var Zipped<I, J, A, B>) -> Pair<A, B>? ``` The next item of each, or `none` once either runs out. **Returns**: the pair [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Adaptors.rux#L243){rel=""nofollow""} ## `Zip<I, J, A, B>` ```rux pub func Zip<I: Cursor<A>, J: Cursor<B>, A, B>( first: I, second: J ) -> Zipped<I, J, A, B> ``` The items of `first` and `second` in pairs, as long as both last. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Adaptors.rux#L259){rel=""nofollow""} **Type parameters** | Name | Description | | -------------- | ---------------------- | | `I: Cursor<A>` | the first cursor | | `J: Cursor<B>` | the second cursor | | `A` | what the first yields | | `B` | what the second yields | **Parameters** | Name | Type | Description | | -------- | ---- | ----------------- | | `first` | `I` | the first cursor | | `second` | `J` | the second cursor | **Returns**: the adaptor ## `Chained<I, J, T>` ```rux pub struct Chained<I: Cursor<T>, J: Cursor<T>, T> { // private fields } ``` The items of one cursor and then of another. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Adaptors.rux#L268){rel=""nofollow""} **Type parameters** | Name | Description | | -------------- | ----------------- | | `I: Cursor<T>` | the first cursor | | `J: Cursor<T>` | the second cursor | | `T` | what both yield | **Methods** ### `Next` ```rux pub func Next(self: &var Chained<I, J, T>) -> T? ``` The next item of the first cursor, then of the second once the first has run out. **Returns**: the item [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Adaptors.rux#L278){rel=""nofollow""} ## `Chain<I, J, T>` ```rux pub func Chain<I: Cursor<T>, J: Cursor<T>, T>( first: I, second: J ) -> Chained<I, J, T> ``` The items of `first` followed by the items of `second`. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Adaptors.rux#L297){rel=""nofollow""} **Type parameters** | Name | Description | | -------------- | ----------------- | | `I: Cursor<T>` | the first cursor | | `J: Cursor<T>` | the second cursor | | `T` | what both yield | **Parameters** | Name | Type | Description | | -------- | ---- | ------------------------ | | `first` | `I` | the cursor read first | | `second` | `J` | the cursor read after it | **Returns**: the adaptor # Booleans The boolean types [`bool8`](https://rux-lang.dev/docs/api/core/booleans#bool8) to [`bool512`](https://rux-lang.dev/docs/api/core/booleans#bool512), with their width constants. The built-in `bool` is [`bool8`](https://rux-lang.dev/docs/api/core/booleans#bool8) and shares its constants. ## `bool8` ```rux extend bool8 ``` One of two values, stored in 8 bits. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Bool8.rux#L7){rel=""nofollow""} **Constants** ### `Bits` ```rux pub const Bits: uint = 8; ``` The number of bits in the representation. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Bool8.rux#L10){rel=""nofollow""} ### `Bytes` ```rux pub const Bytes: uint = 1; ``` The number of bytes in the representation. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Bool8.rux#L13){rel=""nofollow""} ## `bool16` ```rux extend bool16 ``` One of two values, stored in 16 bits. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Bool16.rux#L7){rel=""nofollow""} **Constants** ### `Bits` ```rux pub const Bits: uint = 16; ``` The number of bits in the representation. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Bool16.rux#L10){rel=""nofollow""} ### `Bytes` ```rux pub const Bytes: uint = 2; ``` The number of bytes in the representation. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Bool16.rux#L13){rel=""nofollow""} ## `bool32` ```rux extend bool32 ``` One of two values, stored in 32 bits. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Bool32.rux#L7){rel=""nofollow""} **Constants** ### `Bits` ```rux pub const Bits: uint = 32; ``` The number of bits in the representation. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Bool32.rux#L10){rel=""nofollow""} ### `Bytes` ```rux pub const Bytes: uint = 4; ``` The number of bytes in the representation. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Bool32.rux#L13){rel=""nofollow""} ## `bool64` ```rux extend bool64 ``` One of two values, stored in 64 bits. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Bool64.rux#L7){rel=""nofollow""} **Constants** ### `Bits` ```rux pub const Bits: uint = 64; ``` The number of bits in the representation. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Bool64.rux#L10){rel=""nofollow""} ### `Bytes` ```rux pub const Bytes: uint = 8; ``` The number of bytes in the representation. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Bool64.rux#L13){rel=""nofollow""} ## `bool128` ```rux extend bool128 ``` One of two values, stored in 128 bits. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Bool128.rux#L7){rel=""nofollow""} **Constants** ### `Bits` ```rux pub const Bits: uint = 128; ``` The number of bits in the representation. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Bool128.rux#L10){rel=""nofollow""} ### `Bytes` ```rux pub const Bytes: uint = 16; ``` The number of bytes in the representation. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Bool128.rux#L13){rel=""nofollow""} ## `bool256` ```rux extend bool256 ``` One of two values, stored in 256 bits. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Bool256.rux#L7){rel=""nofollow""} **Constants** ### `Bits` ```rux pub const Bits: uint = 256; ``` The number of bits in the representation. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Bool256.rux#L10){rel=""nofollow""} ### `Bytes` ```rux pub const Bytes: uint = 32; ``` The number of bytes in the representation. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Bool256.rux#L13){rel=""nofollow""} ## `bool512` ```rux extend bool512 ``` One of two values, stored in 512 bits. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Bool512.rux#L7){rel=""nofollow""} **Constants** ### `Bits` ```rux pub const Bits: uint = 512; ``` The number of bits in the representation. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Bool512.rux#L10){rel=""nofollow""} ### `Bytes` ```rux pub const Bytes: uint = 64; ``` The number of bytes in the representation. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Bool512.rux#L13){rel=""nofollow""} # Build Properties of the active build profile and its output. ```rux pub struct Build { pub profile: char8[..]; pub mode: BuildMode; pub optimization: OptimizationMode; pub debugAssertions: bool; pub debugInfo: bool; pub isTest: bool; pub outputKind: OutputKind; pub timestamp: uint64; pub date: char8[..]; pub time: char8[..]; } ``` Every field is fixed when compiling begins and is the same everywhere in one build. Reading one produces no runtime code, so a branch on a field is decided while compiling and the untaken side is not emitted. ## Fields | Name | Type | Description | | ----------------- | ------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `profile` | `char8[..]` | The profile's name as the project spelled it, which may be a project-defined profile rather than one of the two standard ones. | | `mode` | `BuildMode` | The mode the profile implies, which is what a package should branch on. | | `optimization` | `OptimizationMode` | What the profile asked the optimizer to favor. | | `debugAssertions` | `bool` | Whether [`DebugAssert`](https://rux-lang.dev/docs/api/core/diagnostics#debug-assert) checks are kept. False means they are removed without their arguments being evaluated. | | `debugInfo` | `bool` | Whether debug information is emitted alongside the output. | | `isTest` | `bool` | Whether this build is a test build, which is how a package tells a test-only path from a shipped one. | | `outputKind` | `OutputKind` | The artifact being produced. | | `timestamp` | `uint64` | When the build started, in seconds since the Unix epoch. Fixed once per build, so it identifies the build and does not measure time. | | `date` | `char8[..]` | The build's start date as `YYYY-MM-DD`. | | `time` | `char8[..]` | The build's start time as `HH:MM:SS`. | ## Related ### `BuildMode` ```rux pub enum BuildMode: uint8 { Debug = 0, Release = 1 } ``` The high-level mode of the active build profile. A profile is a name, and more than one profile may share a mode; this is the part a package can branch on without knowing which profiles a project defined. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Build.rux#L12){rel=""nofollow""} **Cases** | Name | Value | Description | | --------- | ----- | ----------------------------------------------------------------------- | | `Debug` | `0` | Unoptimized, with debug assertions and debug information on by default. | | `Release` | `1` | Optimized, with debug assertions removed by default. | ### `OptimizationMode` ```rux pub enum OptimizationMode: uint8 { None = 0, Size = 1, Speed = 2 } ``` What the active build asked the optimizer to favor. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Build.rux#L21){rel=""nofollow""} **Cases** | Name | Value | Description | | ------- | ----- | -------------------------------------------------------------------- | | `None` | `0` | No optimization: the output follows the source as closely as it can. | | `Size` | `1` | Smaller output preferred where it costs speed. | | `Speed` | `2` | Faster output preferred where it costs size. | ### `OutputKind` ```rux pub enum OutputKind: uint8 { Executable = 0, SharedLibrary = 1, StaticLibrary = 2, SourceLibrary = 3 } ``` The kind of artifact the active build produces. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Build.rux#L32){rel=""nofollow""} **Cases** | Name | Value | Description | | --------------- | ----- | ------------------------------------------------------------------- | | `Executable` | `0` | A program with an entry point. | | `SharedLibrary` | `1` | A library linked at load time and shipped as its own file. | | `StaticLibrary` | `2` | A library linked into whatever uses it, as compiled code. | | `SourceLibrary` | `3` | A library linked into whatever uses it, as source compiled with it. | ### `#build` ```rux pub const #build: Build; ``` The active build, as a compile-time value. Reading a field produces no runtime code. A `when` on one keeps only the branch that applies, so the untaken side is never resolved or type-checked and may name things this build does not have. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Build.rux#L76){rel=""nofollow""} # Characters The character types [`char8`](https://rux-lang.dev/docs/api/core/characters#char8) to [`char512`](https://rux-lang.dev/docs/api/core/characters#char512), with their width and limit constants. The built-in `char` is [`char32`](https://rux-lang.dev/docs/api/core/characters#char32) and shares its constants. ## `char8` ```rux extend char8 ``` One UTF-8 code unit. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Char8.rux#L8){rel=""nofollow""} **Constants** ### `Bits` ```rux pub const Bits: uint = 8; ``` The number of bits in the representation. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Char8.rux#L11){rel=""nofollow""} ### `Bytes` ```rux pub const Bytes: uint = 1; ``` The number of bytes in the representation. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Char8.rux#L14){rel=""nofollow""} ### `Min` ```rux pub const Min: char8 = 0u32 as char8; ``` The first code unit or Unicode scalar value. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Char8.rux#L17){rel=""nofollow""} ### `Max` ```rux pub const Max: char8 = 255u32 as char8; ``` The last code unit or Unicode scalar value. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Char8.rux#L20){rel=""nofollow""} ## `char16` ```rux extend char16 ``` One UTF-16 code unit. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Char16.rux#L7){rel=""nofollow""} **Constants** ### `Bits` ```rux pub const Bits: uint = 16; ``` The number of bits in the representation. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Char16.rux#L10){rel=""nofollow""} ### `Bytes` ```rux pub const Bytes: uint = 2; ``` The number of bytes in the representation. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Char16.rux#L13){rel=""nofollow""} ### `Min` ```rux pub const Min: char16 = 0u32 as char16; ``` The first code unit or Unicode scalar value. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Char16.rux#L16){rel=""nofollow""} ### `Max` ```rux pub const Max: char16 = 65535u32 as char16; ``` The last code unit or Unicode scalar value. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Char16.rux#L19){rel=""nofollow""} ## `char32` ```rux extend char32 ``` One Unicode scalar value. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Char32.rux#L7){rel=""nofollow""} **Constants** ### `Bits` ```rux pub const Bits: uint = 32; ``` The number of bits in the representation. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Char32.rux#L10){rel=""nofollow""} ### `Bytes` ```rux pub const Bytes: uint = 4; ``` The number of bytes in the representation. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Char32.rux#L13){rel=""nofollow""} ### `Min` ```rux pub const Min: char32 = 0u32 as char32; ``` The first code unit or Unicode scalar value. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Char32.rux#L16){rel=""nofollow""} ### `Max` ```rux pub const Max: char32 = 1114111u32 as char32; ``` The last code unit or Unicode scalar value. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Char32.rux#L19){rel=""nofollow""} ## `char64` ```rux extend char64 ``` One Unicode scalar value, in eight bytes. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Char64.rux#L8){rel=""nofollow""} **Constants** ### `Bits` ```rux pub const Bits: uint = 64; ``` The number of bits in the representation. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Char64.rux#L11){rel=""nofollow""} ### `Bytes` ```rux pub const Bytes: uint = 8; ``` The number of bytes in the representation. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Char64.rux#L14){rel=""nofollow""} ### `Min` ```rux pub const Min: char64 = 0u32 as char64; ``` The first code unit or Unicode scalar value. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Char64.rux#L17){rel=""nofollow""} ### `Max` ```rux pub const Max: char64 = 1114111u32 as char64; ``` The last code unit or Unicode scalar value. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Char64.rux#L20){rel=""nofollow""} ## `char128` ```rux extend char128 ``` One Unicode scalar value, in sixteen bytes. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Char128.rux#L8){rel=""nofollow""} **Constants** ### `Bits` ```rux pub const Bits: uint = 128; ``` The number of bits in the representation. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Char128.rux#L11){rel=""nofollow""} ### `Bytes` ```rux pub const Bytes: uint = 16; ``` The number of bytes in the representation. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Char128.rux#L14){rel=""nofollow""} ### `Min` ```rux pub const Min: char128 = 0u32 as char128; ``` The first code unit or Unicode scalar value. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Char128.rux#L17){rel=""nofollow""} ### `Max` ```rux pub const Max: char128 = 1114111u32 as char128; ``` The last code unit or Unicode scalar value. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Char128.rux#L20){rel=""nofollow""} ## `char256` ```rux extend char256 ``` One Unicode scalar value, in thirty-two bytes. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Char256.rux#L8){rel=""nofollow""} **Constants** ### `Bits` ```rux pub const Bits: uint = 256; ``` The number of bits in the representation. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Char256.rux#L11){rel=""nofollow""} ### `Bytes` ```rux pub const Bytes: uint = 32; ``` The number of bytes in the representation. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Char256.rux#L14){rel=""nofollow""} ### `Min` ```rux pub const Min: char256 = 0u32 as char256; ``` The first code unit or Unicode scalar value. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Char256.rux#L17){rel=""nofollow""} ### `Max` ```rux pub const Max: char256 = 1114111u32 as char256; ``` The last code unit or Unicode scalar value. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Char256.rux#L20){rel=""nofollow""} ## `char512` ```rux extend char512 ``` One Unicode scalar value, in sixty-four bytes. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Char512.rux#L8){rel=""nofollow""} **Constants** ### `Bits` ```rux pub const Bits: uint = 512; ``` The number of bits in the representation. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Char512.rux#L11){rel=""nofollow""} ### `Bytes` ```rux pub const Bytes: uint = 64; ``` The number of bytes in the representation. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Char512.rux#L14){rel=""nofollow""} ### `Min` ```rux pub const Min: char512 = 0u32 as char512; ``` The first code unit or Unicode scalar value. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Char512.rux#L17){rel=""nofollow""} ### `Max` ```rux pub const Max: char512 = 1114111u32 as char512; ``` The last code unit or Unicode scalar value. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Char512.rux#L20){rel=""nofollow""} # Compiler Properties of the compiler performing the build. ```rux pub struct Compiler { pub version: SemanticVersion; } ``` Fixed when compiling begins. Reading a field produces no runtime code. ## Fields | Name | Type | Description | | --------- | ----------------- | --------------------------- | | `version` | `SemanticVersion` | The compiler's own version. | ## Methods ### `HasFeature` ```rux pub func HasFeature( self: &Compiler, feature: char8[..] ) -> bool ``` Whether this compiler provides the named language or library feature. `self` is borrowed and `feature` must be a string literal, since this is answered while compiling. Prefer it to comparing `version`: a feature name says what the code needs, and stays right when the feature arrives in a release the comparison did not anticipate. Cannot fail: an unknown name is absent rather than an error. Costs nothing in the built program. | Name | Type | Description | | --------- | ----------- | ------------------ | | `feature` | `char8[..]` | the feature's name | **Returns**: whether this compiler reports that feature [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Compiler.rux#L168){rel=""nofollow""} ## Related ### `#compiler` ```rux pub const #compiler: Compiler; ``` The compiler performing the build, as a compile-time value. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Compiler.rux#L173){rel=""nofollow""} # Config The set of user-defined build values. ```rux pub struct Config {} ``` Carries no fields: the values live in the build rather than in the value, and are reached through the two queries below. [`#config`](https://rux-lang.dev/docs/api/core/config#config-constant) is the only instance. ## Methods ### `Get` ```rux pub func Get(self: &Config, name: char8[..]) -> char8[..] ``` The value defined for `name`, or an empty slice when none was. `self` is borrowed and `name` must be a string literal, since this is answered while compiling. Returns a borrowed view of the build's own storage, which outlives the program. An absent name and a name defined as empty both yield an empty slice; use [`Has`](https://rux-lang.dev/docs/api/core/config#has) to tell them apart. Cannot fail. Costs nothing in the built program. | Name | Type | Description | | ------ | ----------- | ---------------------- | | `name` | `char8[..]` | the build value's name | **Returns**: its value, or an empty slice when the build defines none [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Config.rux#L23){rel=""nofollow""} ### `Has` ```rux pub func Has(self: &Config, name: char8[..]) -> bool ``` Whether `name` was defined at all, whatever its value. `self` is borrowed and `name` must be a string literal. Answered while compiling. Cannot fail. Costs nothing in the built program. | Name | Type | Description | | ------ | ----------- | ---------------------- | | `name` | `char8[..]` | the build value's name | **Returns**: whether the build defines it [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Config.rux#L31){rel=""nofollow""} ## Related ### `#config` ```rux pub const #config: Config; ``` The build's user-defined values, as a compile-time value. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Config.rux#L36){rel=""nofollow""} # Floating-point types The floating-point types [`float8`](https://rux-lang.dev/docs/api/core/floating-point#float8) to [`float512`](https://rux-lang.dev/docs/api/core/floating-point#float512), with their width, limit and special-value constants. The built-in `float` is [`float64`](https://rux-lang.dev/docs/api/core/floating-point#float64) and shares its constants. ## `float8` ```rux extend float8 ``` An eight-bit E4M3 floating-point number with IEEE 754 infinities and NaNs. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Float8.rux#L9){rel=""nofollow""} **Constants** ### `Bits` ```rux pub const Bits: uint = 8; ``` The number of bits in the representation. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Float8.rux#L12){rel=""nofollow""} ### `Bytes` ```rux pub const Bytes: uint = 1; ``` The number of bytes in the representation. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Float8.rux#L15){rel=""nofollow""} ### `Lowest` ```rux pub const Lowest: float8 = -240.0f8; ``` The lowest finite value. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Float8.rux#L18){rel=""nofollow""} ### `Max` ```rux pub const Max: float8 = 240.0f8; ``` The highest finite value. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Float8.rux#L21){rel=""nofollow""} ### `MinPositive` ```rux pub const MinPositive: float8 = 0.015625f8; ``` The smallest positive normal value. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Float8.rux#L24){rel=""nofollow""} ### `Epsilon` ```rux pub const Epsilon: float8 = 0.125f8; ``` The difference between one and the next representable value. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Float8.rux#L27){rel=""nofollow""} ### `Infinity` ```rux pub const Infinity: float8; ``` Positive infinity. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Float8.rux#L30){rel=""nofollow""} ### `NaN` ```rux pub const NaN: float8; ``` A quiet not-a-number value. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Float8.rux#L33){rel=""nofollow""} ## `float16` ```rux extend float16 ``` An IEEE 754 binary16 floating-point number. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Float16.rux#L6){rel=""nofollow""} **Constants** ### `Bits` ```rux pub const Bits: uint = 16; ``` The number of bits in the representation. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Float16.rux#L9){rel=""nofollow""} ### `Bytes` ```rux pub const Bytes: uint = 2; ``` The number of bytes in the representation. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Float16.rux#L12){rel=""nofollow""} ### `Lowest` ```rux pub const Lowest: float16 = -65504.0f16; ``` The lowest finite value. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Float16.rux#L15){rel=""nofollow""} ### `Max` ```rux pub const Max: float16 = 65504.0f16; ``` The highest finite value. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Float16.rux#L18){rel=""nofollow""} ### `MinPositive` ```rux pub const MinPositive: float16 = 6.103515625e-05f16; ``` The smallest positive normal value. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Float16.rux#L21){rel=""nofollow""} ### `Epsilon` ```rux pub const Epsilon: float16 = 0.0009765625f16; ``` The difference between one and the next representable value. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Float16.rux#L24){rel=""nofollow""} ### `Infinity` ```rux pub const Infinity: float16; ``` Positive infinity. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Float16.rux#L27){rel=""nofollow""} ### `NaN` ```rux pub const NaN: float16; ``` A quiet not-a-number value. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Float16.rux#L30){rel=""nofollow""} ## `float32` ```rux extend float32 ``` An IEEE 754 binary32 floating-point number. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Float32.rux#L7){rel=""nofollow""} **Constants** ### `Bits` ```rux pub const Bits: uint = 32; ``` The number of bits in the representation. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Float32.rux#L10){rel=""nofollow""} ### `Bytes` ```rux pub const Bytes: uint = 4; ``` The number of bytes in the representation. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Float32.rux#L13){rel=""nofollow""} ### `Lowest` ```rux pub const Lowest: float32 = -3.4028234663852886e+38f32; ``` The lowest finite value. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Float32.rux#L16){rel=""nofollow""} ### `Max` ```rux pub const Max: float32 = 3.4028234663852886e+38f32; ``` The highest finite value. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Float32.rux#L19){rel=""nofollow""} ### `MinPositive` ```rux pub const MinPositive: float32 = 1.1754943508222875e-38f32; ``` The smallest positive normal value. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Float32.rux#L22){rel=""nofollow""} ### `Epsilon` ```rux pub const Epsilon: float32 = 1.1920928955078125e-7f32; ``` The difference between one and the next representable value. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Float32.rux#L25){rel=""nofollow""} ### `Infinity` ```rux pub const Infinity: float32; ``` Positive infinity. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Float32.rux#L28){rel=""nofollow""} ### `NaN` ```rux pub const NaN: float32; ``` A quiet not-a-number value. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Float32.rux#L31){rel=""nofollow""} ## `float64` ```rux extend float64 ``` An IEEE 754 binary64 floating-point number. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Float64.rux#L6){rel=""nofollow""} **Constants** ### `Bits` ```rux pub const Bits: uint = 64; ``` The number of bits in the representation. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Float64.rux#L9){rel=""nofollow""} ### `Bytes` ```rux pub const Bytes: uint = 8; ``` The number of bytes in the representation. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Float64.rux#L12){rel=""nofollow""} ### `Lowest` ```rux pub const Lowest: float64 = -1.7976931348623157e+308f64; ``` The lowest finite value. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Float64.rux#L15){rel=""nofollow""} ### `Max` ```rux pub const Max: float64 = 1.7976931348623157e+308f64; ``` The highest finite value. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Float64.rux#L18){rel=""nofollow""} ### `MinPositive` ```rux pub const MinPositive: float64 = 2.2250738585072014e-308f64; ``` The smallest positive normal value. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Float64.rux#L21){rel=""nofollow""} ### `Epsilon` ```rux pub const Epsilon: float64 = 2.2204460492503131e-16f64; ``` The difference between one and the next representable value. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Float64.rux#L24){rel=""nofollow""} ### `Infinity` ```rux pub const Infinity: float64; ``` Positive infinity. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Float64.rux#L27){rel=""nofollow""} ### `NaN` ```rux pub const NaN: float64; ``` A quiet not-a-number value. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Float64.rux#L30){rel=""nofollow""} ## `float80` ```rux extend float80 ``` An x87 extended-precision floating-point number. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Float80.rux#L8){rel=""nofollow""} **Constants** ### `Bits` ```rux pub const Bits: uint = 80; ``` The number of bits in the representation. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Float80.rux#L11){rel=""nofollow""} ### `Bytes` ```rux pub const Bytes: uint = 16; ``` The number of bytes in the representation. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Float80.rux#L14){rel=""nofollow""} ### `Lowest` ```rux pub const Lowest: float80; ``` The lowest finite value. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Float80.rux#L17){rel=""nofollow""} ### `Max` ```rux pub const Max: float80; ``` The highest finite value. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Float80.rux#L20){rel=""nofollow""} ### `MinPositive` ```rux pub const MinPositive: float80; ``` The smallest positive normal value. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Float80.rux#L23){rel=""nofollow""} ### `Epsilon` ```rux pub const Epsilon: float80; ``` The difference between one and the next representable value. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Float80.rux#L26){rel=""nofollow""} ### `Infinity` ```rux pub const Infinity: float80; ``` Positive infinity. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Float80.rux#L29){rel=""nofollow""} ### `NaN` ```rux pub const NaN: float80; ``` A quiet not-a-number value. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Float80.rux#L32){rel=""nofollow""} ## `float128` ```rux extend float128 ``` An IEEE 754 binary128 floating-point number. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Float128.rux#L7){rel=""nofollow""} **Constants** ### `Bits` ```rux pub const Bits: uint = 128; ``` The number of bits in the representation. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Float128.rux#L10){rel=""nofollow""} ### `Bytes` ```rux pub const Bytes: uint = 16; ``` The number of bytes in the representation. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Float128.rux#L13){rel=""nofollow""} ### `Lowest` ```rux pub const Lowest: float128; ``` The lowest finite value. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Float128.rux#L16){rel=""nofollow""} ### `Max` ```rux pub const Max: float128; ``` The highest finite value. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Float128.rux#L19){rel=""nofollow""} ### `MinPositive` ```rux pub const MinPositive: float128; ``` The smallest positive normal value. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Float128.rux#L22){rel=""nofollow""} ### `Epsilon` ```rux pub const Epsilon: float128; ``` The difference between one and the next representable value. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Float128.rux#L25){rel=""nofollow""} ### `Infinity` ```rux pub const Infinity: float128; ``` Positive infinity. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Float128.rux#L28){rel=""nofollow""} ### `NaN` ```rux pub const NaN: float128; ``` A quiet not-a-number value. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Float128.rux#L31){rel=""nofollow""} ## `float256` ```rux extend float256 ``` An IEEE 754 binary256 floating-point number. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Float256.rux#L8){rel=""nofollow""} **Constants** ### `Bits` ```rux pub const Bits: uint = 256; ``` The number of bits in the representation. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Float256.rux#L11){rel=""nofollow""} ### `Bytes` ```rux pub const Bytes: uint = 32; ``` The number of bytes in the representation. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Float256.rux#L14){rel=""nofollow""} ### `Lowest` ```rux pub const Lowest: float256; ``` The lowest finite value. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Float256.rux#L17){rel=""nofollow""} ### `Max` ```rux pub const Max: float256; ``` The highest finite value. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Float256.rux#L20){rel=""nofollow""} ### `MinPositive` ```rux pub const MinPositive: float256; ``` The smallest positive normal value. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Float256.rux#L23){rel=""nofollow""} ### `Epsilon` ```rux pub const Epsilon: float256; ``` The difference between one and the next representable value. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Float256.rux#L26){rel=""nofollow""} ### `Infinity` ```rux pub const Infinity: float256; ``` Positive infinity. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Float256.rux#L29){rel=""nofollow""} ### `NaN` ```rux pub const NaN: float256; ``` A quiet not-a-number value. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Float256.rux#L32){rel=""nofollow""} ## `float512` ```rux extend float512 ``` A binary512 floating-point number in the IEEE 754 interchange-format progression. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Float512.rux#L8){rel=""nofollow""} **Constants** ### `Bits` ```rux pub const Bits: uint = 512; ``` The number of bits in the representation. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Float512.rux#L11){rel=""nofollow""} ### `Bytes` ```rux pub const Bytes: uint = 64; ``` The number of bytes in the representation. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Float512.rux#L14){rel=""nofollow""} ### `Lowest` ```rux pub const Lowest: float512; ``` The lowest finite value. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Float512.rux#L17){rel=""nofollow""} ### `Max` ```rux pub const Max: float512; ``` The highest finite value. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Float512.rux#L20){rel=""nofollow""} ### `MinPositive` ```rux pub const MinPositive: float512; ``` The smallest positive normal value. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Float512.rux#L23){rel=""nofollow""} ### `Epsilon` ```rux pub const Epsilon: float512; ``` The difference between one and the next representable value. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Float512.rux#L26){rel=""nofollow""} ### `Infinity` ```rux pub const Infinity: float512; ``` Positive infinity. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Float512.rux#L29){rel=""nofollow""} ### `NaN` ```rux pub const NaN: float512; ``` A quiet not-a-number value. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Float512.rux#L32){rel=""nofollow""} # Integers The signed and unsigned integer types from 8 to 512 bits and the pointer-sized [`int`](https://rux-lang.dev/docs/api/core/integers#int) and [`uint`](https://rux-lang.dev/docs/api/core/integers#uint), with their width and limit constants. The built-in `byte` is [`uint8`](https://rux-lang.dev/docs/api/core/integers#uint8) and shares its constants. ## `int` ```rux extend int ``` A target pointer-sized signed integer. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Int.rux#L7){rel=""nofollow""} **Constants** ### `Bits` ```rux pub const Bits: uint = sizeof(int) * 8u; ``` The target representation width in bits. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Int.rux#L10){rel=""nofollow""} ### `Bytes` ```rux pub const Bytes: uint = sizeof(int); ``` The target representation size in bytes. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Int.rux#L13){rel=""nofollow""} ### `Min` ```rux pub const Min: int = -(((~0u) >> 1u) as int) - 1; ``` The smallest representable value. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Int.rux#L16){rel=""nofollow""} ### `Max` ```rux pub const Max: int = ((~0u) >> 1u) as int; ``` The largest representable value. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Int.rux#L19){rel=""nofollow""} ## `int8` ```rux extend int8 ``` A signed integer in 8 bits, two's complement. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Int8.rux#L7){rel=""nofollow""} **Constants** ### `Bits` ```rux pub const Bits: uint = 8; ``` The number of bits in the representation. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Int8.rux#L10){rel=""nofollow""} ### `Bytes` ```rux pub const Bytes: uint = 1; ``` The number of bytes in the representation. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Int8.rux#L13){rel=""nofollow""} ### `Min` ```rux pub const Min: int8 = -128; ``` The smallest representable value. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Int8.rux#L16){rel=""nofollow""} ### `Max` ```rux pub const Max: int8 = 127; ``` The largest representable value. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Int8.rux#L19){rel=""nofollow""} ## `int16` ```rux extend int16 ``` A signed integer in 16 bits, two's complement. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Int16.rux#L7){rel=""nofollow""} **Constants** ### `Bits` ```rux pub const Bits: uint = 16; ``` The number of bits in the representation. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Int16.rux#L10){rel=""nofollow""} ### `Bytes` ```rux pub const Bytes: uint = 2; ``` The number of bytes in the representation. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Int16.rux#L13){rel=""nofollow""} ### `Min` ```rux pub const Min: int16 = -32768; ``` The smallest representable value. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Int16.rux#L16){rel=""nofollow""} ### `Max` ```rux pub const Max: int16 = 32767; ``` The largest representable value. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Int16.rux#L19){rel=""nofollow""} ## `int32` ```rux extend int32 ``` A signed integer in 32 bits, two's complement. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Int32.rux#L7){rel=""nofollow""} **Constants** ### `Bits` ```rux pub const Bits: uint = 32; ``` The number of bits in the representation. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Int32.rux#L10){rel=""nofollow""} ### `Bytes` ```rux pub const Bytes: uint = 4; ``` The number of bytes in the representation. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Int32.rux#L13){rel=""nofollow""} ### `Min` ```rux pub const Min: int32 = -2147483648; ``` The smallest representable value. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Int32.rux#L16){rel=""nofollow""} ### `Max` ```rux pub const Max: int32 = 2147483647; ``` The largest representable value. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Int32.rux#L19){rel=""nofollow""} ## `int64` ```rux extend int64 ``` A signed integer in 64 bits, two's complement. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Int64.rux#L7){rel=""nofollow""} **Constants** ### `Bits` ```rux pub const Bits: uint = 64; ``` The number of bits in the representation. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Int64.rux#L10){rel=""nofollow""} ### `Bytes` ```rux pub const Bytes: uint = 8; ``` The number of bytes in the representation. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Int64.rux#L13){rel=""nofollow""} ### `Min` ```rux pub const Min: int64 = -9223372036854775808; ``` The smallest representable value. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Int64.rux#L16){rel=""nofollow""} ### `Max` ```rux pub const Max: int64 = 9223372036854775807; ``` The largest representable value. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Int64.rux#L19){rel=""nofollow""} ## `int128` ```rux extend int128 ``` A signed integer in 128 bits, two's complement. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Int128.rux#L7){rel=""nofollow""} **Constants** ### `Bits` ```rux pub const Bits: uint = 128u; ``` The number of bits in the representation. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Int128.rux#L10){rel=""nofollow""} ### `Bytes` ```rux pub const Bytes: uint = 16u; ``` The number of bytes in the representation. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Int128.rux#L13){rel=""nofollow""} ### `Min` ```rux pub const Min: int128 = -170141183460469231731687303715884105728i128; ``` The smallest representable value. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Int128.rux#L16){rel=""nofollow""} ### `Max` ```rux pub const Max: int128 = 170141183460469231731687303715884105727i128; ``` The largest representable value. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Int128.rux#L19){rel=""nofollow""} ## `int256` ```rux extend int256 ``` A signed integer in 256 bits, two's complement. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Int256.rux#L7){rel=""nofollow""} **Constants** ### `Bits` ```rux pub const Bits: uint = 256u; ``` The number of bits in the representation. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Int256.rux#L10){rel=""nofollow""} ### `Bytes` ```rux pub const Bytes: uint = 32u; ``` The number of bytes in the representation. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Int256.rux#L13){rel=""nofollow""} ### `Min` ```rux pub const Min: int256 = -57896044618658097711785492504343953926634992332820282019728792003956564819968i256; ``` The smallest representable value. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Int256.rux#L16){rel=""nofollow""} ### `Max` ```rux pub const Max: int256 = 57896044618658097711785492504343953926634992332820282019728792003956564819967i256; ``` The largest representable value. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Int256.rux#L19){rel=""nofollow""} ## `int512` ```rux extend int512 ``` A signed integer in 512 bits, two's complement. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Int512.rux#L7){rel=""nofollow""} **Constants** ### `Bits` ```rux pub const Bits: uint = 512u; ``` The number of bits in the representation. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Int512.rux#L10){rel=""nofollow""} ### `Bytes` ```rux pub const Bytes: uint = 64u; ``` The number of bytes in the representation. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Int512.rux#L13){rel=""nofollow""} ### `Min` ```rux pub const Min: int512 = …; ``` The smallest representable value. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Int512.rux#L16){rel=""nofollow""} ### `Max` ```rux pub const Max: int512 = …; ``` The largest representable value. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Int512.rux#L19){rel=""nofollow""} ## `uint` ```rux extend uint ``` A target pointer-sized unsigned integer. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Uint.rux#L6){rel=""nofollow""} **Constants** ### `Bits` ```rux pub const Bits: uint = sizeof(uint) * 8u; ``` The target representation width in bits. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Uint.rux#L9){rel=""nofollow""} ### `Bytes` ```rux pub const Bytes: uint = sizeof(uint); ``` The target representation size in bytes. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Uint.rux#L12){rel=""nofollow""} ### `Min` ```rux pub const Min: uint = 0u; ``` The smallest representable value. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Uint.rux#L15){rel=""nofollow""} ### `Max` ```rux pub const Max: uint = ~0u; ``` The largest representable value. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Uint.rux#L18){rel=""nofollow""} ## `uint8` ```rux extend uint8 ``` An unsigned integer in 8 bits. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Uint8.rux#L7){rel=""nofollow""} **Constants** ### `Bits` ```rux pub const Bits: uint = 8; ``` The number of bits in the representation. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Uint8.rux#L10){rel=""nofollow""} ### `Bytes` ```rux pub const Bytes: uint = 1; ``` The number of bytes in the representation. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Uint8.rux#L13){rel=""nofollow""} ### `Min` ```rux pub const Min: uint8 = 0; ``` The smallest representable value. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Uint8.rux#L16){rel=""nofollow""} ### `Max` ```rux pub const Max: uint8 = 255; ``` The largest representable value. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Uint8.rux#L19){rel=""nofollow""} ## `uint16` ```rux extend uint16 ``` An unsigned integer in 16 bits. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Uint16.rux#L7){rel=""nofollow""} **Constants** ### `Bits` ```rux pub const Bits: uint = 16; ``` The number of bits in the representation. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Uint16.rux#L10){rel=""nofollow""} ### `Bytes` ```rux pub const Bytes: uint = 2; ``` The number of bytes in the representation. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Uint16.rux#L13){rel=""nofollow""} ### `Min` ```rux pub const Min: uint16 = 0; ``` The smallest representable value. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Uint16.rux#L16){rel=""nofollow""} ### `Max` ```rux pub const Max: uint16 = 65535; ``` The largest representable value. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Uint16.rux#L19){rel=""nofollow""} ## `uint32` ```rux extend uint32 ``` An unsigned integer in 32 bits. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Uint32.rux#L7){rel=""nofollow""} **Constants** ### `Bits` ```rux pub const Bits: uint = 32; ``` The number of bits in the representation. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Uint32.rux#L10){rel=""nofollow""} ### `Bytes` ```rux pub const Bytes: uint = 4; ``` The number of bytes in the representation. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Uint32.rux#L13){rel=""nofollow""} ### `Min` ```rux pub const Min: uint32 = 0; ``` The smallest representable value. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Uint32.rux#L16){rel=""nofollow""} ### `Max` ```rux pub const Max: uint32 = 4294967295; ``` The largest representable value. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Uint32.rux#L19){rel=""nofollow""} ## `uint64` ```rux extend uint64 ``` An unsigned integer in 64 bits. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Uint64.rux#L7){rel=""nofollow""} **Constants** ### `Bits` ```rux pub const Bits: uint = 64; ``` The number of bits in the representation. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Uint64.rux#L10){rel=""nofollow""} ### `Bytes` ```rux pub const Bytes: uint = 8; ``` The number of bytes in the representation. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Uint64.rux#L13){rel=""nofollow""} ### `Min` ```rux pub const Min: uint64 = 0; ``` The smallest representable value. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Uint64.rux#L16){rel=""nofollow""} ### `Max` ```rux pub const Max: uint64 = 18446744073709551615; ``` The largest representable value. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Uint64.rux#L19){rel=""nofollow""} ## `uint128` ```rux extend uint128 ``` An unsigned integer in 128 bits. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Uint128.rux#L7){rel=""nofollow""} **Constants** ### `Bits` ```rux pub const Bits: uint = 128u; ``` The number of bits in the representation. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Uint128.rux#L10){rel=""nofollow""} ### `Bytes` ```rux pub const Bytes: uint = 16u; ``` The number of bytes in the representation. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Uint128.rux#L13){rel=""nofollow""} ### `Min` ```rux pub const Min: uint128 = 0u128; ``` The smallest representable value. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Uint128.rux#L16){rel=""nofollow""} ### `Max` ```rux pub const Max: uint128 = 340282366920938463463374607431768211455u128; ``` The largest representable value. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Uint128.rux#L19){rel=""nofollow""} ## `uint256` ```rux extend uint256 ``` An unsigned integer in 256 bits. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Uint256.rux#L7){rel=""nofollow""} **Constants** ### `Bits` ```rux pub const Bits: uint = 256u; ``` The number of bits in the representation. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Uint256.rux#L10){rel=""nofollow""} ### `Bytes` ```rux pub const Bytes: uint = 32u; ``` The number of bytes in the representation. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Uint256.rux#L13){rel=""nofollow""} ### `Min` ```rux pub const Min: uint256 = 0u256; ``` The smallest representable value. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Uint256.rux#L16){rel=""nofollow""} ### `Max` ```rux pub const Max: uint256 = 115792089237316195423570985008687907853269984665640564039457584007913129639935u256; ``` The largest representable value. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Uint256.rux#L19){rel=""nofollow""} ## `uint512` ```rux extend uint512 ``` An unsigned integer in 512 bits. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Uint512.rux#L7){rel=""nofollow""} **Constants** ### `Bits` ```rux pub const Bits: uint = 512u; ``` The number of bits in the representation. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Uint512.rux#L10){rel=""nofollow""} ### `Bytes` ```rux pub const Bytes: uint = 64u; ``` The number of bytes in the representation. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Uint512.rux#L13){rel=""nofollow""} ### `Min` ```rux pub const Min: uint512 = 0u512; ``` The smallest representable value. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Uint512.rux#L16){rel=""nofollow""} ### `Max` ```rux pub const Max: uint512 = …; ``` The largest representable value. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Primitives/Uint512.rux#L19){rel=""nofollow""} # Ordering The answer a three-way comparison gives: which side is smaller, or that neither is. ```rux pub enum Ordering: int8 { Less = -1, Equal = 0, Greater = 1 } ``` The discriminants are `-1`, `0` and `1` stored in an [`int8`](https://rux-lang.dev/docs/api/core/integers#int8), so an ordering costs one byte and its sign is the comparison's sign. A comparison that cannot decide has no representation here: every pair a comparison is asked about must land on exactly one of these three. `Ordering` is a `Copy` value, so reading one never consumes it. ## Cases | Name | Value | Description | | --------- | ----- | -------------------------------------------- | | `Less` | `-1` | The left value comes before the right one. | | `Equal` | `0` | Neither comes first; the two order the same. | | `Greater` | `1` | The left value comes after the right one. | ## Methods ### `IsLess` ```rux pub func IsLess(self: &Ordering) -> bool ``` Reports whether the left side of the comparison was the smaller one. Borrows the ordering through `self` and leaves it untouched. Cannot fail. Runs in constant time and allocates nothing. **Returns**: whether this ordering is `Less` [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Ordering.rux#L26){rel=""nofollow""} ### `IsEqual` ```rux pub func IsEqual(self: &Ordering) -> bool ``` Reports whether the two sides compared equal. Borrows the ordering through `self` and leaves it untouched. Cannot fail. Runs in constant time and allocates nothing. **Returns**: whether this ordering is `Equal` [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Ordering.rux#L38){rel=""nofollow""} ### `IsGreater` ```rux pub func IsGreater(self: &Ordering) -> bool ``` Reports whether the left side of the comparison was the larger one. Borrows the ordering through `self` and leaves it untouched. Cannot fail. Runs in constant time and allocates nothing. **Returns**: whether this ordering is `Greater` [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Ordering.rux#L50){rel=""nofollow""} ### `IsLessOrEqual` ```rux pub func IsLessOrEqual(self: &Ordering) -> bool ``` Reports whether the left side was smaller than or equal to the right. Borrows the ordering through `self` and leaves it untouched. This is the negation of [`IsGreater`](https://rux-lang.dev/docs/api/core/ordering#is-greater), spelled out so a caller testing a bound does not have to negate one. Cannot fail. Runs in constant time and allocates nothing. **Returns**: whether this ordering is `Less` or `Equal` [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Ordering.rux#L63){rel=""nofollow""} ### `IsGreaterOrEqual` ```rux pub func IsGreaterOrEqual(self: &Ordering) -> bool ``` Reports whether the left side was larger than or equal to the right. Borrows the ordering through `self` and leaves it untouched. This is the negation of [`IsLess`](https://rux-lang.dev/docs/api/core/ordering#is-less). Cannot fail. Runs in constant time and allocates nothing. **Returns**: whether this ordering is `Greater` or `Equal` [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Ordering.rux#L75){rel=""nofollow""} ### `Reverse` ```rux pub func Reverse(self: Ordering) -> Ordering ``` The ordering the same comparison would have given with its two sides swapped. Consumes the ordering by value and returns a new one; `Less` and `Greater` trade places while `Equal` is its own reverse. A `Copy` value, so the caller's own ordering is unaffected. Cannot fail. Runs in constant time and allocates nothing. **Returns**: the opposite ordering, with `Equal` unchanged [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Ordering.rux#L88){rel=""nofollow""} # SemanticVersion A semantic version, as its three numeric core components. ```rux pub struct SemanticVersion { pub major: uint; pub minor: uint; pub patch: uint; } ``` Carries the core only: a pre-release tag or build metadata is not represented, so two versions differing only in those compare equal. Copy, owns nothing, and allocates nothing. Ordered by precedence, major component first, as semantic versioning defines it. ## Fields | Name | Type | Description | | ------- | ------ | ----------------------------------------------------------- | | `major` | `uint` | The major component, which changes when compatibility does. | | `minor` | `uint` | The minor component. | | `patch` | `uint` | The patch component. | ## Constructors ### `SemanticVersion` ```rux pub func SemanticVersion( major: uint, minor: uint, patch: uint ) -> SemanticVersion ``` Constructs a version with the given components. All three are read by value; the version is returned by copy and borrows nothing. Cannot fail: every triple of components is a version. Runs in constant time and allocates nothing. | Name | Type | Description | | ------- | ------ | ----------------- | | `major` | `uint` | the major version | | `minor` | `uint` | the minor version | | `patch` | `uint` | the patch version | **Returns**: the version [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Compiler.rux#L29){rel=""nofollow""} ## Methods ### `Compare` ```rux pub func Compare( self: &SemanticVersion, other: SemanticVersion ) -> int ``` Compares precedence with `other`. `self` is borrowed and `other` is read by value. Returns a negative value when `self` precedes `other`, zero when the two have the same precedence, and a positive value when `self` follows it. Components are compared major first, and the first difference decides. Cannot fail. Runs in constant time and allocates nothing. | Name | Type | Description | | ------- | ----------------- | ---------------------------- | | `other` | `SemanticVersion` | the value to compare against | **Returns**: how this value orders against `other` [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Compiler.rux#L41){rel=""nofollow""} ### `IsEqualTo` ```rux pub func IsEqualTo( self: &SemanticVersion, other: SemanticVersion ) -> bool ``` Whether the two versions have the same precedence. `self` is borrowed and `other` is read by value. Cannot fail. Runs in constant time and allocates nothing. | Name | Type | Description | | ------- | ----------------- | ---------------------------- | | `other` | `SemanticVersion` | the value to compare against | **Returns**: whether the two versions are the same [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Compiler.rux#L56){rel=""nofollow""} ### `IsLessThan` ```rux pub func IsLessThan( self: &SemanticVersion, other: SemanticVersion ) -> bool ``` Whether this version precedes `other`. `self` is borrowed and `other` is read by value. Cannot fail. Runs in constant time and allocates nothing. | Name | Type | Description | | ------- | ----------------- | ---------------------------- | | `other` | `SemanticVersion` | the value to compare against | **Returns**: whether this version is older [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Compiler.rux#L65){rel=""nofollow""} ### `IsAtMost` ```rux pub func IsAtMost( self: &SemanticVersion, other: SemanticVersion ) -> bool ``` Whether this version precedes `other` or matches it. `self` is borrowed and `other` is read by value. Cannot fail. Runs in constant time and allocates nothing. | Name | Type | Description | | ------- | ----------------- | ---------------------------- | | `other` | `SemanticVersion` | the value to compare against | **Returns**: whether this version is the same or older [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Compiler.rux#L74){rel=""nofollow""} ### `IsGreaterThan` ```rux pub func IsGreaterThan( self: &SemanticVersion, other: SemanticVersion ) -> bool ``` Whether this version follows `other`. `self` is borrowed and `other` is read by value. Cannot fail. Runs in constant time and allocates nothing. | Name | Type | Description | | ------- | ----------------- | ---------------------------- | | `other` | `SemanticVersion` | the value to compare against | **Returns**: whether this version is newer [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Compiler.rux#L83){rel=""nofollow""} ### `IsAtLeast` ```rux pub func IsAtLeast( self: &SemanticVersion, other: SemanticVersion ) -> bool ``` Whether this version follows `other` or matches it, which is how a minimum requirement is written. `self` is borrowed and `other` is read by value. Cannot fail. Runs in constant time and allocates nothing. | Name | Type | Description | | ------- | ----------------- | ---------------------------- | | `other` | `SemanticVersion` | the value to compare against | **Returns**: whether this version is the same or newer [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Compiler.rux#L92){rel=""nofollow""} ## Operators ### `==` ```rux pub func ==( self: &SemanticVersion, other: SemanticVersion ) -> bool ``` Equality by precedence, the operator spelling of [`IsEqualTo`](https://rux-lang.dev/docs/api/core/semantic-version#is-equal-to). Cannot fail. Runs in constant time and allocates nothing. | Name | Type | Description | | ------- | ----------------- | ---------------------------- | | `other` | `SemanticVersion` | the value to compare against | **Returns**: whether the two are equal [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Compiler.rux#L101){rel=""nofollow""} ### `!=` ```rux pub func !=( self: &SemanticVersion, other: SemanticVersion ) -> bool ``` Inequality by precedence. Cannot fail. Runs in constant time and allocates nothing. | Name | Type | Description | | ------- | ----------------- | ---------------------------- | | `other` | `SemanticVersion` | the value to compare against | **Returns**: whether the two differ [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Compiler.rux#L110){rel=""nofollow""} ### `<` ```rux pub func <(self: &SemanticVersion, other: SemanticVersion) -> bool ``` Precedence ordering, the operator spelling of [`IsLessThan`](https://rux-lang.dev/docs/api/core/semantic-version#is-less-than). Cannot fail. Runs in constant time and allocates nothing. | Name | Type | Description | | ------- | ----------------- | ---------------------------- | | `other` | `SemanticVersion` | the value to compare against | **Returns**: whether this one is less [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Compiler.rux#L119){rel=""nofollow""} ### `<=` ```rux pub func <=(self: &SemanticVersion, other: SemanticVersion) -> bool ``` Precedence ordering, the operator spelling of [`IsAtMost`](https://rux-lang.dev/docs/api/core/semantic-version#is-at-most). Cannot fail. Runs in constant time and allocates nothing. | Name | Type | Description | | ------- | ----------------- | ---------------------------- | | `other` | `SemanticVersion` | the value to compare against | **Returns**: whether this one is less or equal [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Compiler.rux#L128){rel=""nofollow""} ### `>` ```rux pub func >(self: &SemanticVersion, other: SemanticVersion) -> bool ``` Precedence ordering, the operator spelling of [`IsGreaterThan`](https://rux-lang.dev/docs/api/core/semantic-version#is-greater-than). Cannot fail. Runs in constant time and allocates nothing. | Name | Type | Description | | ------- | ----------------- | ---------------------------- | | `other` | `SemanticVersion` | the value to compare against | **Returns**: whether this one is greater [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Compiler.rux#L137){rel=""nofollow""} ### `>=` ```rux pub func >=(self: &SemanticVersion, other: SemanticVersion) -> bool ``` Precedence ordering, the operator spelling of [`IsAtLeast`](https://rux-lang.dev/docs/api/core/semantic-version#is-at-least). Cannot fail. Runs in constant time and allocates nothing. | Name | Type | Description | | ------- | ----------------- | ---------------------------- | | `other` | `SemanticVersion` | the value to compare against | **Returns**: whether this one is greater or equal [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Compiler.rux#L146){rel=""nofollow""} # Source The location of the expression that reads it. ```rux pub struct Source { pub line: uint; pub column: uint; pub file: char8[..]; pub fileName: char8[..]; pub filePath: char8[..]; pub function: char8[..]; pub module: char8[..]; } ``` Every field is fixed while compiling, from the read's own position. A field read produces no runtime code beyond the constant it folds to; the text fields borrow the compiler's own storage, which outlives the program. ## Fields | Name | Type | Description | | ---------- | ----------- | ------------------------------------------------------------------------------- | | `line` | `uint` | The one-based line of the reading expression. | | `column` | `uint` | The one-based column of the reading expression. | | `file` | `char8[..]` | The source file as the build named it, which is the spelling a diagnostic uses. | | `fileName` | `char8[..]` | The file's last path component, with its extension. | | `filePath` | `char8[..]` | The file's path, relative to the package root where the file belongs to one. | | `function` | `char8[..]` | The enclosing function, qualified with its type for a method. | | `module` | `char8[..]` | The enclosing module path, relative to the package root. | ## Related ### `#source` ```rux pub const #source: Source; ``` The reading expression's own location, as a compile-time value. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Source.rux#L29){rel=""nofollow""} # Target Properties of the machine the build targets. ```rux pub struct Target { pub os: OperatingSystem; pub arch: Architecture; pub abi: ApplicationBinaryInterface; pub endian: Endianness; pub pointerBits: uint; pub dataModel: DataModel; pub objectFormat: ObjectFormat; pub triple: char8[..]; } ``` Every field is fixed when compiling begins. Reading one produces no runtime code, so a branch on a field is decided while compiling and the untaken side is not emitted. ## Fields | Name | Type | Description | | -------------- | ---------------------------- | ----------------------------------------------------------------------------------- | | `os` | `OperatingSystem` | The operating system. | | `arch` | `Architecture` | The processor architecture. | | `abi` | `ApplicationBinaryInterface` | The calling and layout conventions the target's code follows. | | `endian` | `Endianness` | The order the target stores a multi-byte value's bytes in. | | `pointerBits` | `uint` | How many bits a pointer occupies. | | `dataModel` | `DataModel` | The widths the target's C environment assigns to `long` and to a pointer. | | `objectFormat` | `ObjectFormat` | The object-file format compiled code is emitted in. | | `triple` | `char8[..]` | The canonical target name, spelled `<os>-<arch>`, which is what `--target` accepts. | ## Methods ### `HasFeature` ```rux pub func HasFeature( self: &Target, feature: TargetFeature ) -> bool ``` Whether the build enables `feature` on this target. `self` is borrowed and `feature` is read by value. Answered while compiling, so a branch on it emits only the side that applies and a body using an instruction the feature provides is never emitted without it. Cannot fail: a feature the target does not have is absent rather than an error. Costs nothing in the built program. | Name | Type | Description | | --------- | --------------- | ------------------------------- | | `feature` | `TargetFeature` | the target feature to ask about | **Returns**: whether the target being built for has it [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Target.rux#L145){rel=""nofollow""} ## Related ### `OperatingSystem` ```rux pub enum OperatingSystem: uint8 { Unknown = 0, FreeBSD = 1, Linux = 2, macOS = 3, Windows = 4 } ``` An operating system a build can target. Named per system rather than per family, so a package can tell FreeBSD from Linux where their interfaces differ. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Target.rux#L12){rel=""nofollow""} **Cases** | Name | Value | Description | | --------- | ----- | --------------------------------------------------------------------------- | | `Unknown` | `0` | A target the compiler has no name for, which no supported build produces. | | `FreeBSD` | `1` | FreeBSD. Told apart from the other BSDs, which this enumeration also names. | | `Linux` | `2` | Linux, any distribution. | | `macOS` | `3` | Apple macOS. | | `Windows` | `4` | Microsoft Windows. | ### `Architecture` ```rux pub enum Architecture: uint8 { Unknown = 0, AArch64 = 1, X86_64 = 2 } ``` A processor architecture a build can target. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Target.rux#L28){rel=""nofollow""} **Cases** | Name | Value | Description | | --------- | ----- | -------------------------------------------------------------------------------- | | `Unknown` | `0` | An architecture the compiler has no name for, which no supported build produces. | | `AArch64` | `1` | The 64-bit Arm architecture. | | `X86_64` | `2` | The 64-bit x86 architecture. | ### `ApplicationBinaryInterface` ```rux pub enum ApplicationBinaryInterface: uint8 { Unknown = 0, AAPCS64 = 1, SystemV = 2, WindowsX64 = 3 } ``` The calling and layout conventions a target's code follows. This is what decides how arguments are passed and how aggregates are laid out, so a declaration that has to match a foreign interface branches on it rather than on the operating system. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Target.rux#L41){rel=""nofollow""} **Cases** | Name | Value | Description | | ------------ | ----- | ----------------------------------------------------------------------- | | `Unknown` | `0` | An ABI the compiler has no name for, which no supported build produces. | | `AAPCS64` | `1` | The AArch64 procedure call standard. | | `SystemV` | `2` | The System V AMD64 ABI, used by Linux, FreeBSD, and macOS on x86-64. | | `WindowsX64` | `3` | The Windows x64 calling convention. | ### `TargetFeature` ```rux pub enum TargetFeature: uint8 { AVX = 0, AVX2 = 1, AVX512 = 2, NEON = 3, SSE2 = 4, SSE3 = 5, SSE41 = 6, SSE42 = 7, SSSE3 = 8, SVE = 9 } ``` A processor feature a target may be built with. Presence is asked about with [`Target::HasFeature`](https://rux-lang.dev/docs/api/core/target#has-feature) rather than read as a field, because a build enables a set rather than a single one. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Target.rux#L56){rel=""nofollow""} **Cases** | Name | Value | Description | | -------- | ----- | --------------------------------------------- | | `AVX` | `0` | x86 Advanced Vector Extensions. | | `AVX2` | `1` | x86 Advanced Vector Extensions 2. | | `AVX512` | `2` | x86 Advanced Vector Extensions 512. | | `NEON` | `3` | Arm Advanced SIMD. | | `SSE2` | `4` | x86 Streaming SIMD Extensions 2. | | `SSE3` | `5` | x86 Streaming SIMD Extensions 3. | | `SSE41` | `6` | x86 Streaming SIMD Extensions 4.1. | | `SSE42` | `7` | x86 Streaming SIMD Extensions 4.2. | | `SSSE3` | `8` | x86 Supplemental Streaming SIMD Extensions 3. | | `SVE` | `9` | Arm Scalable Vector Extension. | ### `Endianness` ```rux pub enum Endianness: uint8 { Big = 0, Little = 1 } ``` The order a target stores a multi-byte value's bytes in. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Target.rux#L81){rel=""nofollow""} **Cases** | Name | Value | Description | | -------- | ----- | -------------------------------------------------------------------------- | | `Big` | `0` | Most significant byte first, which is network byte order. | | `Little` | `1` | Least significant byte first, which every currently supported target uses. | ### `DataModel` ```rux pub enum DataModel: uint8 { Unknown = 0, LLP64 = 1, LP64 = 2 } ``` The widths a target's C environment assigns to `long` and to a pointer. This is what a raw C declaration needs to get `long` right, since the two models disagree about it. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Target.rux#L91){rel=""nofollow""} **Cases** | Name | Value | Description | | --------- | ----- | ------------------------------------------------------------------------ | | `Unknown` | `0` | A model the compiler has no name for, which no supported build produces. | | `LLP64` | `1` | 32-bit `long`, 64-bit pointer. Windows. | | `LP64` | `2` | 64-bit `long`, 64-bit pointer. Every supported Unix target. | ### `ObjectFormat` ```rux pub enum ObjectFormat: uint8 { Unknown = 0, COFF = 1, ELF = 2, MachO = 3 } ``` The object-file format a target's compiled code is emitted in. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Target.rux#L102){rel=""nofollow""} **Cases** | Name | Value | Description | | --------- | ----- | ------------------------------------------------------------------------- | | `Unknown` | `0` | A format the compiler has no name for, which no supported build produces. | | `COFF` | `1` | The format Windows links, carried in a PE image. | | `ELF` | `2` | The format Linux and FreeBSD link. | | `MachO` | `3` | The format macOS links. | ### `#target` ```rux pub const #target: Target; ``` The machine being compiled for, as a compile-time value. Reading a field produces no runtime code. A `when` on one keeps only the branch that applies, so the untaken side is never resolved or type-checked and may name declarations this target does not have. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Target.rux#L152){rel=""nofollow""} # Integer arithmetic Checked, wrapping and saturating arithmetic at every integer width, the limits of an integer type, and the [`uint64`](https://rux-lang.dev/docs/api/core/integers#uint64) intrinsics allocation sizes are computed with. ## `MaximumOf<T>` ```rux pub func MaximumOf<T>(sample: T) -> T ``` The largest value the integer type of `sample` can hold. `sample` is read by value and only its type matters; its value is never used. Returns the maximum by copy. Cannot fail. Runs in constant time and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Arithmetic.rux#L24){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | -------------------------------------------------------------- | | `T` | the integer or floating-point type, deduced from the arguments | **Parameters** | Name | Type | Description | | -------- | ---- | --------------------------------------------- | | `sample` | `T` | any value of the type, read only to deduce it | **Returns**: the largest value the type can hold ## `MinimumOf<T>` ```rux pub func MinimumOf<T>(sample: T) -> T ``` The smallest value the integer type of `sample` can hold. `sample` is read by value and only its type matters. Returns the minimum by copy: zero for an unsigned type, and the most negative value for a signed one. Cannot fail. Runs in constant time and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Arithmetic.rux#L41){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | -------------------------------------------------------------- | | `T` | the integer or floating-point type, deduced from the arguments | **Parameters** | Name | Type | Description | | -------- | ---- | --------------------------------------------- | | `sample` | `T` | any value of the type, read only to deduce it | **Returns**: the smallest value the type can hold ## `AddChecked<T>` ```rux pub func AddChecked<T>( left: T, right: T, result: *var T ) -> bool ``` Adds two integers and reports whether the true sum is representable. `left` and `right` are read by value. `result` receives the sum the machine produced, which is the true sum when this returns `false` and the wrapped one when it returns `true`; it is written in both cases, so a caller that wants the wrapped answer does not have to compute it again. `result` must not be null. Returns `true` when the sum overflowed. Never traps, so the caller decides what a sum too large to express means. Runs in constant time and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Arithmetic.rux#L61){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | -------------------------------------------------------------- | | `T` | the integer or floating-point type, deduced from the arguments | **Parameters** | Name | Type | Description | | -------- | -------- | --------------------------------------------------------------------- | | `left` | `T` | the left operand | | `right` | `T` | the right operand | | `result` | `*var T` | receives the answer the machine produced, true or wrapped; never null | **Returns**: true when the sum does not fit; `result` then holds the wrapped sum ## `SubChecked<T>` ```rux pub func SubChecked<T>( left: T, right: T, result: *var T ) -> bool ``` Subtracts one integer from another and reports whether the true difference is representable. `left` and `right` are read by value. `result` receives the difference the machine produced, true or wrapped, and is written in both cases. `result` must not be null. Returns `true` when the difference overflowed, which for an unsigned type means it was negative. Never traps. Runs in constant time and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Arithmetic.rux#L84){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | -------------------------------------------------------------- | | `T` | the integer or floating-point type, deduced from the arguments | **Parameters** | Name | Type | Description | | -------- | -------- | --------------------------------------------------------------------- | | `left` | `T` | the left operand | | `right` | `T` | the right operand | | `result` | `*var T` | receives the answer the machine produced, true or wrapped; never null | **Returns**: true when the difference does not fit; `result` then holds the wrapped difference ## `MulChecked<T>` ```rux pub func MulChecked<T>( left: T, right: T, result: *var T ) -> bool ``` Multiplies two integers and reports whether the true product is representable. `left` and `right` are read by value. `result` receives the product the machine produced, true or wrapped, and is written in both cases. `result` must not be null. Returns `true` when the product overflowed. This is the operation an allocation size is computed with: a wrapped product is an allocation far smaller than the caller asked for, so the report has to be read before the size is used. Never traps, including for the one signed pair whose quotient cannot be taken. Runs in constant time and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Arithmetic.rux#L110){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | -------------------------------------------------------------- | | `T` | the integer or floating-point type, deduced from the arguments | **Parameters** | Name | Type | Description | | -------- | -------- | --------------------------------------------------------------------- | | `left` | `T` | the left operand | | `right` | `T` | the right operand | | `result` | `*var T` | receives the answer the machine produced, true or wrapped; never null | **Returns**: true when the product does not fit; `result` then holds the wrapped product ## `AddWrapping<T>` ```rux pub func AddWrapping<T>(left: T, right: T) -> T ``` Adds two integers, wrapping around the type's range. `left` and `right` are read by value; the sum is returned by copy. This is what `+` already does, named so that wrapping on purpose reads differently from wrapping by accident. Cannot fail: every pair of operands has a wrapped sum. Runs in constant time and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Arithmetic.rux#L139){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | -------------------------------------------------------------- | | `T` | the integer or floating-point type, deduced from the arguments | **Parameters** | Name | Type | Description | | ------- | ---- | ----------------- | | `left` | `T` | the left operand | | `right` | `T` | the right operand | **Returns**: the sum, wrapped into the type's range ## `SubWrapping<T>` ```rux pub func SubWrapping<T>(left: T, right: T) -> T ``` Subtracts one integer from another, wrapping around the type's range. `left` and `right` are read by value; the difference is returned by copy. Cannot fail. Runs in constant time and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Arithmetic.rux#L151){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | -------------------------------------------------------------- | | `T` | the integer or floating-point type, deduced from the arguments | **Parameters** | Name | Type | Description | | ------- | ---- | ----------------- | | `left` | `T` | the left operand | | `right` | `T` | the right operand | **Returns**: the difference, wrapped into the type's range ## `MulWrapping<T>` ```rux pub func MulWrapping<T>(left: T, right: T) -> T ``` Multiplies two integers, wrapping around the type's range. `left` and `right` are read by value; the product is returned by copy. Cannot fail. Runs in constant time and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Arithmetic.rux#L163){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | -------------------------------------------------------------- | | `T` | the integer or floating-point type, deduced from the arguments | **Parameters** | Name | Type | Description | | ------- | ---- | ----------------- | | `left` | `T` | the left operand | | `right` | `T` | the right operand | **Returns**: the product, wrapped into the type's range ## `AddSaturating<T>` ```rux pub func AddSaturating<T>(left: T, right: T) -> T ``` Adds two integers, clamping to the type's range instead of wrapping. `left` and `right` are read by value; the sum is returned by copy. A sum too large becomes the maximum, and for a signed type a sum too small becomes the minimum. Cannot fail: the answer is always the nearest representable value to the true sum. Runs in constant time and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Arithmetic.rux#L177){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | -------------------------------------------------------------- | | `T` | the integer or floating-point type, deduced from the arguments | **Parameters** | Name | Type | Description | | ------- | ---- | ----------------- | | `left` | `T` | the left operand | | `right` | `T` | the right operand | **Returns**: the sum, clamped to the type's range rather than wrapped ## `SubSaturating<T>` ```rux pub func SubSaturating<T>(left: T, right: T) -> T ``` Subtracts one integer from another, clamping to the type's range instead of wrapping. `left` and `right` are read by value; the difference is returned by copy. For an unsigned type a negative difference becomes zero; for a signed one the difference clamps to whichever limit it ran past. Cannot fail. Runs in constant time and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Arithmetic.rux#L197){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | -------------------------------------------------------------- | | `T` | the integer or floating-point type, deduced from the arguments | **Parameters** | Name | Type | Description | | ------- | ---- | ----------------- | | `left` | `T` | the left operand | | `right` | `T` | the right operand | **Returns**: the difference, clamped to the type's range rather than wrapped ## `MulSaturating<T>` ```rux pub func MulSaturating<T>(left: T, right: T) -> T ``` Multiplies two integers, clamping to the type's range instead of wrapping. `left` and `right` are read by value; the product is returned by copy. A product too large becomes the maximum, and for a signed type a product too small becomes the minimum. Cannot fail. Runs in constant time and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Arithmetic.rux#L217){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | -------------------------------------------------------------- | | `T` | the integer or floating-point type, deduced from the arguments | **Parameters** | Name | Type | Description | | ------- | ---- | ----------------- | | `left` | `T` | the left operand | | `right` | `T` | the right operand | **Returns**: the product, clamped to the type's range rather than wrapped ## `CheckedAdd` ```rux pub func CheckedAdd( left: uint64, right: uint64, result: *var uint64 ) -> bool ``` Adds two unsigned 64-bit values and reports whether the true sum is representable. `left` and `right` are read by value. `result` receives the sum the machine produced, which is the true sum when this returns `false` and the wrapped one when it returns `true`; it is written in both cases. Returns `true` when the sum overflowed. The operation never traps, so the caller decides what a value too large to express becomes. Runs in constant time and allocates nothing. The compiler emits the arithmetic and the check where the call is written rather than calling out to a helper. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Checked.rux#L19){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | ------------- | --------------------------------------------------------- | | `left` | `uint64` | the left operand | | `right` | `uint64` | the right operand | | `result` | `*var uint64` | receives the answer the machine produced, true or wrapped | **Returns**: true when the sum does not fit; `result` then holds the wrapped sum ## `CheckedSub` ```rux pub func CheckedSub( left: uint64, right: uint64, result: *var uint64 ) -> bool ``` Subtracts one unsigned 64-bit value from another and reports whether the true difference is representable. `left` and `right` are read by value. `result` receives the difference the machine produced, which is the true one when this returns `false` and the wrapped one when it returns `true`; it is written in both cases. Returns `true` when the difference is negative and therefore not representable. The operation never traps. Runs in constant time and allocates nothing. The compiler emits the arithmetic and the check where the call is written rather than calling out to a helper. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Checked.rux#L32){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | ------------- | --------------------------------------------------------- | | `left` | `uint64` | the left operand | | `right` | `uint64` | the right operand | | `result` | `*var uint64` | receives the answer the machine produced, true or wrapped | **Returns**: true when the difference does not fit; `result` then holds the wrapped difference ## `CheckedMul` ```rux pub func CheckedMul( left: uint64, right: uint64, result: *var uint64 ) -> bool ``` Multiplies two unsigned 64-bit values and reports whether the true product is representable. `left` and `right` are read by value. `result` receives the product the machine produced, which is the true product when this returns `false` and the wrapped one when it returns `true`; it is written in both cases. Returns `true` when the product overflowed. This is the operation an allocation size is computed with: a wrapped product is an allocation far smaller than the caller asked for, so the report has to be checked before the size is used. Runs in constant time and allocates nothing. The compiler emits the arithmetic and the check where the call is written rather than calling out to a helper. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Checked.rux#L47){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | ------------- | --------------------------------------------------------- | | `left` | `uint64` | the left operand | | `right` | `uint64` | the right operand | | `result` | `*var uint64` | receives the answer the machine produced, true or wrapped | **Returns**: true when the product does not fit; `result` then holds the wrapped product # Atomic intrinsics The atomic loads, stores, exchanges and read-modify-write operations, memory orders and fences that the Atomic package builds on. ## `MemoryOrder` ```rux pub enum MemoryOrder: uint8 { Relaxed = 0, Acquire = 1, Release = 2, AcquireRelease = 3, SequentiallyConsistent = 4 } ``` Which other memory operations may be reordered across an atomic one. The weakest ordering that makes a program correct is also the fastest, and a stronger one is never wrong. When in doubt, `SequentiallyConsistent` gives every thread one agreed order of all such operations. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Atomic.rux#L15){rel=""nofollow""} **Cases** | Name | Value | Description | | ------------------------ | ----- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `Relaxed` | `0` | No ordering: the operation itself is atomic, and nothing around it is held back. Right for counters whose value no other memory depends on. | | `Acquire` | `1` | Later operations of this thread are not moved before this load, so whatever a releasing thread wrote before its release is visible after this acquire. For loads and the read half of read-modify-write operations. | | `Release` | `2` | Earlier operations of this thread are not moved after this store, so they are visible to a thread that acquires what it stores. For stores and the write half of read-modify-write operations. | | `AcquireRelease` | `3` | Both `Acquire` and `Release`, for a read-modify-write operation that does both. | | `SequentiallyConsistent` | `4` | `AcquireRelease`, and also a single order of every sequentially consistent operation that all threads agree on. | ## `AtomicLoad<T>` ```rux pub func AtomicLoad<T>(address: *T, order: MemoryOrder) -> T ``` Reads the value at `address` atomically. `order` must be `Relaxed`, `Acquire` or `SequentiallyConsistent`, written at the call. `address` must be aligned to the size of `T` and point at memory every thread that touches it reaches only through atomic operations. Runs in constant time and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Atomic.rux#L40){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | ------------------------------------------------ | | `T` | an integer of 8 to 64 bits, `bool`, or a pointer | **Parameters** | Name | Type | Description | | --------- | ------------- | ----------------------------------------------- | | `address` | `*T` | the value to read | | `order` | `MemoryOrder` | which other operations may move across this one | **Returns**: the value read ## `AtomicStore<T>` ```rux pub func AtomicStore<T>( address: *var T, value: T, order: MemoryOrder ) ``` Writes `value` to `address` atomically. `order` must be `Relaxed`, `Release` or `SequentiallyConsistent`, written at the call. `address` must be aligned to the size of `T`. Runs in constant time and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Atomic.rux#L50){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | ------------------------------------------------ | | `T` | an integer of 8 to 64 bits, `bool`, or a pointer | **Parameters** | Name | Type | Description | | --------- | ------------- | ----------------------------------------------- | | `address` | `*var T` | where to write | | `value` | `T` | what to write | | `order` | `MemoryOrder` | which other operations may move across this one | ## `AtomicExchange<T>` ```rux pub func AtomicExchange<T>( address: *var T, value: T, order: MemoryOrder ) -> T ``` Writes `value` to `address` and returns what was there, as one atomic step. Any ordering is allowed. `address` must be aligned to the size of `T`. Runs in constant time and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Atomic.rux#L60){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | ------------------------------------------------ | | `T` | an integer of 8 to 64 bits, `bool`, or a pointer | **Parameters** | Name | Type | Description | | --------- | ------------- | ----------------------------------------------- | | `address` | `*var T` | where to write | | `value` | `T` | what to write | | `order` | `MemoryOrder` | which other operations may move across this one | **Returns**: the value that was replaced ## `AtomicCompareExchange<T>` ```rux pub func AtomicCompareExchange<T>( address: *var T, expected: T, desired: T, success: MemoryOrder, failure: MemoryOrder ) -> T ``` Writes `desired` to `address` if it holds `expected`, and returns what it held, as one atomic step. The write happened exactly when the returned value equals `expected`. `success` orders the operation when it writes, and `failure` when it only reads; `failure` may not be `Release` or `AcquireRelease`, nor acquire more than `success` does. `address` must be aligned to the size of `T`. Never fails spuriously. Runs in constant time apart from contention and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Atomic.rux#L75){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | ------------------------------------------------ | | `T` | an integer of 8 to 64 bits, `bool`, or a pointer | **Parameters** | Name | Type | Description | | ---------- | ------------- | ----------------------------------------------------- | | `address` | `*var T` | the value to compare and replace | | `expected` | `T` | the value `address` must hold for the write to happen | | `desired` | `T` | the value to write | | `success` | `MemoryOrder` | the ordering when the write happens | | `failure` | `MemoryOrder` | the ordering when it does not | **Returns**: the value `address` held before the operation ## `AtomicFetchAdd<T>` ```rux pub func AtomicFetchAdd<T>( address: *var T, value: T, order: MemoryOrder ) -> T ``` Adds `value` to the integer at `address` and returns what was there, as one atomic step. The sum wraps on overflow, as two's complement arithmetic does. Any ordering is allowed. Runs in constant time apart from contention and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Atomic.rux#L87){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | -------------------------- | | `T` | an integer of 8 to 64 bits | **Parameters** | Name | Type | Description | | --------- | ------------- | ----------------------------------------------- | | `address` | `*var T` | the integer to add to | | `value` | `T` | what to add | | `order` | `MemoryOrder` | which other operations may move across this one | **Returns**: the value before the addition ## `AtomicFetchSub<T>` ```rux pub func AtomicFetchSub<T>( address: *var T, value: T, order: MemoryOrder ) -> T ``` Subtracts `value` from the integer at `address` and returns what was there, as one atomic step. The difference wraps on overflow. Any ordering is allowed. Runs in constant time apart from contention and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Atomic.rux#L98){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | -------------------------- | | `T` | an integer of 8 to 64 bits | **Parameters** | Name | Type | Description | | --------- | ------------- | ----------------------------------------------- | | `address` | `*var T` | the integer to subtract from | | `value` | `T` | what to subtract | | `order` | `MemoryOrder` | which other operations may move across this one | **Returns**: the value before the subtraction ## `AtomicFetchAnd<T>` ```rux pub func AtomicFetchAnd<T>( address: *var T, value: T, order: MemoryOrder ) -> T ``` Combines the value at `address` with `value` by bitwise and, and returns what was there, as one atomic step. Any ordering is allowed. Runs in constant time apart from contention and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Atomic.rux#L108){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | ------------------------------------- | | `T` | an integer of 8 to 64 bits, or `bool` | **Parameters** | Name | Type | Description | | --------- | ------------- | ----------------------------------------------- | | `address` | `*var T` | the value to combine | | `value` | `T` | the bits to keep | | `order` | `MemoryOrder` | which other operations may move across this one | **Returns**: the value before the operation ## `AtomicFetchOr<T>` ```rux pub func AtomicFetchOr<T>( address: *var T, value: T, order: MemoryOrder ) -> T ``` Combines the value at `address` with `value` by bitwise or, and returns what was there, as one atomic step. Any ordering is allowed. Runs in constant time apart from contention and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Atomic.rux#L118){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | ------------------------------------- | | `T` | an integer of 8 to 64 bits, or `bool` | **Parameters** | Name | Type | Description | | --------- | ------------- | ----------------------------------------------- | | `address` | `*var T` | the value to combine | | `value` | `T` | the bits to set | | `order` | `MemoryOrder` | which other operations may move across this one | **Returns**: the value before the operation ## `AtomicFetchXor<T>` ```rux pub func AtomicFetchXor<T>( address: *var T, value: T, order: MemoryOrder ) -> T ``` Combines the value at `address` with `value` by bitwise exclusive or, and returns what was there, as one atomic step. Any ordering is allowed. Runs in constant time apart from contention and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Atomic.rux#L129){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | ------------------------------------- | | `T` | an integer of 8 to 64 bits, or `bool` | **Parameters** | Name | Type | Description | | --------- | ------------- | ----------------------------------------------- | | `address` | `*var T` | the value to combine | | `value` | `T` | the bits to flip | | `order` | `MemoryOrder` | which other operations may move across this one | **Returns**: the value before the operation ## `Fence` ```rux pub func Fence(order: MemoryOrder) ``` Orders this thread's memory operations without touching memory. `order` must not be `Relaxed`, which would order nothing. An `Acquire` fence keeps later operations after earlier loads, a `Release` fence keeps earlier operations before later stores, and `SequentiallyConsistent` does both and takes part in the single order of sequentially consistent operations. Runs in constant time and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Atomic.rux#L137){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------- | ------------- | ------------------------- | | `order` | `MemoryOrder` | what the fence holds back | ## `SpinHint` ```rux pub func SpinHint() ``` Tells the processor that the thread is waiting in a loop for another thread. It saves power and lets a sibling hardware thread run, and has no effect on memory. A loop that waits long should sleep instead. Runs in constant time and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Atomic.rux#L143){rel=""nofollow""} # Bit operations Counting, rotating, reversing and testing the bits of an integer of any width, and a right shift that brings in zeros whatever the sign. ## `BitWidthOf<T>` ```rux pub func BitWidthOf<T>(sample: T) -> uint64 ``` The number of bits in the integer type of `sample`. `sample` is read by value and only its type matters; its value is never used. Returns the width by copy. Cannot fail. Runs in constant time and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Bits.rux#L19){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | -------------------------------------------------------------- | | `T` | the integer or floating-point type, deduced from the arguments | **Parameters** | Name | Type | Description | | -------- | ---- | --------------------------------------------- | | `sample` | `T` | any value of the type, read only to deduce it | **Returns**: how many bits the type occupies ## `ShiftRightLogical<T>` ```rux pub func ShiftRightLogical<T>(value: T, amount: uint64) -> T ``` Shifts an integer right, bringing zeros in at the top whatever its signedness. `value` and `amount` are read by value; the result is returned by copy. This is what `>>` does for an unsigned type and what it deliberately does not do for a signed one, where `>>` replicates the sign bit instead. An `amount` at or beyond the type's width yields zero rather than being left undefined. Cannot fail. Runs in constant time and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Bits.rux#L33){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | -------------------------------------------------------------- | | `T` | the integer or floating-point type, deduced from the arguments | **Parameters** | Name | Type | Description | | -------- | -------- | ------------------- | | `value` | `T` | the value to act on | | `amount` | `uint64` | how many bits | **Returns**: the value shifted right with zero bits shifted in, whatever its signedness ## `BitAt<T>` ```rux pub func BitAt<T>(value: T, index: uint64) -> bool ``` Whether the bit at `index` is set, counting from the least significant bit. `value` and `index` are read by value. An `index` at or beyond the type's width reads no bit and reports `false`. Cannot fail. Runs in constant time and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Bits.rux#L53){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | -------------------------------------------------------------- | | `T` | the integer or floating-point type, deduced from the arguments | **Parameters** | Name | Type | Description | | ------- | -------- | ---------------------------------------------- | | `value` | `T` | the value to act on | | `index` | `uint64` | which bit, counting from the least significant | **Returns**: whether the bit at `index` is set ## `CountOnes<T>` ```rux pub func CountOnes<T>(value: T) -> uint32 ``` The number of set bits. `value` is read by value. Returns a count between zero and the type's width. Cannot fail. Runs in time linear in the type's width and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Bits.rux#L67){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | -------------------------------------------------------------- | | `T` | the integer or floating-point type, deduced from the arguments | **Parameters** | Name | Type | Description | | ------- | ---- | ------------------- | | `value` | `T` | the value to act on | **Returns**: how many bits are set ## `CountZeros<T>` ```rux pub func CountZeros<T>(value: T) -> uint32 ``` The number of clear bits. `value` is read by value. Returns a count between zero and the type's width: the exact complement of [`CountOnes`](https://rux-lang.dev/docs/api/core/bits#count-ones). Cannot fail. Runs in time linear in the type's width and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Bits.rux#L87){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | -------------------------------------------------------------- | | `T` | the integer or floating-point type, deduced from the arguments | **Parameters** | Name | Type | Description | | ------- | ---- | ------------------- | | `value` | `T` | the value to act on | **Returns**: how many bits are clear ## `LeadingZeros<T>` ```rux pub func LeadingZeros<T>(value: T) -> uint32 ``` The number of clear bits above the highest set bit. `value` is read by value. A zero value has no set bit, so every bit counts and the answer is the type's width. Cannot fail. Runs in time linear in the type's width and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Bits.rux#L98){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | -------------------------------------------------------------- | | `T` | the integer or floating-point type, deduced from the arguments | **Parameters** | Name | Type | Description | | ------- | ---- | ------------------- | | `value` | `T` | the value to act on | **Returns**: how many clear bits precede the most significant set one ## `TrailingZeros<T>` ```rux pub func TrailingZeros<T>(value: T) -> uint32 ``` The number of clear bits below the lowest set bit. `value` is read by value. A zero value has no set bit, so the answer is the type's width. Cannot fail. Runs in time linear in the type's width and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Bits.rux#L116){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | -------------------------------------------------------------- | | `T` | the integer or floating-point type, deduced from the arguments | **Parameters** | Name | Type | Description | | ------- | ---- | ------------------- | | `value` | `T` | the value to act on | **Returns**: how many clear bits follow the least significant set one ## `LeadingOnes<T>` ```rux pub func LeadingOnes<T>(value: T) -> uint32 ``` The number of set bits above the highest clear bit. `value` is read by value. An all-ones value has no clear bit, so the answer is the type's width. Cannot fail. Runs in time linear in the type's width and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Bits.rux#L133){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | -------------------------------------------------------------- | | `T` | the integer or floating-point type, deduced from the arguments | **Parameters** | Name | Type | Description | | ------- | ---- | ------------------- | | `value` | `T` | the value to act on | **Returns**: how many set bits precede the most significant clear one ## `TrailingOnes<T>` ```rux pub func TrailingOnes<T>(value: T) -> uint32 ``` The number of set bits below the lowest clear bit. `value` is read by value. An all-ones value has no clear bit, so the answer is the type's width. Cannot fail. Runs in time linear in the type's width and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Bits.rux#L151){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | -------------------------------------------------------------- | | `T` | the integer or floating-point type, deduced from the arguments | **Parameters** | Name | Type | Description | | ------- | ---- | ------------------- | | `value` | `T` | the value to act on | **Returns**: how many set bits follow the least significant clear one ## `RotateLeft<T>` ```rux pub func RotateLeft<T>(value: T, amount: uint64) -> T ``` Rotates an integer's bits toward the most significant end, wrapping the ones that run off. `value` and `amount` are read by value; the result is returned by copy. `amount` is taken modulo the type's width, so no rotation is out of range and rotating by the width is the identity. Cannot fail: no bit is lost, unlike a shift. Runs in constant time and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Bits.rux#L170){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | -------------------------------------------------------------- | | `T` | the integer or floating-point type, deduced from the arguments | **Parameters** | Name | Type | Description | | -------- | -------- | ------------------- | | `value` | `T` | the value to act on | | `amount` | `uint64` | how many bits | **Returns**: the value rotated left, with the bits that leave the top re-entering at the bottom ## `RotateRight<T>` ```rux pub func RotateRight<T>(value: T, amount: uint64) -> T ``` Rotates an integer's bits toward the least significant end, wrapping the ones that run off. `value` and `amount` are read by value; the result is returned by copy. `amount` is taken modulo the type's width. Cannot fail. Runs in constant time and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Bits.rux#L186){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | -------------------------------------------------------------- | | `T` | the integer or floating-point type, deduced from the arguments | **Parameters** | Name | Type | Description | | -------- | -------- | ------------------- | | `value` | `T` | the value to act on | | `amount` | `uint64` | how many bits | **Returns**: the value rotated right, with the bits that leave the bottom re-entering at the top ## `ReverseBits<T>` ```rux pub func ReverseBits<T>(value: T) -> T ``` The value with its bits in the opposite order: bit zero becomes the highest bit and back again. `value` is read by value; the result is returned by copy. Cannot fail. Runs in time linear in the type's width and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Bits.rux#L200){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | -------------------------------------------------------------- | | `T` | the integer or floating-point type, deduced from the arguments | **Parameters** | Name | Type | Description | | ------- | ---- | ------------------- | | `value` | `T` | the value to act on | **Returns**: the value with its bit order reversed ## `ReverseBytes<T>` ```rux pub func ReverseBytes<T>(value: T) -> T ``` The value with its bytes in the opposite order, leaving the bits within each byte where they were. `value` is read by value; the result is returned by copy. This is the operation that turns a little-endian value into the big-endian one with the same bytes, and is what the endian conversions are built from. Cannot fail. Runs in time linear in the type's width and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Bits.rux#L223){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | -------------------------------------------------------------- | | `T` | the integer or floating-point type, deduced from the arguments | **Parameters** | Name | Type | Description | | ------- | ---- | ------------------- | | `value` | `T` | the value to act on | **Returns**: the value with its byte order reversed ## `IsPowerOfTwo<T>` ```rux pub func IsPowerOfTwo<T>(value: T) -> bool ``` Whether the value has exactly one bit set. `value` is read by value. Zero has no bit set and is not a power of two; for a signed type the most negative value has exactly one bit set and is reported as one, because this asks about bits rather than about magnitude. Cannot fail. Runs in time linear in the type's width and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Bits.rux#L249){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | -------------------------------------------------------------- | | `T` | the integer or floating-point type, deduced from the arguments | **Parameters** | Name | Type | Description | | ------- | ---- | ------------------- | | `value` | `T` | the value to act on | **Returns**: whether exactly one bit is set; false for zero # Byte order Converting integers between the target's byte order and little- or big-endian, in a register or through raw bytes at any alignment. ## `TargetIsLittleEndian` ```rux pub func TargetIsLittleEndian() -> bool ``` Whether this target stores an integer's least significant byte first. Takes nothing and returns the answer by copy. It is established by writing a value whose bytes differ and reading back the first one, so it is right on any target rather than on a list of known ones. Cannot fail. Runs in constant time and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Endian.rux#L17){rel=""nofollow""} **Returns**: whether the target stores the least significant byte first ## `ToLittleEndian<T>` ```rux pub func ToLittleEndian<T>(value: T) -> T ``` The value's bytes as a little-endian value would hold them. `value` is read by value; the result is returned by copy. On a little-endian target this is the identity; on a big-endian one it is a byte reversal. The result is a bit pattern to be stored, not a number to compute with. Cannot fail. Costs nothing on a little-endian target and one byte reversal on a big-endian one, so it runs in time linear in the type's width at worst and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Endian.rux#L32){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | -------------------------------------------------------------- | | `T` | the integer or floating-point type, deduced from the arguments | **Parameters** | Name | Type | Description | | ------- | ---- | ------------------- | | `value` | `T` | the value to act on | **Returns**: the value with its bytes in little-endian order ## `FromLittleEndian<T>` ```rux pub func FromLittleEndian<T>(value: T) -> T ``` The value a little-endian bit pattern stands for on this target. `value` is read by value; the result is returned by copy. The exact inverse of [`ToLittleEndian`](https://rux-lang.dev/docs/api/core/byte-order#to-little-endian), and the same operation — a byte reversal is its own inverse. Cannot fail. Costs exactly what [`ToLittleEndian`](https://rux-lang.dev/docs/api/core/byte-order#to-little-endian) costs and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Endian.rux#L44){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | -------------------------------------------------------------- | | `T` | the integer or floating-point type, deduced from the arguments | **Parameters** | Name | Type | Description | | ------- | ---- | ------------------- | | `value` | `T` | the value to act on | **Returns**: the value read from little-endian bytes, in the target's own order ## `ToBigEndian<T>` ```rux pub func ToBigEndian<T>(value: T) -> T ``` The value's bytes as a big-endian value would hold them. `value` is read by value; the result is returned by copy. On a big-endian target this is the identity; on a little-endian one it is a byte reversal. This is network byte order. Cannot fail. Costs nothing on a big-endian target and one byte reversal on a little-endian one, so it runs in time linear in the type's width at worst and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Endian.rux#L57){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | -------------------------------------------------------------- | | `T` | the integer or floating-point type, deduced from the arguments | **Parameters** | Name | Type | Description | | ------- | ---- | ------------------- | | `value` | `T` | the value to act on | **Returns**: the value with its bytes in big-endian order ## `FromBigEndian<T>` ```rux pub func FromBigEndian<T>(value: T) -> T ``` The value a big-endian bit pattern stands for on this target. `value` is read by value; the result is returned by copy. The exact inverse of [`ToBigEndian`](https://rux-lang.dev/docs/api/core/byte-order#to-big-endian), and the same operation. Cannot fail. Costs exactly what [`ToBigEndian`](https://rux-lang.dev/docs/api/core/byte-order#to-big-endian) costs and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Endian.rux#L69){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | -------------------------------------------------------------- | | `T` | the integer or floating-point type, deduced from the arguments | **Parameters** | Name | Type | Description | | ------- | ---- | ------------------- | | `value` | `T` | the value to act on | **Returns**: the value read from big-endian bytes, in the target's own order ## `StoreLittleEndian<T>` ```rux pub func StoreLittleEndian<T>( value: T, destination: *var byte ) ``` Writes an integer to raw bytes, least significant byte first. `value` is read by value. `destination` is borrowed for the call and receives exactly `sizeof(T)` bytes; it is never read. The bytes need no alignment, so a value may be written straight into the middle of a buffer. Cannot fail: every value has a representation. Runs in time linear in the type's width and allocates nothing. `destination` must be non-null and must have room for `sizeof(T)` bytes. Neither is checked. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Endian.rux#L82){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | -------------------------------------------------------------- | | `T` | the integer or floating-point type, deduced from the arguments | **Parameters** | Name | Type | Description | | ------------- | ----------- | ------------------- | | `value` | `T` | the value to act on | | `destination` | `*var byte` | receives the bytes | ## `StoreBigEndian<T>` ```rux pub func StoreBigEndian<T>(value: T, destination: *var byte) ``` Writes an integer to raw bytes, most significant byte first. `value` is read by value. `destination` is borrowed for the call and receives exactly `sizeof(T)` bytes; it is never read. This is the order a network protocol asks for. Cannot fail. Runs in time linear in the type's width and allocates nothing. `destination` must be non-null and must have room for `sizeof(T)` bytes. Neither is checked. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Endian.rux#L103){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | -------------------------------------------------------------- | | `T` | the integer or floating-point type, deduced from the arguments | **Parameters** | Name | Type | Description | | ------------- | ----------- | ------------------- | | `value` | `T` | the value to act on | | `destination` | `*var byte` | receives the bytes | ## `LoadLittleEndian<T>` ```rux pub func LoadLittleEndian<T>( source: *byte, destination: *var T ) ``` Reads an integer from raw bytes holding it least significant byte first. `source` is borrowed for the call and `sizeof(T)` bytes are read from it. `destination` names the type being read and receives the value; whatever it held is overwritten. The bytes need no alignment. Cannot fail: every byte sequence of the right length is a value. Runs in time linear in the type's width and allocates nothing. `source` must be non-null and readable for `sizeof(T)` bytes, and `destination` must be non-null. Neither is checked. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Endian.rux#L124){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | -------------------------------------------------------------- | | `T` | the integer or floating-point type, deduced from the arguments | **Parameters** | Name | Type | Description | | ------------- | -------- | ------------------ | | `source` | `*byte` | the bytes to read | | `destination` | `*var T` | receives the bytes | ## `LoadBigEndian<T>` ```rux pub func LoadBigEndian<T>( source: *byte, destination: *var T ) ``` Reads an integer from raw bytes holding it most significant byte first. `source` is borrowed for the call and `sizeof(T)` bytes are read from it. `destination` names the type being read and receives the value; whatever it held is overwritten. Cannot fail. Runs in time linear in the type's width and allocates nothing. `source` must be non-null and readable for `sizeof(T)` bytes, and `destination` must be non-null. Neither is checked. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Endian.rux#L144){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | -------------------------------------------------------------- | | `T` | the integer or floating-point type, deduced from the arguments | **Parameters** | Name | Type | Description | | ------------- | -------- | ------------------ | | `source` | `*byte` | the bytes to read | | `destination` | `*var T` | receives the bytes | # Checked conversion Converting between primitive types with a report of whether the value survived, with wrapping on purpose, or clamped to the destination's range. ## `IsSignedType<T>` ```rux pub func IsSignedType<T>(sample: T) -> bool ``` Whether the integer type of `sample` has values below zero. `sample` is read by value and only its type matters; its value is never used. Returns the answer by copy. A type's own all-ones pattern is what answers this: read as a signed type it is `-1`, and read as an unsigned one it is the maximum. Nothing has to be told which it has. Cannot fail. Runs in constant time and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Convert.rux#L23){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | -------------------------------------------------------------- | | `T` | the integer or floating-point type, deduced from the arguments | **Parameters** | Name | Type | Description | | -------- | ---- | --------------------------------------------- | | `sample` | `T` | any value of the type, read only to deduce it | **Returns**: whether the type can hold a negative value ## `ConvertChecked<From, To>` ```rux pub func ConvertChecked<From, To>( value: From, result: *var To ) -> bool ``` Converts a primitive value to another primitive type and reports whether the true value was representable. `value` is read by value. `result` receives the conversion the machine produced, which is the true value when this returns `false` and the wrapped, truncated or rounded one when it returns `true`; it is written in both cases, so a caller who wants the lossy answer does not have to convert again. Returns `true` when the conversion lost the value: a magnitude too large for the destination, a negative value converted to an unsigned type, a value above the signed range converted to a signed type of the same width, a float with a fractional part converted to an integer, or a float narrowed past its precision. A NaN and an infinity are both reported, since neither survives a round trip. Runs in constant time and allocates nothing. Never traps, so the caller decides what a lost value means. `result` must be non-null. This is not checked. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Convert.rux#L44){rel=""nofollow""} **Type parameters** | Name | Description | | ------ | -------------------- | | `From` | the source type | | `To` | the destination type | **Parameters** | Name | Type | Description | | -------- | --------- | ------------------------------------------------------------------------ | | `value` | `From` | the value to act on | | `result` | `*var To` | receives the conversion the machine produced, exact or lossy; never null | **Returns**: true when the value does not fit the destination; `result` then holds the lossy conversion ## `ConvertWrapping<From, To>` ```rux pub func ConvertWrapping<From, To>( value: From, result: *var To ) ``` Converts a primitive value to another primitive type, keeping whatever fits. `value` is read by value; `result` receives the destination type's own answer, wrapping an integer around its range, truncating a float toward zero, and rounding a narrowed float. This is what `as` does, named so that discarding the rest on purpose reads differently from discarding it by accident. Cannot fail: every value has a wrapped conversion. Runs in constant time and allocates nothing. `result` must be non-null. This is not checked. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Convert.rux#L65){rel=""nofollow""} **Type parameters** | Name | Description | | ------ | -------------------- | | `From` | the source type | | `To` | the destination type | **Parameters** | Name | Type | Description | | -------- | --------- | ----------------------------------------------------------------- | | `value` | `From` | the value to act on | | `result` | `*var To` | receives the wrapped, truncated or rounded conversion; never null | ## `ConvertSaturating<From, To>` ```rux pub func ConvertSaturating<From, To>( value: From, result: *var To ) ``` Converts a primitive value to an integer type, clamping to that type's range instead of wrapping. `value` is read by value; `result` receives the nearest representable value: the destination's maximum for a value too large, its minimum for one too small, and the exact conversion for one that fits. A NaN has no nearest value and yields zero. `To` must be an integer type. A floating destination has no limits to clamp against and is not supported; use [`ConvertChecked`](https://rux-lang.dev/docs/api/core/conversion#convert-checked) and decide what to do with the report. Cannot fail: the answer is always the nearest representable value. Runs in constant time and allocates nothing. `result` must be non-null. This is not checked. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Convert.rux#L82){rel=""nofollow""} **Type parameters** | Name | Description | | ------ | -------------------- | | `From` | the source type | | `To` | the destination type | **Parameters** | Name | Type | Description | | -------- | --------- | ---------------------------------------------------- | | `value` | `From` | the value to act on | | `result` | `*var To` | receives the nearest representable value; never null | # Diagnostics Run-time assertions and panics that report and terminate, and the compile-time [`#Error`](https://rux-lang.dev/docs/api/core/diagnostics#error) and [`#Warn`](https://rux-lang.dev/docs/api/core/diagnostics#warn) that reject or flag a configuration. ## `Assert` ```rux pub func Assert(condition: bool, message: char8[..]) ``` Terminates the program unless `condition` holds. `condition` and `message` are read by value; nothing is returned and nothing is taken ownership of. `message` should say what was expected rather than what was found, since the value that failed is not printed. Reports the message, the enclosing function, and the file, line and column of the call, then terminates. Does not unwind: no destructor runs, and no caller observes the failure. Present in every build, so it is the right check for a contract that must hold in a released program. Runs in constant time and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Diagnostics.rux#L20){rel=""nofollow""} **Parameters** | Name | Type | Description | | ----------- | ----------- | ------------------------------- | | `condition` | `bool` | what must hold | | `message` | `char8[..]` | what to report when it does not | ## `DebugAssert` ```rux pub func DebugAssert(condition: bool, message: char8[..]) ``` Terminates the program unless `condition` holds, in builds that keep debug assertions. `condition` and `message` are read by value. Identical to [`Assert`](https://rux-lang.dev/docs/api/core/diagnostics#assert) where it is kept, and removed entirely where it is not: a release build does not evaluate `condition`, so an argument with a side effect will not have it, and an expensive check costs nothing. Reports and terminates exactly as [`Assert`](https://rux-lang.dev/docs/api/core/diagnostics#assert) does. Does not unwind. Runs in constant time and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Diagnostics.rux#L31){rel=""nofollow""} **Parameters** | Name | Type | Description | | ----------- | ----------- | ------------------------------- | | `condition` | `bool` | what must hold | | `message` | `char8[..]` | what to report when it does not | ## `Panic` ```rux pub func Panic(message: char8[..]) ``` Terminates the program, reporting `message`. `message` is read by value; this never returns. Use it where a case is unreachable by construction rather than unlikely — a caller who could have handled the failure should have been given a fallible `T ! E` instead. Reports the message, the enclosing function, and the file, line and column of the call, then terminates. Does not unwind: no destructor runs. Runs in constant time and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Diagnostics.rux#L41){rel=""nofollow""} **Parameters** | Name | Type | Description | | --------- | ----------- | --------------------------------- | | `message` | `char8[..]` | what to report before terminating | ## `#Error` ```rux pub func #Error(message: char8[..]) ``` Rejects the build where it is written, reporting `message`. `message` must be a string literal, since this is evaluated while compiling. Produces no runtime code and never returns a value. A directive inside a `when` branch that was not taken never fires. Cannot fail at run time, because it does not reach run time. Costs nothing in the built program. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Diagnostics.rux#L49){rel=""nofollow""} **Parameters** | Name | Type | Description | | --------- | ----------- | --------------------------------------- | | `message` | `char8[..]` | the diagnostic to emit at the call site | ## `#Warn` ```rux pub func #Warn(message: char8[..]) ``` Reports `message` as a compilation warning where it is written, without rejecting the build. `message` must be a string literal. Produces no runtime code. A directive inside a `when` branch that was not taken never fires, so a warning about one target does not appear when building for another. Cannot fail. Costs nothing in the built program. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Diagnostics.rux#L57){rel=""nofollow""} **Parameters** | Name | Type | Description | | --------- | ----------- | --------------------------------------- | | `message` | `char8[..]` | the diagnostic to emit at the call site | # Float classification Asking whether a floating-point value is NaN, infinite, finite or zero, and reading its sign, at every float width. ## `IsNaN<T>` ```rux pub func IsNaN<T>(value: T) -> bool ``` Whether the value is not a number. `value` is read by value. Returns `true` for every NaN, quiet or signaling, and `false` for everything else -- including both infinities, which are outside the finite range but are still ordered against it. Cannot fail. Runs in constant time and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Floating.rux#L21){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | -------------------------------------------------------------- | | `T` | the integer or floating-point type, deduced from the arguments | **Parameters** | Name | Type | Description | | ------- | ---- | ------------------- | | `value` | `T` | the value to act on | **Returns**: whether the value is a NaN, which no comparison can tell you ## `IsZero<T>` ```rux pub func IsZero<T>(value: T) -> bool ``` Whether the value is either zero. `value` is read by value. Both `+0.0` and `-0.0` report `true`, since the two compare equal; [`IsNegativeZero`](https://rux-lang.dev/docs/api/core/float-classification#is-negative-zero) separates them. A NaN and an infinity report `false`, because subtracting either from itself gives a NaN. Cannot fail. Runs in constant time and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Floating.rux#L33){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | -------------------------------------------------------------- | | `T` | the integer or floating-point type, deduced from the arguments | **Parameters** | Name | Type | Description | | ------- | ---- | ------------------- | | `value` | `T` | the value to act on | **Returns**: whether the value is either signed zero ## `IsInfinite<T>` ```rux pub func IsInfinite<T>(value: T) -> bool ``` Whether the value is an infinity, of either sign. `value` is read by value. A zero is excluded explicitly: it is the other value that doubles to itself. Cannot fail. Runs in constant time and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Floating.rux#L44){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | -------------------------------------------------------------- | | `T` | the integer or floating-point type, deduced from the arguments | **Parameters** | Name | Type | Description | | ------- | ---- | ------------------- | | `value` | `T` | the value to act on | **Returns**: whether the value is either infinity ## `IsFinite<T>` ```rux pub func IsFinite<T>(value: T) -> bool ``` Whether the value is an ordinary number: neither a NaN nor an infinity. `value` is read by value. Every zero and every subnormal is finite. Cannot fail. Runs in constant time and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Floating.rux#L55){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | -------------------------------------------------------------- | | `T` | the integer or floating-point type, deduced from the arguments | **Parameters** | Name | Type | Description | | ------- | ---- | ------------------- | | `value` | `T` | the value to act on | **Returns**: whether the value is neither infinite nor a NaN ## `IsNegativeZero<T>` ```rux pub func IsNegativeZero<T>(value: T) -> bool ``` Whether the value is the zero that carries a minus sign. `value` is read by value. `-0.0` reports `true` and `+0.0` reports `false`, though the two compare equal; every other value, NaN included, reports `false`. The sign of a zero is invisible to comparison, so it is read from the infinity the zero divides into: `1 / -0.0` is negative infinity and `1 / +0.0` is positive infinity. The division is exact and traps nothing, because dividing by zero is a defined floating-point operation rather than an error. Cannot fail. Runs in constant time and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Floating.rux#L70){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | -------------------------------------------------------------- | | `T` | the integer or floating-point type, deduced from the arguments | **Parameters** | Name | Type | Description | | ------- | ---- | ------------------- | | `value` | `T` | the value to act on | **Returns**: whether the value is negative zero specifically, which `== 0.0` cannot distinguish ## `IsSignNegative<T>` ```rux pub func IsSignNegative<T>(value: T) -> bool ``` Whether the value carries a minus sign. `value` is read by value. Every negative number reports `true`, and so does `-0.0` — which is why this is named for the sign rather than for the comparison: `-0.0 < 0` is false. A NaN reports `false` whichever sign its encoding carries, since a NaN is outside the ordering and its sign has no arithmetic meaning. Cannot fail. Runs in constant time and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Floating.rux#L83){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | -------------------------------------------------------------- | | `T` | the integer or floating-point type, deduced from the arguments | **Parameters** | Name | Type | Description | | ------- | ---- | ------------------- | | `value` | `T` | the value to act on | **Returns**: whether the sign bit is set, which it is for negative zero and for a negative NaN ## `IsSignPositive<T>` ```rux pub func IsSignPositive<T>(value: T) -> bool ``` Whether the value carries a plus sign. `value` is read by value. Every positive number reports `true`, and so does `+0.0`. A NaN reports `false`, so this is not the negation of [`IsSignNegative`](https://rux-lang.dev/docs/api/core/float-classification#is-sign-negative): a NaN carries neither sign for these purposes. Cannot fail. Runs in constant time and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Floating.rux#L95){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | -------------------------------------------------------------- | | `T` | the integer or floating-point type, deduced from the arguments | **Parameters** | Name | Type | Description | | ------- | ---- | ------------------- | | `value` | `T` | the value to act on | **Returns**: whether the sign bit is clear ## `SignOf<T>` ```rux pub func SignOf<T>(value: T) -> T ``` The value's sign as one of `-1`, `+1`, or the zero it started from. `value` is read by value; the answer is returned by copy in the same type. A zero returns itself, so `-0.0` returns `-0.0` and its sign is not lost. A NaN returns itself, since it has no sign to report. Cannot fail. Runs in constant time and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Floating.rux#L107){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | -------------------------------------------------------------- | | `T` | the integer or floating-point type, deduced from the arguments | **Parameters** | Name | Type | Description | | ------- | ---- | ------------------- | | `value` | `T` | the value to act on | **Returns**: -1, 0 or 1 as the value is negative, either zero, or positive # Outcomes Asking which channel a native fallible `T ! E` holds without unwrapping it. ## `Succeeded<T, E>` ```rux pub func Succeeded<T, E>(outcome: T ! E) -> bool ``` Whether `outcome` holds a success. `outcome` is consumed; its payload is destroyed after the question is answered. Runs in constant time and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Outcome.rux#L17){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | ---------------- | | `T` | the success type | | `E` | the error type | **Parameters** | Name | Type | Description | | --------- | ------- | ------------------- | | `outcome` | `T ! E` | the fallible to ask | **Returns**: whether it holds a success ## `Failed<T, E>` ```rux pub func Failed<T, E>(outcome: T ! E) -> bool ``` Whether `outcome` holds a failure. `outcome` is consumed; its payload is destroyed after the question is answered. Runs in constant time and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Outcome.rux#L32){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | ---------------- | | `T` | the success type | | `E` | the error type | **Parameters** | Name | Type | Description | | --------- | ------- | ------------------- | | `outcome` | `T ! E` | the fallible to ask | **Returns**: whether it holds a failure # Process start The frame the operating system hands a program when it starts. ## `ProcessStartFrame` ```rux pub func ProcessStartFrame() -> *uint ``` The address the kernel started the program at, on targets where that is where the arguments are. On Linux and FreeBSD it points at the argument count, followed by the argument pointers, a null, the environment pointers, a null and the auxiliary vector, all one word wide. It is null on Windows and macOS, whose command line and environment are read through system calls, and in a shared library, which the kernel never starts. The words belong to the process for its whole life and must not be written. Cannot fail; runs in constant time and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Core/Src/Startup.rux#L15){rel=""nofollow""} **Returns**: the initial stack address, or null where the platform supplies the arguments another way # Zeroize Overwrites a byte range with zeros, and is never removed however unread those bytes are afterwards. ```rux pub func Zeroize(memory: *var uint8, length: uint64) ``` `memory` is borrowed for the call and must address at least `length` writable bytes; passing fewer, or a null pointer with a non-zero length, is undefined. `length` of zero writes nothing. Nothing is returned. Clearing a secret is a write nothing reads back, which is exactly what dead-store elimination is entitled to delete. Ordinary source cannot say "and mean it", so this is a compiler guarantee rather than a library one: every write the call lowers to is marked as one that must happen. Runs in time proportional to `length` and allocates nothing. It clears the storage it is given and nothing else -- a value copied elsewhere beforehand, or spilled to a register or the stack by the caller, is not reached. ## Parameters | Name | Type | Description | | -------- | ------------ | ------------------ | | `memory` | `*var uint8` | the bytes to clear | | `length` | `uint64` | how many bytes | # Memory Memory management functions. ## Installation Add `Memory` to the `[Dependencies]` table of your package's `Rux.toml`: ```toml [Dependencies] Memory = { Namespace = "Rux", Version = "0.1.0" } ``` Standard packages are declared by hand: the registry does not serve them, so `rux add Rux/Memory` cannot add them. ## Dependencies - [`Core`](https://rux-lang.dev/docs/api/core) 0.1.0 - [`FreeBSD`](https://rux-lang.dev/docs/api/freebsd) 0.1.0 (FreeBSD only) - [`Linux`](https://rux-lang.dev/docs/api/linux) 0.1.0 (Linux only) - [`macOS`](https://rux-lang.dev/docs/api/macos) 0.1.0 (macOS only) - [`Windows`](https://rux-lang.dev/docs/api/windows) 0.1.0 (Windows only) ## Guide Memory management functions: raw allocation and the block operations that go with it. Every function dispatches on `#target.os` at compile time, so a build carries exactly one platform's implementation — `mmap`/`munmap` on Linux, macOS, and the BSDs, and the process heap on Windows. ### What it provides | Function | Purpose | | ------------------------------------------------------------------------------- | --------------------------------------------------------------- | | [`Alloc`](https://rux-lang.dev/docs/api/memory/allocation#alloc) | Allocate an uninitialized block | | [`Realloc`](https://rux-lang.dev/docs/api/memory/allocation#realloc) | Resize a block, preserving its contents | | [`Free`](https://rux-lang.dev/docs/api/memory/allocation#free) | Release a block | | [`Copy`](https://rux-lang.dev/docs/api/memory/blocks#copy) | Copy bytes between blocks that do not overlap | | [`Move`](https://rux-lang.dev/docs/api/memory/blocks#move) | Copy bytes between blocks that may overlap in any way | | [`Set`](https://rux-lang.dev/docs/api/memory/blocks#set) | Fill a block with a byte value | | [`Zero`](https://rux-lang.dev/docs/api/memory/blocks#zero) | Fill a block with zero | | [`Compare`](https://rux-lang.dev/docs/api/memory/blocks#compare) | Order two blocks lexicographically, returning an `Ordering` | | [`Equal`](https://rux-lang.dev/docs/api/memory/blocks#equal) | Whether two blocks hold the same bytes | | [`MismatchOffset`](https://rux-lang.dev/docs/api/memory/blocks#mismatch-offset) | Where two blocks first differ, or their length when they do not | | [`Find`](https://rux-lang.dev/docs/api/memory/blocks#find) | Where a byte first occurs, or the length when it does not | \| [`PageSize`](https://rux-lang.dev/docs/api/memory/pages#page-size) / [`MinimumPageSize`](https://rux-lang.dev/docs/api/memory/pages#minimum-page-size) / [`PageAlign`](https://rux-lang.dev/docs/api/memory/pages#page-align) | Asking the system its real page size, the documented floor, and rounding a length to that floor | \| [`PageAllocate`](https://rux-lang.dev/docs/api/memory/pages#page-allocate) / [`PageRelease`](https://rux-lang.dev/docs/api/memory/pages#page-release) / [`PageProtect`](https://rux-lang.dev/docs/api/memory/pages#page-protect) | Address space at the granularity the system hands it out in | **Zero length is always legal, and null is legal with it.** `Copy(null, null, 0)` is defined and does nothing. That is deliberately not C's rule, where passing null to `memcpy` is undefined even for a zero length — a rule that turns an ordinary empty case into a trap and makes every caller guard. [`Copy`](https://rux-lang.dev/docs/api/memory/blocks#copy) may be read as copying byte zero first, so a destination overlapping the source ahead of it reads bytes the copy has already overwritten. [`Move`](https://rux-lang.dev/docs/api/memory/blocks#move) is defined for every overlap and chooses its direction accordingly. The page layer is what sits under an allocator, not an allocator itself. Nothing there tracks what it gave out or remembers a length; a caller releases exactly what it took. Failure is a [`PageError`](https://rux-lang.dev/docs/api/memory/pages#page-error) rather than an errno, a `GetLastError` code or a sentinel address — one set of reasons across four systems that report three different ways. Windows differs in kind: it separates reserving address space from committing storage to it, and [`PageAllocate`](https://rux-lang.dev/docs/api/memory/pages#page-allocate) always does both, which is what every other system does and what an allocator expects. A caller wanting a large reservation cheaply has to reach for `Rux/Windows` directly. [`PageSize`](https://rux-lang.dev/docs/api/memory/pages#page-size) asks the system, and reports whether it got an answer. Each platform package owns its own query — `GetSystemInfo` on Windows, `getpagesize` on Darwin, the `hw.pagesize` sysctl on FreeBSD, and `/proc/self/auxv` on Linux, whose kernel publishes the value in the auxiliary vector rather than behind a system call. Nothing is captured at process start and no libc is called. When the system will not answer — a container built without `/proc` is the ordinary way that happens — this reports `Unsupported` rather than substituting a number, because a caller asking for the real size is worse served by a wrong one than by a refusal. [`PageAlign`](https://rux-lang.dev/docs/api/memory/pages#page-align) rounds to [`MinimumPageSize`](https://rux-lang.dev/docs/api/memory/pages#minimum-page-size), which is 4 KiB and is the floor on every supported cell rather than the size on any particular one: Apple Silicon uses 16 KiB, and a Linux kernel may be configured for 16 or 64. Rounding to a divisor of the real size cannot make an allocation wrong — every call here hands the length to a system that rounds again — and it keeps a file read out of an allocator's inner loop. A caller that needs whole *real* pages asks [`PageSize`](https://rux-lang.dev/docs/api/memory/pages#page-size) once, keeps the answer, and rounds with [`AlignUp`](https://rux-lang.dev/docs/api/memory/alignment#align-up) itself. None of the comparisons is constant-time: each stops at the first difference, so none may compare a secret. ### Value and ownership model [`PageError`](https://rux-lang.dev/docs/api/memory/pages#page-error) is a structural [`Copy`](https://rux-lang.dev/docs/api/memory/blocks#copy) value. Every address remains a raw pointer because this package exposes byte ranges, nullable allocation failure, stored addresses, pointer arithmetic, and explicit release—the operations for which references cannot prove validity or ownership. [`Alloc`](https://rux-lang.dev/docs/api/memory/allocation#alloc) and [`PageAllocate`](https://rux-lang.dev/docs/api/memory/pages#page-allocate) transfer ownership to the caller; [`Free`](https://rux-lang.dev/docs/api/memory/allocation#free) and [`PageRelease`](https://rux-lang.dev/docs/api/memory/pages#page-release) end it. No destructor runs automatically, so never copy an owning address with the intent of freeing both copies. Scalar output slots are also raw: pass writable addresses such as `@result` and obey the function's non-null contract. > **Changed in this release.** [`Compare`](https://rux-lang.dev/docs/api/memory/blocks#compare) now returns an `Ordering`, which is what this table always claimed it did; > the old first-difference offset is [`MismatchOffset`](https://rux-lang.dev/docs/api/memory/blocks#mismatch-offset), and [`Equal`](https://rux-lang.dev/docs/api/memory/blocks#equal) is what most callers of the old [`Compare`](https://rux-lang.dev/docs/api/memory/blocks#compare) wanted. > [`Set`](https://rux-lang.dev/docs/api/memory/blocks#set) takes its arguments in `memset` order — destination, value, length — where it previously took the length > before the value, and its value is a `byte` rather than an `int32`, so a mistaken call fails to compile. ### Example ```rux import Memory::{ Alloc, Free, Zero }; var buffer = Alloc(1024); if buffer != null { Zero(buffer, 1024); Free(buffer); } ``` ## Index ### Types | Name | Summary | | -------------------------------------------------------------------- | ----------------------------------------------- | | [`PageError`](https://rux-lang.dev/docs/api/memory/pages#page-error) | Why a page operation did not do what was asked. | ### Functions | Name | Summary | | --------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------- | | [`IsAligned`](https://rux-lang.dev/docs/api/memory/alignment#is-aligned) | Whether `address` is a multiple of `alignment`. | | [`IsPointerAligned`](https://rux-lang.dev/docs/api/memory/alignment#is-pointer-aligned) | Whether `pointer` is aligned for `alignment`. | | [`AlignUp`](https://rux-lang.dev/docs/api/memory/alignment#align-up) | The next multiple of `alignment` at or above `value`. | | [`AlignUpChecked`](https://rux-lang.dev/docs/api/memory/alignment#align-up-checked) | The next multiple of `alignment` at or above `value`, reporting whether it was representable. | | [`AlignDown`](https://rux-lang.dev/docs/api/memory/alignment#align-down) | The previous multiple of `alignment` at or below `value`. | | [`LoadUnaligned<T>`](https://rux-lang.dev/docs/api/memory/unaligned-access#load-unaligned) | Reads a value of `T` from `source`, whatever `source` is aligned to. | | [`StoreUnaligned<T>`](https://rux-lang.dev/docs/api/memory/unaligned-access#store-unaligned) | Writes a value of `T` to `destination`, whatever `destination` is aligned to. | | [`ReverseBlock`](https://rux-lang.dev/docs/api/memory/unaligned-access#reverse-block) | Reverses the order of `length` bytes at `buffer`, in place. | | [`LoadLittleEndian<T>`](https://rux-lang.dev/docs/api/memory/unaligned-access#load-little-endian) | Reads a `T` from `source`, taking the bytes as little-endian. | | [`LoadBigEndian<T>`](https://rux-lang.dev/docs/api/memory/unaligned-access#load-big-endian) | Reads a `T` from `source`, taking the bytes as big-endian. | | [`StoreLittleEndian<T>`](https://rux-lang.dev/docs/api/memory/unaligned-access#store-little-endian) | Writes a `T` to `destination` as little-endian bytes. | | [`StoreBigEndian<T>`](https://rux-lang.dev/docs/api/memory/unaligned-access#store-big-endian) | Writes a `T` to `destination` as big-endian bytes. | | [`ZeroizeBlock`](https://rux-lang.dev/docs/api/memory/blocks#zeroize-block) | Clears `length` bytes at `buffer`, and is not removed however unread those bytes are afterwards. | | [`Alloc`](https://rux-lang.dev/docs/api/memory/allocation#alloc) | Allocates `size` uninitialized bytes. | | [`Copy`](https://rux-lang.dev/docs/api/memory/blocks#copy) | Copies `length` bytes from `source` to `destination`, which must not overlap. | | [`Move`](https://rux-lang.dev/docs/api/memory/blocks#move) | Copies `length` bytes from `source` to `destination`, correctly even when the two overlap. | | [`Set`](https://rux-lang.dev/docs/api/memory/blocks#set) | Writes `value` to each of `length` bytes at `destination`. | | [`Zero`](https://rux-lang.dev/docs/api/memory/blocks#zero) | Writes zero to each of `length` bytes at `destination`. | | [`MismatchOffset`](https://rux-lang.dev/docs/api/memory/blocks#mismatch-offset) | The offset at which two blocks first differ, or `length` when they do not. | | [`Compare`](https://rux-lang.dev/docs/api/memory/blocks#compare) | Orders two blocks lexicographically, byte by byte. | | [`Equal`](https://rux-lang.dev/docs/api/memory/blocks#equal) | Whether two blocks hold the same bytes. | | [`Find`](https://rux-lang.dev/docs/api/memory/blocks#find) | The offset of the first byte equal to `value`, or `length` when there is none. | | [`Free`](https://rux-lang.dev/docs/api/memory/allocation#free) | Releases an allocation. | | [`PageSize`](https://rux-lang.dev/docs/api/memory/pages#page-size) | Asks the system how large a page actually is, in bytes. | | [`PageAllocate`](https://rux-lang.dev/docs/api/memory/pages#page-allocate) | Takes `length` bytes of address space with the given protection, and reports where it landed. | | [`PageRelease`](https://rux-lang.dev/docs/api/memory/pages#page-release) | Gives back `length` bytes of address space at `address`. | | [`PageProtect`](https://rux-lang.dev/docs/api/memory/pages#page-protect) | Changes what may be done with `length` bytes at `address`. | | [`PageAlign`](https://rux-lang.dev/docs/api/memory/pages#page-align) | Rounds `length` up to a whole number of [`MinimumPageSize`](https://rux-lang.dev/docs/api/memory/pages#minimum-page-size) blocks. | | [`Realloc`](https://rux-lang.dev/docs/api/memory/allocation#realloc) | Resizes an allocation to `size` bytes, preserving the bytes that still fit. | ### Constants | Name | Summary | | --------------------------------------------------------------------------------- | -------------------------------------------------------------------- | | [`PageNone`](https://rux-lang.dev/docs/api/memory/pages#page-none) | What may be done with a page, as a set of flags to combine with `|`. | | [`PageRead`](https://rux-lang.dev/docs/api/memory/pages#page-read) | The page may be read. | | [`PageWrite`](https://rux-lang.dev/docs/api/memory/pages#page-write) | The page may be written. | | [`PageExecute`](https://rux-lang.dev/docs/api/memory/pages#page-execute) | The page may be executed. | | [`MinimumPageSize`](https://rux-lang.dev/docs/api/memory/pages#minimum-page-size) | The smallest page any supported system uses, in bytes. | # Alignment Testing addresses for alignment and rounding them to a boundary. ## `IsAligned` ```rux pub func IsAligned(address: uint, alignment: uint) -> bool ``` Whether `address` is a multiple of `alignment`. `address` and `alignment` are read by value. An `alignment` of zero reports false rather than dividing by it, and an alignment that is not a power of two gives an answer that is arithmetically true but rarely meaningful, since hardware alignment is always a power of two. Cannot fail. Runs in constant time and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Memory/Src/Access.rux#L22){rel=""nofollow""} **Parameters** | Name | Type | Description | | ----------- | ------ | ------------------------------------------------ | | `address` | `uint` | the address or offset to test | | `alignment` | `uint` | the boundary to test against; zero reports false | **Returns**: whether `address` is a multiple of `alignment` ## `IsPointerAligned` ```rux pub func IsPointerAligned( pointer: *opaque, alignment: uint ) -> bool ``` Whether `pointer` is aligned for `alignment`. `pointer` is read by value and never dereferenced. A null pointer reports true for every alignment, since zero is a multiple of everything; a caller that means "usable" has to ask that separately. Cannot fail. Runs in constant time and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Memory/Src/Access.rux#L35){rel=""nofollow""} **Parameters** | Name | Type | Description | | ----------- | --------- | --------------------------------------- | | `pointer` | `*opaque` | the address to test, never dereferenced | | `alignment` | `uint` | the boundary to test against | **Returns**: whether `pointer` is a multiple of `alignment` ## `AlignUp` ```rux pub func AlignUp(value: uint, alignment: uint) -> uint ``` The next multiple of `alignment` at or above `value`. `value` and `alignment` are read by value. An `alignment` of zero or one returns `value` unchanged, since every value is already a multiple of both. Returns `value` itself when it is already aligned, so this is idempotent. A `value` within `alignment - 1` of the maximum has no next multiple, and this wraps to a small number rather than reporting it. A caller sizing an allocation must check for that before trusting the result; [`AlignUpChecked`](https://rux-lang.dev/docs/api/memory/alignment#align-up-checked) does the checking. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Memory/Src/Access.rux#L50){rel=""nofollow""} **Parameters** | Name | Type | Description | | ----------- | ------ | ----------------------------------------------------- | | `value` | `uint` | the value to round up | | `alignment` | `uint` | the boundary to round to; zero or one changes nothing | **Returns**: the next multiple of `alignment` at or above `value` ## `AlignUpChecked` ```rux pub func AlignUpChecked( value: uint, alignment: uint, result: *var uint ) -> bool ``` The next multiple of `alignment` at or above `value`, reporting whether it was representable. `value` and `alignment` are read by value; `result` receives the aligned value when this returns `false`, and is left unwritten when it returns `true`. `result` must not be null. Returns `true` when rounding up would pass the maximum, which is the case an allocation size has to notice: a wrapped size is an allocation far smaller than the caller asked for. Runs in constant time and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Memory/Src/Access.rux#L67){rel=""nofollow""} **Parameters** | Name | Type | Description | | ----------- | ----------- | ----------------------------------------------------- | | `value` | `uint` | the value to round up | | `alignment` | `uint` | the boundary to round to; zero or one changes nothing | | `result` | `*var uint` | receives the aligned value when this returns false | **Returns**: true when rounding up would pass the maximum ## `AlignDown` ```rux pub func AlignDown(value: uint, alignment: uint) -> uint ``` The previous multiple of `alignment` at or below `value`. `value` and `alignment` are read by value. An `alignment` of zero or one returns `value` unchanged. Cannot fail: rounding down never leaves the range. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Memory/Src/Access.rux#L90){rel=""nofollow""} **Parameters** | Name | Type | Description | | ----------- | ------ | ----------------------------------------------------- | | `value` | `uint` | the value to round down | | `alignment` | `uint` | the boundary to round to; zero or one changes nothing | **Returns**: the previous multiple of `alignment` at or below `value` # Heap allocation Allocating, resizing and releasing blocks on the system heap. ## `Alloc` ```rux pub func Alloc(size: uint) -> *var opaque ``` Allocates `size` uninitialized bytes. Returns the base address, or null when the size overflows the platform bookkeeping or the system cannot satisfy the request. A zero size is permitted, but the returned address is platform-dependent and must not be touched. The allocation is owned by the caller until [`Free`](https://rux-lang.dev/docs/api/memory/allocation#free) releases it or [`Realloc`](https://rux-lang.dev/docs/api/memory/allocation#realloc) replaces it. The address is aligned to at least 16 bytes on every supported target. The bytes are uninitialized. Reading any byte before writing it, accessing beyond `size`, or using the address after it is released is invalid. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Memory/Src/Alloc.rux#L29){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------ | ------ | ----------------------------------------- | | `size` | `uint` | how many bytes to take; zero returns null | **Returns**: the address of the allocation, or null when the system refused ## `Free` ```rux pub func Free(ptr: *opaque) ``` Releases an allocation. A null pointer is accepted and does nothing. A non-null `ptr` must be the live base address returned by [`Alloc`](https://rux-lang.dev/docs/api/memory/allocation#alloc) or [`Realloc`](https://rux-lang.dev/docs/api/memory/allocation#realloc). Every pointer into the block becomes invalid immediately; releasing an interior, foreign, or already released address is invalid. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Memory/Src/Free.rux#L20){rel=""nofollow""} **Parameters** | Name | Type | Description | | ----- | --------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `ptr` | `*opaque` | an address [`Alloc`](https://rux-lang.dev/docs/api/memory/allocation#alloc) or [`Realloc`](https://rux-lang.dev/docs/api/memory/allocation#realloc) returned, or null | ## `Realloc` ```rux pub func Realloc(ptr: *opaque, size: uint) -> *var opaque ``` Resizes an allocation to `size` bytes, preserving the bytes that still fit. A null `ptr` behaves as `Alloc(size)`. A zero size releases a non-null allocation and returns null. On failure, returns null and leaves the original allocation valid; on success, the original address is invalid even when the returned address has the same numeric value. A non-null `ptr` must be the live base address returned by [`Alloc`](https://rux-lang.dev/docs/api/memory/allocation#alloc) or an earlier `Realloc`. Interior, released, or foreign addresses are invalid. Bytes added beyond the old size are uninitialized. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Memory/Src/Realloc.rux#L23){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------ | --------- | ----------------------------------------------- | | `ptr` | `*opaque` | the allocation to resize, or null to allocate | | `size` | `uint` | the wanted size; zero releases and returns null | **Returns**: the address of the resized allocation, or null on failure # Block operations Copying, filling, clearing, comparing and searching blocks of bytes. ## `ZeroizeBlock` ```rux pub func ZeroizeBlock(buffer: *var opaque, length: uint) ``` Clears `length` bytes at `buffer`, and is not removed however unread those bytes are afterwards. `buffer` is borrowed and written. A `length` of zero writes nothing and accepts a null pointer. This is what [`Zero`](https://rux-lang.dev/docs/api/memory/blocks#zero) is not. Clearing a secret is a write nothing reads back, which dead-store elimination is entitled to delete, and ordinary source cannot say "and mean it" — so this is a compiler guarantee rather than a library one. The guarantee is `Core::Zeroize`'s; this adds the empty-case contract the rest of this module has and takes the `*var opaque` and `uint` every other block operation here takes. Cannot fail. Runs in time proportional to `length` and allocates nothing. `buffer` must be writable for `length` bytes. It clears the storage it is given and nothing else. A copy the caller made beforehand, a value the compiler spilled to the stack, or bytes a reallocation left behind are all still there — so a secret has to be kept in one place from the start for this to be the whole of its erasure. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Memory/Src/Access.rux#L227){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | ------------- | -------------------------------------------------------------- | | `buffer` | `*var opaque` | the bytes to clear | | `length` | `uint` | how many bytes; zero writes nothing and accepts a null pointer | ## `Copy` ```rux pub func Copy( destination: *var opaque, source: *opaque, length: uint ) ``` Copies `length` bytes from `source` to `destination`, which must not overlap. `source` is borrowed and read; `destination` is borrowed and written. Nothing is returned and nothing takes ownership. A `length` of zero copies nothing and accepts null for either pointer. Cannot fail. Runs in time proportional to `length` and allocates nothing. `destination` must be writable for `length` bytes and `source` readable for `length`, and the two ranges must not overlap. Use [`Move`](https://rux-lang.dev/docs/api/memory/blocks#move) when they might: this one is free to copy in whichever order suits the machine. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Memory/Src/Block.rux#L30){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------------- | ------------- | --------------------------------------------- | | `destination` | `*var opaque` | where the bytes go; must not overlap `source` | | `source` | `*opaque` | where the bytes come from | | `length` | `uint` | how many bytes to copy | ## `Move` ```rux pub func Move( destination: *var opaque, source: *opaque, length: uint ) ``` Copies `length` bytes from `source` to `destination`, correctly even when the two overlap. `source` is borrowed and read; `destination` is borrowed and written. A `length` of zero moves nothing and accepts null for either pointer. The result is what copying through a temporary would give: every source byte reaches its destination as it was before the move began. Sliding a run forward within one buffer therefore works, which is what an insertion into the middle of an array needs. Cannot fail. Runs in time proportional to `length` and allocates nothing — the temporary is notional, and the direction of the copy is what actually makes it right. `destination` must be writable for `length` bytes and `source` readable for `length`. They may overlap in any way, including exactly. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Memory/Src/Block.rux#L59){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------------- | ------------- | ---------------------------------------- | | `destination` | `*var opaque` | where the bytes go; may overlap `source` | | `source` | `*opaque` | where the bytes come from | | `length` | `uint` | how many bytes to move | ## `Set` ```rux pub func Set( destination: *var opaque, value: byte, length: uint ) ``` Writes `value` to each of `length` bytes at `destination`. `destination` is borrowed and written. A `length` of zero writes nothing and accepts a null pointer. Cannot fail. Runs in time proportional to `length` and allocates nothing. `destination` must be writable for `length` bytes. This is not the call for clearing a secret: a write nothing reads back may be deleted, and `Core::Zeroize` is the one that may not be. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Memory/Src/Block.rux#L92){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------------- | ------------- | ------------------------- | | `destination` | `*var opaque` | the bytes to write | | `value` | `byte` | the byte to write to each | | `length` | `uint` | how many bytes to write | ## `Zero` ```rux pub func Zero(destination: *var opaque, length: uint) ``` Writes zero to each of `length` bytes at `destination`. `destination` is borrowed and written. A `length` of zero writes nothing and accepts a null pointer. Cannot fail. Runs in time proportional to `length` and allocates nothing. `destination` must be writable for `length` bytes. For a secret, use `Core::Zeroize`, which the compiler may not delete however unread the bytes are afterwards. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Memory/Src/Block.rux#L114){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------------- | ------------- | ----------------------- | | `destination` | `*var opaque` | the bytes to clear | | `length` | `uint` | how many bytes to clear | ## `MismatchOffset` ```rux pub func MismatchOffset( left: *opaque, right: *opaque, length: uint ) -> uint ``` The offset at which two blocks first differ, or `length` when they do not. Both pointers are borrowed and read. A `length` of zero reports zero and accepts null for either pointer, which is the same answer two equal empty blocks give. The answer is a position rather than an ordering, so it says where the blocks diverge and not which one sorts first. [`Compare`](https://rux-lang.dev/docs/api/memory/blocks#compare) answers that. Cannot fail. Runs in time proportional to the shared prefix and allocates nothing. Both pointers must be readable for `length` bytes. Not constant-time: it stops at the first difference, so it must not be used on a secret. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Memory/Src/Block.rux#L136){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | --------- | ------------------------- | | `left` | `*opaque` | one of the two blocks | | `right` | `*opaque` | the other | | `length` | `uint` | how many bytes to compare | **Returns**: the offset of the first differing byte, or `length` when none differs ## `Compare` ```rux pub func Compare( left: *opaque, right: *opaque, length: uint ) -> Ordering ``` Orders two blocks lexicographically, byte by byte. Both pointers are borrowed and read. Returns `Less` when `left` sorts first, `Greater` when `right` does, and [`Equal`](https://rux-lang.dev/docs/api/memory/blocks#equal) when the two ranges hold the same bytes. A `length` of zero reports [`Equal`](https://rux-lang.dev/docs/api/memory/blocks#equal) and accepts null for either pointer. Bytes are compared as unsigned, so the answer does not depend on whether the platform's plain `char` is signed, and it matches the order the bytes would sort in as a string. Cannot fail. Runs in time proportional to the shared prefix and allocates nothing. Both pointers must be readable for `length` bytes. Not constant-time: it stops at the first difference, so a secret compared this way leaks where it differs. `Rux/Crypto` is where a constant-time comparison belongs. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Memory/Src/Block.rux#L166){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | --------- | ------------------------- | | `left` | `*opaque` | one of the two blocks | | `right` | `*opaque` | the other | | `length` | `uint` | how many bytes to compare | **Returns**: how `left` orders against `right` ## `Equal` ```rux pub func Equal( left: *opaque, right: *opaque, length: uint ) -> bool ``` Whether two blocks hold the same bytes. Both pointers are borrowed and read. A `length` of zero reports true and accepts null for either pointer: two empty blocks are equal. Cannot fail. Runs in time proportional to the shared prefix and allocates nothing. Both pointers must be readable for `length` bytes. Not constant-time. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Memory/Src/Block.rux#L184){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | --------- | ------------------------- | | `left` | `*opaque` | one of the two blocks | | `right` | `*opaque` | the other | | `length` | `uint` | how many bytes to compare | **Returns**: whether every byte matches ## `Find` ```rux pub func Find( haystack: *opaque, length: uint, value: byte ) -> uint ``` The offset of the first byte equal to `value`, or `length` when there is none. `haystack` is borrowed and read. A `length` of zero reports zero and accepts a null pointer, which is also what a search that found nothing reports — an empty block contains nothing to find either way. Cannot fail. Runs in time proportional to the offset returned and allocates nothing. `haystack` must be readable for `length` bytes. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Memory/Src/Block.rux#L198){rel=""nofollow""} **Parameters** | Name | Type | Description | | ---------- | --------- | ------------------------ | | `haystack` | `*opaque` | the bytes to search | | `length` | `uint` | how many bytes to search | | `value` | `byte` | the byte to look for | **Returns**: the offset of the first occurrence, or `length` when there is none # Unaligned and byte-order access Reading and writing values at any alignment and in either byte order. ## `LoadUnaligned<T>` ```rux pub func LoadUnaligned<T>( source: *opaque, destination: *var T ) ``` Reads a value of `T` from `source`, whatever `source` is aligned to. `source` is borrowed and `sizeof(T)` bytes are read from it; `destination` receives the value. Both must be non-null. The bytes are taken one at a time, so this is correct at any address on any machine — including the ones where a misaligned load faults rather than merely costing more. Cannot fail. Runs in time proportional to `sizeof(T)` and allocates nothing. `source` must be readable for `sizeof(T)` bytes. The bytes are taken as they are, so a value that is not a valid `T` stays invalid; this reinterprets rather than validating. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Memory/Src/Access.rux#L107){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | ----------------------------- | | `T` | the type whose bytes are read | **Parameters** | Name | Type | Description | | ------------- | --------- | ------------------------------------------------------------ | | `source` | `*opaque` | the address to read `sizeof(T)` bytes from, at any alignment | | `destination` | `*var T` | receives the value | ## `StoreUnaligned<T>` ```rux pub func StoreUnaligned<T>( destination: *var opaque, value: *T ) ``` Writes a value of `T` to `destination`, whatever `destination` is aligned to. `value` is borrowed and read; `destination` is borrowed and receives `sizeof(T)` bytes. Both must be non-null. Cannot fail. Runs in time proportional to `sizeof(T)` and allocates nothing. `destination` must be writable for `sizeof(T)` bytes. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Memory/Src/Access.rux#L119){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | -------------------------------- | | `T` | the type whose bytes are written | **Parameters** | Name | Type | Description | | ------------- | ------------- | ----------------------------------------------------------- | | `destination` | `*var opaque` | the address to write `sizeof(T)` bytes to, at any alignment | | `value` | `*T` | the value to write | ## `ReverseBlock` ```rux pub func ReverseBlock(buffer: *var opaque, length: uint) ``` Reverses the order of `length` bytes at `buffer`, in place. `buffer` is borrowed and rewritten. A `length` of zero or one changes nothing and accepts a null pointer at zero. This is the byte-order conversion for a run of bytes rather than for one value; `Core::ReverseBytes` is the one that takes an integer. Cannot fail. Runs in time proportional to `length` and allocates nothing. `buffer` must be readable and writable for `length` bytes. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Memory/Src/Access.rux#L132){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | ------------- | ------------------------------------------- | | `buffer` | `*var opaque` | the bytes to reverse in place | | `length` | `uint` | how many bytes; zero or one changes nothing | ## `LoadLittleEndian<T>` ```rux pub func LoadLittleEndian<T>( source: *opaque, destination: *var T ) ``` Reads a `T` from `source`, taking the bytes as little-endian. `source` is borrowed and `sizeof(T)` bytes are read; `destination` receives the value in the target's own order. Both must be non-null. Needs no alignment. This is the pair of calls a file or wire format actually needs: the bytes are wherever the format put them, and their order is the format's rather than the machine's. Cannot fail. Runs in time proportional to `sizeof(T)` and allocates nothing. `source` must be readable for `sizeof(T)` bytes. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Memory/Src/Access.rux#L157){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | ----------------------------- | | `T` | the type whose bytes are read | **Parameters** | Name | Type | Description | | ------------- | --------- | -------------------------------------------------------- | | `source` | `*opaque` | the address to read `sizeof(T)` little-endian bytes from | | `destination` | `*var T` | receives the value in the target's own order | ## `LoadBigEndian<T>` ```rux pub func LoadBigEndian<T>( source: *opaque, destination: *var T ) ``` Reads a `T` from `source`, taking the bytes as big-endian. `source` is borrowed and `sizeof(T)` bytes are read; `destination` receives the value in the target's own order. Both must be non-null. Needs no alignment. This is network byte order. Cannot fail. Runs in time proportional to `sizeof(T)` and allocates nothing. `source` must be readable for `sizeof(T)` bytes. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Memory/Src/Access.rux#L173){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | ----------------------------- | | `T` | the type whose bytes are read | **Parameters** | Name | Type | Description | | ------------- | --------- | ----------------------------------------------------- | | `source` | `*opaque` | the address to read `sizeof(T)` big-endian bytes from | | `destination` | `*var T` | receives the value in the target's own order | ## `StoreLittleEndian<T>` ```rux pub func StoreLittleEndian<T>( destination: *var opaque, value: *T ) ``` Writes a `T` to `destination` as little-endian bytes. `value` is borrowed and read; `destination` receives `sizeof(T)` bytes. Both must be non-null. Needs no alignment. Cannot fail. Runs in time proportional to `sizeof(T)` and allocates nothing. `destination` must be writable for `sizeof(T)` bytes. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Memory/Src/Access.rux#L189){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | -------------------------------- | | `T` | the type whose bytes are written | **Parameters** | Name | Type | Description | | ------------- | ------------- | ---------------------------------------- | | `destination` | `*var opaque` | receives `sizeof(T)` little-endian bytes | | `value` | `*T` | the value to write | ## `StoreBigEndian<T>` ```rux pub func StoreBigEndian<T>( destination: *var opaque, value: *T ) ``` Writes a `T` to `destination` as big-endian bytes. `value` is borrowed and read; `destination` receives `sizeof(T)` bytes. Both must be non-null. Needs no alignment. Cannot fail. Runs in time proportional to `sizeof(T)` and allocates nothing. `destination` must be writable for `sizeof(T)` bytes. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Memory/Src/Access.rux#L205){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | -------------------------------- | | `T` | the type whose bytes are written | **Parameters** | Name | Type | Description | | ------------- | ------------- | ------------------------------------- | | `destination` | `*var opaque` | receives `sizeof(T)` big-endian bytes | | `value` | `*T` | the value to write | # Pages Address space in whole pages from the operating system, with a protection. ## `PageNone` ```rux pub const PageNone: uint32 = 0; ``` What may be done with a page, as a set of flags to combine with `|`. A protection of `PageNone` reserves the address space and refuses every access to it, which is how a guard page is made. Combining write and execute is refused outright by some systems and by policy on others, so a caller that needs both should write through one protection and execute through another. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Memory/Src/Pages.rux#L38){rel=""nofollow""} ## `PageRead` ```rux pub const PageRead: uint32 = 1; ``` The page may be read. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Memory/Src/Pages.rux#L42){rel=""nofollow""} ## `PageWrite` ```rux pub const PageWrite: uint32 = 2; ``` The page may be written. Implies readability on every supported system: none of them can make a page write-only, whatever their flags suggest. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Memory/Src/Pages.rux#L48){rel=""nofollow""} ## `PageExecute` ```rux pub const PageExecute: uint32 = 4; ``` The page may be executed. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Memory/Src/Pages.rux#L52){rel=""nofollow""} ## `PageError` ```rux pub enum PageError: uint8 { InvalidLength = 1, InvalidAddress = 2, OutOfMemory = 3, PermissionDenied = 4, Unsupported = 5, Failed = 6 } ``` Why a page operation did not do what was asked. [`Copy`](https://rux-lang.dev/docs/api/memory/blocks#copy). One set of reasons across four systems that report failure three different ways: an errno, a `GetLastError` code, and a sentinel address. A reason the mapping does not cover arrives as `Failed`, which is not a promise that nothing went wrong — only that this module could not name it. Every case is a failure: a call that succeeds reports its success channel instead. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Memory/Src/Pages.rux#L60){rel=""nofollow""} **Cases** | Name | Value | Description | | ------------------ | ----- | ----------------------------------------------------------------------------------------- | | `InvalidLength` | `1` | The length was zero, or too large for the address space to hold. | | `InvalidAddress` | `2` | The address was not page-aligned, or names nothing this process may operate on. | | `OutOfMemory` | `3` | The system has no storage to back the request. | | `PermissionDenied` | `4` | The system refused the protection asked for, which is usually write and execute together. | | `Unsupported` | `5` | The combination is not supported on this system. | | `Failed` | `6` | The system reported a failure this module has no name for. | ## `MinimumPageSize` ```rux pub const MinimumPageSize: uint = 4096; ``` The smallest page any supported system uses, in bytes. Four kibibytes, which is the page size on seven of the eight supported target cells and the floor on the eighth: Apple Silicon uses sixteen, and a Linux kernel may be configured for sixteen or sixty-four, but none of them goes below this. It is a bound, not an answer. [`PageAlign`](https://rux-lang.dev/docs/api/memory/pages#page-align) rounds to it because rounding to a divisor of the real page size is always safe — the system rounds again, up to whatever its pages actually are — and because asking the system on every call would put a file read or a system call inside an allocator's inner loop. A caller that needs the real granularity asks [`PageSize`](https://rux-lang.dev/docs/api/memory/pages#page-size) once and keeps the answer. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Memory/Src/Pages.rux#L84){rel=""nofollow""} ## `PageSize` ```rux pub func PageSize() -> uint ! PageError ``` Asks the system how large a page actually is, in bytes. The answer is always a power of two, and is the granularity every call in this module rounds a length up to. It varies by machine and not only by system: Apple Silicon uses sixteen kibibytes where Apple's x86-64 uses four, and a Linux kernel may be configured for either or for sixty-four. Each system is asked the way it wants to be asked, by the package that owns it — `GetSystemInfo` on Windows, `getpagesize` on Darwin, the `hw.pagesize` sysctl on FreeBSD, and `/proc/self/auxv` on Linux, whose kernel publishes the value in the auxiliary vector rather than behind a system call. Nothing is captured at process start and no libc is called. Reports `Unsupported` when the system would not answer — on Linux, a container built without `/proc` is the ordinary way that happens. A failure is reported rather than a guess substituted, because a caller that is asking this instead of using [`MinimumPageSize`](https://rux-lang.dev/docs/api/memory/pages#minimum-page-size) is asking for the real number, and a wrong real number is worse than a refusal it can handle. Allocates nothing. Runs in constant time on three systems and performs one open, read and close on Linux, so a caller that needs the size more than once should keep it. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Memory/Src/Pages.rux#L102){rel=""nofollow""} **Returns**: the page size in bytes, or the reason the system would not answer ## `PageAllocate` ```rux pub func PageAllocate( length: uint, protection: uint32 ) -> (*var opaque) ! PageError ``` Takes `length` bytes of address space with the given protection, and reports where it landed. `length` is rounded up to whole pages by the system. `protection` is a combination of the `Page*` flags, and [`PageNone`](https://rux-lang.dev/docs/api/memory/pages#page-none) is legal — it takes the space and refuses every access to it. The pages are zero-filled on every supported system. Nothing else about their contents is promised. A `length` of zero is refused with `InvalidLength` rather than succeeding with nothing, because a zero-length mapping is a caller's arithmetic error far more often than an intention. Runs in constant time as far as this module is concerned; the system may take longer. Allocates nothing beyond what it is asked for. The pages are the caller's until [`PageRelease`](https://rux-lang.dev/docs/api/memory/pages#page-release) takes exactly this length back. Releasing a different length, or an address this did not return, is undefined on Windows and silently partial elsewhere. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Memory/Src/Pages.rux#L134){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------------ | -------- | -------------------------------------------------------------------------------- | | `length` | `uint` | how many bytes of address space to take, rounded up to whole pages by the system | | `protection` | `uint32` | what may be done with the pages, as `Page*` flags | **Returns**: the base address of the pages, or the reason the address space was not taken ## `PageRelease` ```rux pub func PageRelease( address: *var opaque, length: uint ) -> ! PageError ``` Gives back `length` bytes of address space at `address`. `address` must be a base address [`PageAllocate`](https://rux-lang.dev/docs/api/memory/pages#page-allocate) returned, and `length` the length it was given. Succeeds when the system accepted the release. A `length` of zero is refused with `InvalidLength`, and a null `address` with `InvalidAddress`, rather than either being quietly ignored: both are arithmetic errors at the caller far more often than intentions. Every pointer into the range becomes invalid, and the address space may be handed to the next allocation at once. Windows requires the exact base address and ignores the length entirely; the other systems accept a sub-range and release only that, so a wrong length there silently releases the wrong amount. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Memory/Src/Pages.rux#L162){rel=""nofollow""} **Parameters** | Name | Type | Description | | --------- | ------------- | -------------------------------------------------------------------------------------------------- | | `address` | `*var opaque` | a base address [`PageAllocate`](https://rux-lang.dev/docs/api/memory/pages#page-allocate) returned | | `length` | `uint` | the length it was given | **Returns**: nothing on success, or the reason the system refused the release ## `PageProtect` ```rux pub func PageProtect( address: *var opaque, length: uint, protection: uint32 ) -> ! PageError ``` Changes what may be done with `length` bytes at `address`. `address` must be page-aligned and `length` is rounded up to whole pages. Succeeds when the system accepted the change. The change takes effect at once, so a thread touching the range concurrently faults rather than finishing what it started. Nothing here checks that the range was ever allocated. Asking for write and execute together is refused on Apple Silicon without an entitlement and by policy on hardened systems elsewhere, which arrives as `PermissionDenied`. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Memory/Src/Pages.rux#L189){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------------ | ------------- | ------------------------------------------ | | `address` | `*var opaque` | a page-aligned address | | `length` | `uint` | how many bytes, rounded up to whole pages | | `protection` | `uint32` | what may be done with the pages afterwards | **Returns**: nothing on success, or the reason the system refused the change ## `PageAlign` ```rux pub func PageAlign(length: uint) -> uint ``` Rounds `length` up to a whole number of [`MinimumPageSize`](https://rux-lang.dev/docs/api/memory/pages#minimum-page-size) blocks. It rounds to the bound rather than to the system's real page size, which is a deliberate difference from what the name suggests and the reason [`MinimumPageSize`](https://rux-lang.dev/docs/api/memory/pages#minimum-page-size) is public. Rounding to a divisor of the real size cannot make an allocation wrong — every call in this module hands the length to a system that rounds again, up to whatever its pages actually are — and it keeps a file read out of an allocator's inner loop. On a machine with larger pages the result is a length the system will round further, which costs nothing. A caller that needs the length to be a whole number of *real* pages asks [`PageSize`](https://rux-lang.dev/docs/api/memory/pages#page-size) once, keeps the answer, and rounds with [`AlignUp`](https://rux-lang.dev/docs/api/memory/alignment#align-up) itself. Returns the rounded length, or `length` itself when rounding would pass the end of the range — which a caller sizing an allocation should notice, since the system will refuse such a length anyway. Cannot fail. Runs in constant time and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Memory/Src/Pages.rux#L219){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | ------ | -------------------------- | | `length` | `uint` | the byte count to round up | **Returns**: the rounded length # Allocator Allocation contracts and the allocators that meet them. ## Installation Add `Allocator` to the `[Dependencies]` table of your package's `Rux.toml`: ```toml [Dependencies] Allocator = { Namespace = "Rux", Version = "0.1.0" } ``` Standard packages are declared by hand: the registry does not serve them, so `rux add Rux/Allocator` cannot add them. ## Dependencies - [`Core`](https://rux-lang.dev/docs/api/core) 0.1.0 - [`Memory`](https://rux-lang.dev/docs/api/memory) 0.1.0 ## Guide ### What it provides | Module | Covers | | --------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | [`Layout`](https://rux-lang.dev/docs/api/allocator/layout) | a validated size-and-alignment pair, and the layouts a type or array needs | | `Error` | [`AllocError`](https://rux-lang.dev/docs/api/allocator/alloc-error), and the questions worth asking of one | | `Contract` | the [`Allocator`](https://rux-lang.dev/docs/api/allocator/allocator) interface every allocator here implements | | `System` | [`SystemAllocator`](https://rux-lang.dev/docs/api/allocator/system-allocator), which asks the operating system for pages | | [`Box`](https://rux-lang.dev/docs/api/allocator/box) | [`Box<T>`](https://rux-lang.dev/docs/api/allocator/box), one heap value with exactly one owner | | `Shared` | [`Rc<T>`](https://rux-lang.dev/docs/api/allocator/shared#rc) and [`Arc<T>`](https://rux-lang.dev/docs/api/allocator/shared#arc), one heap value shared by counted handles | | [`Arena`](https://rux-lang.dev/docs/api/allocator/arena) | [`Arena`](https://rux-lang.dev/docs/api/allocator/arena), which advances a pointer and reclaims everything at once | | [`FixedBuffer`](https://rux-lang.dev/docs/api/allocator/fixed-buffer) | [`FixedBuffer`](https://rux-lang.dev/docs/api/allocator/fixed-buffer), which hands out storage the caller already has | | [`Pool`](https://rux-lang.dev/docs/api/allocator/pool) | [`Pool`](https://rux-lang.dev/docs/api/allocator/pool), which serves small blocks from per-class free lists | The module names describe where each declaration comes from; they are not part of an import path. A [`Layout`](https://rux-lang.dev/docs/api/allocator/layout) that exists is valid. [`Layout::New`](https://rux-lang.dev/docs/api/allocator/layout#new) refuses an alignment that is not a power of two, or a size whose rounding would pass the end of the address space — so nothing downstream checks again. That second case is the one worth naming: it is how a request for a huge array becomes an allocation far smaller than the caller asked for. Use [`Layout::ForValue<T>()`](https://rux-lang.dev/docs/api/allocator/layout#for-value) or `Layout::ForArray<T>(count)` when storage follows a type; neither requires a sample value, so describing a move-only type consumes nothing. Four promises hold for every allocator here: - **The address satisfies the layout.** Always. - **The contents are undefined.** Nothing here zeroes; the page layer does, because the operating system does. - **A release must match its allocation** — the same pointer, and an equal layout. The allocator needs the size to know what it is taking back. - **A failure leaves everything alone.** A failed reallocation leaves the original block valid and still the caller's. Every operation returns a native fallible: `Allocate` and `Reallocate` give `(*var opaque) ! AllocError`, and `Deallocate` gives `! AllocError`. Every [`AllocError`](https://rux-lang.dev/docs/api/allocator/alloc-error) case is a failure, so a caller propagates with `?`, recovers with `catch`, and a result left unhandled is diagnosed as discarded. A release on a cleanup path that has nobody to report to says so explicitly with `allocator.Deallocate(block, layout) catch { else => {} };`. A zero-sized layout is legal and gives a non-null aligned address that nothing may be read from or written to, and which must still be released. That is cheaper than a null case every caller has to branch on, and it keeps an empty collection from being a special shape. [`Arena`](https://rux-lang.dev/docs/api/allocator/arena), [`Pool`](https://rux-lang.dev/docs/api/allocator/pool), [`FixedBuffer`](https://rux-lang.dev/docs/api/allocator/fixed-buffer), and [`Box<T>`](https://rux-lang.dev/docs/api/allocator/box) prohibit copying. The first two and the box use canonical destructors; the fixed buffer owns no storage but still cannot be copied because duplicate bump state could hand out overlapping blocks. Move an owner explicitly, for example `let destination <- source`. [`Box::Create`](https://rux-lang.dev/docs/api/allocator/box#create) returns `Box<T> ! AllocError`, destroying the value it was given when the allocator refuses. Destroying a box destroys its value before returning the allocation, while [`TryTake`](https://rux-lang.dev/docs/api/allocator/box#try-take) moves the value to the caller and leaves the box empty. [`Rc<T>`](https://rux-lang.dev/docs/api/allocator/shared#rc) and [`Arc<T>`](https://rux-lang.dev/docs/api/allocator/shared#arc) are the opposite: copying a handle shares its value and adds to a count, and the value is destroyed when the last handle goes. [`Rc`](https://rux-lang.dev/docs/api/allocator/shared#rc) counts with plain arithmetic for one thread, so it is declared `#Unsendable()` and cannot be a thread's context; [`Arc`](https://rux-lang.dev/docs/api/allocator/shared#arc) counts atomically, so its copies can be made and dropped on any thread. Both hand out the value for reading through `Get`, and for writing through `GetMutable` only while a single handle exists. There are no weak handles, so a cycle of handles is never freed. Canonical construction is [`SystemAllocator()`](https://rux-lang.dev/docs/api/allocator/system-allocator), `Arena(backing, blockSize)`, `Pool(backing, blocksPerChunk)`, and `FixedBuffer(storage, capacity)`. [`Layout::New`](https://rux-lang.dev/docs/api/allocator/layout#new) retains its name because it validates and returns `Layout?`, so `Layout::New(size, alignment) ?? fail AllocError::Unsupported` turns an unrepresentable layout into a failure. An [`Arena`](https://rux-lang.dev/docs/api/allocator/arena) hands out storage by advancing a pointer and takes it all back at once, which is the right shape whenever a program builds many small things whose lives end together. Blocks come from a backing allocator and each is twice the size of the last, so a long-lived arena stops going back to the system. `Reset` rewinds every allocation while keeping the largest block, so a second round of the same work asks the system for nothing. `BytesUsed` sums what every block has handed out, alignment padding included; the tail a block is left with when a request moves on to a new block is not counted. Borrow a concrete implementation directly for a short-lived interface view, for example `let view: &var Allocator = system`. Arena, pool, and fixed-buffer handles are storable adapters for allocators whose mutable state must stay with an owner. A handle stores a raw pointer because references cannot be fields or returned; it must not outlive or survive a move of its owner. An arena accepts a release rather than refusing one, so it can stand in for any allocator in generic code that releases what it takes. Ordinary releases do nothing; the most recent allocation is rewound, which is what lets a growing collection in an arena avoid wasting every earlier size it passed through. A [`FixedBuffer`](https://rux-lang.dev/docs/api/allocator/fixed-buffer) is the arena's shape without the arena's appetite: it hands out storage the caller already has, never asks anyone for more, and reports `OutOfMemory` when the buffer runs out. That makes it the allocator for the places where allocation must not happen — a fixed working set, a signal-safe path, a target with no allocator underneath at all. It owns nothing and has no destructor, but its copy operation is prohibited because copying its state while it is in use would hand out the same storage twice. A [`Pool`](https://rux-lang.dev/docs/api/allocator/pool) is for the other shape — many small values whose lives end at different times and in no particular order. A request is rounded up to one of five power-of-two classes, each keeping its own free list, so both allocation and release are a pointer swap with no search and no coalescing. A class that runs dry takes one chunk from a backing allocator and carves it, so the backing allocator sees one request per chunk rather than one per block. Rounding up is what pays for the speed: a 17-byte request occupies a 32-byte block, and those 15 bytes are not recoverable until the chunk is released. A request too large for the largest class, or needing a stricter alignment than a chunk is taken at, goes straight to the backing allocator — decided from the layout alone, so a release reaches the same conclusion as its allocation without the pool recording anything per block. [`SystemAllocator`](https://rux-lang.dev/docs/api/allocator/system-allocator) is page-granular, so a small allocation costs a whole page. It is the backing store for an arena or a pool rather than the allocator a program uses for many small values directly. ## Index ### Interfaces | Name | Summary | | ---------------------------------------------------------------- | ---------------------------------------- | | [`Allocator`](https://rux-lang.dev/docs/api/allocator/allocator) | The operations every allocator provides. | ### Types | Name | Summary | | --------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------- | | [`ArenaBlock`](https://rux-lang.dev/docs/api/allocator/arena#arena-block) | One block of arena storage, with the bookkeeping for what has been handed out of it. | | [`Arena`](https://rux-lang.dev/docs/api/allocator/arena) | An allocator that advances a pointer and reclaims everything at once. | | [`ArenaHandle`](https://rux-lang.dev/docs/api/allocator/arena#arena-handle) | A copyable interface adapter pointing at an arena. | | [`Box<T>`](https://rux-lang.dev/docs/api/allocator/box) | One heap-allocated value of `T`, owned by exactly one holder. | | [`AllocError`](https://rux-lang.dev/docs/api/allocator/alloc-error) | Why an allocation, reallocation or release did not do what was asked. | | [`FixedBuffer`](https://rux-lang.dev/docs/api/allocator/fixed-buffer) | An allocator that advances a pointer through storage it does not own. | | [`FixedBufferHandle`](https://rux-lang.dev/docs/api/allocator/fixed-buffer#fixed-buffer-handle) | A copyable interface adapter pointing at a [`FixedBuffer`](https://rux-lang.dev/docs/api/allocator/fixed-buffer). | | [`Layout`](https://rux-lang.dev/docs/api/allocator/layout) | A validated allocation request: a size, and the alignment its address must satisfy. | | [`PoolChunk`](https://rux-lang.dev/docs/api/allocator/pool#pool-chunk) | One chunk of pool storage, carved into blocks of a single class. | | [`Pool`](https://rux-lang.dev/docs/api/allocator/pool) | An allocator that serves small blocks from per-class free lists. | | [`PoolHandle`](https://rux-lang.dev/docs/api/allocator/pool#pool-handle) | A copyable interface adapter pointing at a pool. | | [`Rc<T>`](https://rux-lang.dev/docs/api/allocator/shared#rc) | A shared, counted handle to one value, for use on one thread. | | [`Arc<T>`](https://rux-lang.dev/docs/api/allocator/shared#arc) | A shared, counted handle to one value whose copies may live on different threads. | | [`SystemBlockHeader`](https://rux-lang.dev/docs/api/allocator/system-allocator#system-block-header) | What a system allocation records about itself, immediately before the address the caller sees. | | [`SystemAllocator`](https://rux-lang.dev/docs/api/allocator/system-allocator) | An allocator that asks the operating system for pages. | ### Functions | Name | Summary | | -------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- | | [`EmptyBlockAddress`](https://rux-lang.dev/docs/api/allocator/allocator#empty-block-address) | The address a zero-sized allocation reports, as a pointer. | | [`IsEmptyBlock`](https://rux-lang.dev/docs/api/allocator/allocator#is-empty-block) | Whether `block` is the address a zero-sized allocation reports. | | [`NaturalAlignment`](https://rux-lang.dev/docs/api/allocator/layout#natural-alignment) | The alignment a value of `size` bytes naturally wants. | | [`ClassIndexFor`](https://rux-lang.dev/docs/api/allocator/pool#class-index-for) | The class a layout belongs to, or [`PoolClassCount`](https://rux-lang.dev/docs/api/allocator/pool#pool-class-count) for a layout no class can serve. | ### Constants | Name | Summary | | --------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------- | | [`DefaultArenaBlockSize`](https://rux-lang.dev/docs/api/allocator/arena#default-arena-block-size) | The default payload of an arena's first block. | | [`ArenaBlockAlignment`](https://rux-lang.dev/docs/api/allocator/arena#arena-block-alignment) | The alignment every arena block is taken at, and so the strictest alignment an arena can serve from one. | | [`EmptyBlock`](https://rux-lang.dev/docs/api/allocator/allocator#empty-block) | The address a zero-sized allocation reports. | | [`PoolClassCount`](https://rux-lang.dev/docs/api/allocator/pool#pool-class-count) | How many size classes a pool serves. | | [`PoolSmallestClass`](https://rux-lang.dev/docs/api/allocator/pool#pool-smallest-class) | The smallest size class, and so the block a one-byte request occupies. | | [`PoolLargestClass`](https://rux-lang.dev/docs/api/allocator/pool#pool-largest-class) | The largest size class. | | [`PoolAlignment`](https://rux-lang.dev/docs/api/allocator/pool#pool-alignment) | The alignment every chunk is taken at, and so the strictest alignment a pooled block can satisfy. | | [`DefaultPoolBlocksPerChunk`](https://rux-lang.dev/docs/api/allocator/pool#default-pool-blocks-per-chunk) | How many blocks a chunk holds when the caller does not say. | | [`SystemBlockMagic`](https://rux-lang.dev/docs/api/allocator/system-allocator#system-block-magic) | The pattern a valid system block header carries. | # Allocator The operations every allocator provides. ```rux pub interface Allocator { func Allocate(layout: Layout) -> (*var opaque) ! AllocError; func Deallocate( block: *var opaque, layout: Layout ) -> ! AllocError; func Reallocate( block: *var opaque, oldLayout: Layout, newLayout: Layout ) -> (*var opaque) ! AllocError; } ``` Written as an interface so a generic can require it — `func Build<A: Allocator>(allocator: &var A)` borrows the caller's allocator and resolves calls at each instantiation with nothing dispatched at run time. No operation writes through its receiver: an implementation keeps its state behind a pointer, as the handles do, so a copied allocator value draws from the same storage and a read-only view may allocate. ## Requirements ### `Allocate` ```rux func Allocate(layout: Layout) -> (*var opaque) ! AllocError ``` Takes storage matching `layout` and reports where it landed. The address satisfies the layout's alignment. The contents are undefined. A zero-sized layout gives a non-null aligned address that nothing may be read from or written to. The storage is the caller's until [`Deallocate`](https://rux-lang.dev/docs/api/allocator/allocator#deallocate) takes it back with an equal layout. | Name | Type | Description | | -------- | -------- | ----------------------------- | | `layout` | `Layout` | the size and alignment wanted | **Returns**: the address of the storage, or why none was taken [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Allocator/Src/Contract.rux#L37){rel=""nofollow""} ### `Deallocate` ```rux func Deallocate( block: *var opaque, layout: Layout ) -> ! AllocError ``` Gives back storage that this allocator handed out. `block` must be an address this allocator returned, and `layout` must equal the layout it was given with. Reports `InvalidBlock` where the allocator can tell, and is undefined where it cannot. Every pointer into the block becomes invalid, and the storage may be handed to the next allocation at once. | Name | Type | Description | | -------- | ------------- | ---------------------------------- | | `block` | `*var opaque` | an address this allocator returned | | `layout` | `Layout` | the layout it was allocated with | **Returns**: nothing when the release was accepted, or why it was refused [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Allocator/Src/Contract.rux#L47){rel=""nofollow""} ### `Reallocate` ```rux func Reallocate( block: *var opaque, oldLayout: Layout, newLayout: Layout ) -> (*var opaque) ! AllocError ``` Changes the size of a block, preserving as much of its contents as both layouts hold. `block` and `oldLayout` describe the existing allocation; `newLayout` is what is wanted. The address reported may or may not be the address it was given, so the caller must use what comes back. On success the first `min(old, new)` bytes are preserved and the original block is gone. On failure the original block is untouched and still the caller's. A `newLayout` of size zero reports the shared empty address, exactly as [`Allocate`](https://rux-lang.dev/docs/api/allocator/allocator#allocate) would, so the result is always releasable with the layout it was asked for. The two layouts must have the same alignment. An allocator reports `Unsupported` rather than silently moving a block to a different alignment. The old pointer is invalid once this succeeds, whether or not the address changed. | Name | Type | Description | | ----------- | ------------- | ----------------------------------------------------- | | `block` | `*var opaque` | the existing allocation's address | | `oldLayout` | `Layout` | the layout `block` was allocated with | | `newLayout` | `Layout` | the layout wanted, which must have the same alignment | **Returns**: the address the block is at afterwards, or why it was not resized [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Allocator/Src/Contract.rux#L64){rel=""nofollow""} ## Implementations | Type | Summary | | ----------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------- | | [`ArenaHandle`](https://rux-lang.dev/docs/api/allocator/arena#arena-handle) | A copyable interface adapter pointing at an arena. | | [`FixedBufferHandle`](https://rux-lang.dev/docs/api/allocator/fixed-buffer#fixed-buffer-handle) | A copyable interface adapter pointing at a [`FixedBuffer`](https://rux-lang.dev/docs/api/allocator/fixed-buffer). | | [`PoolHandle`](https://rux-lang.dev/docs/api/allocator/pool#pool-handle) | A copyable interface adapter pointing at a pool. | | [`SystemAllocator`](https://rux-lang.dev/docs/api/allocator/system-allocator) | An allocator that asks the operating system for pages. | ## Related ### `EmptyBlock` ```rux pub const EmptyBlock: uint = 0xFFFFFFFFFFFF0000; ``` The address a zero-sized allocation reports. Not null, so a caller need not branch, and aligned to anything, so it satisfies every layout. Nothing may be read from or written to it: it is an address that exists rather than storage that does. Every allocator in this package returns exactly this for a zero-sized layout, which makes a zero-sized block recognizable and its release free. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Allocator/Src/Contract.rux#L73){rel=""nofollow""} ### `EmptyBlockAddress` ```rux pub func EmptyBlockAddress() -> *var opaque ``` The address a zero-sized allocation reports, as a pointer. Takes nothing and returns the same value every time. Cannot fail. Runs in constant time and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Allocator/Src/Contract.rux#L80){rel=""nofollow""} **Returns**: the address every zero-sized allocation reports ### `IsEmptyBlock` ```rux pub func IsEmptyBlock(block: *var opaque) -> bool ``` Whether `block` is the address a zero-sized allocation reports. `block` is read by value and never dereferenced. Cannot fail. Runs in constant time and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Allocator/Src/Contract.rux#L90){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------- | ------------- | --------------------------------------- | | `block` | `*var opaque` | the address to test, never dereferenced | **Returns**: whether it is the address a zero-sized allocation reports # AllocError Why an allocation, reallocation or release did not do what was asked. ```rux pub enum AllocError: uint8 { Unsupported = 1, OutOfMemory = 2, InvalidBlock = 3 } ``` ## Cases | Name | Value | Description | | -------------- | ----- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `Unsupported` | `1` | The layout cannot be served by this allocator at all: an alignment stricter than it can give, or a size it could never hold. A different allocator might succeed; retrying with this one will not. | | `OutOfMemory` | `2` | The allocator has no storage left. A smaller request might succeed, and so might this one later. | | `InvalidBlock` | `3` | The arguments do not describe an allocation this allocator handed out — a pointer it did not give, or a layout that does not match the one it was given with. This is a caller's mistake rather than a shortage. | ## Methods ### `IsTransient` ```rux pub func IsTransient(self: AllocError) -> bool ``` Whether a later attempt could plausibly succeed. `self` is borrowed. True only for `OutOfMemory`, which is a shortage rather than a mistake: `Unsupported` and `InvalidBlock` describe the request rather than the moment, so repeating either gives the same answer. **Returns**: whether asking again later could succeed [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Allocator/Src/Error.rux#L27){rel=""nofollow""} # Arena An allocator that advances a pointer and reclaims everything at once. ```rux pub struct Arena { // private fields } ``` Move-only, because it owns its blocks and explicitly prohibits copying. Pass its [`Handle`](https://rux-lang.dev/docs/api/allocator/arena#handle) where a storable [`Allocator`](https://rux-lang.dev/docs/api/allocator/allocator) adapter is needed. ## Constructors ### `Arena` ```rux pub func Arena(backing: Allocator, blockSize: uint) -> Arena ``` An arena that will take its storage from `backing`. `backing` is borrowed for the call and kept. `blockSize` is the payload of the first block; zero asks for the default. Cannot fail and allocates nothing: the first block is taken when the first request arrives, so an arena that is never used costs nothing. | Name | Type | Description | | ----------- | ----------- | ------------------------------------------------------------- | | `backing` | `Allocator` | where the arena's blocks come from | | `blockSize` | `uint` | the first block's payload in bytes; zero asks for the default | **Returns**: the arena, holding no block yet [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Allocator/Src/Arena.rux#L70){rel=""nofollow""} ## Methods ### `Handle` ```rux pub func Handle(self: *var Arena) -> ArenaHandle ``` A copyable interface adapter pointing at this arena. `self` stays the caller's. Allocations through the handle update this arena rather than copied state. Cannot fail. Runs in constant time and allocates nothing. The handle borrows the arena and must not outlive it, nor survive the arena being moved. Nothing here tracks that: a handle held past its arena's life points at released storage. **Returns**: a copyable adapter pointing at this arena [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Allocator/Src/Arena.rux#L88){rel=""nofollow""} ### `Reset` ```rux pub func Reset(self: &var Arena) ``` Rewinds every allocation, keeping the largest block for the next round of work. `self` is borrowed mutably. Every pointer the arena ever handed out becomes invalid, including any still held by a caller — an arena reclaims in one operation, which is what makes it fast and what makes this the one dangerous call on it. The kept block is the current one, which is the largest, so a second round of the same work runs without asking the system for anything. Runs in time proportional to the number of blocks. Nothing may be read from or written to any earlier allocation afterwards. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Allocator/Src/Arena.rux#L100){rel=""nofollow""} ### `BytesUsed` ```rux pub func BytesUsed(self: &Arena) -> uint ``` How many payload bytes the arena has handed out, summed over every block it holds. `self` is borrowed. Alignment padding between allocations counts as used. The tail a block was left with when a request did not fit in it and the arena moved on to a new block is not counted: nothing was handed out of it, and nothing will be until a [`Reset`](https://rux-lang.dev/docs/api/allocator/arena#reset). Runs in time proportional to the number of blocks and allocates nothing. **Returns**: how many payload bytes the arena's blocks have handed out [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Allocator/Src/Arena.rux#L123){rel=""nofollow""} ### `BlockCount` ```rux pub func BlockCount(self: &Arena) -> uint ``` How many blocks the arena holds. `self` is borrowed. Zero before the first request. **Returns**: how many blocks the arena holds [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Allocator/Src/Arena.rux#L137){rel=""nofollow""} ## Destructor ```rux func ~Arena(self: &var Arena) ``` Gives every block back to the backing allocator. Runs when the arena's life ends. Every pointer the arena handed out becomes invalid. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Allocator/Src/Arena.rux#L190){rel=""nofollow""} ## Related ### `DefaultArenaBlockSize` ```rux pub const DefaultArenaBlockSize: uint = 4096; ``` The default payload of an arena's first block. One page on every supported system. Each later block doubles, so an arena that keeps growing stops asking the system after a handful of requests. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Allocator/Src/Arena.rux#L21){rel=""nofollow""} ### `ArenaBlockAlignment` ```rux pub const ArenaBlockAlignment: uint = 16; ``` The alignment every arena block is taken at, and so the strictest alignment an arena can serve from one. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Allocator/Src/Arena.rux#L25){rel=""nofollow""} ### `ArenaBlock` ```rux pub struct ArenaBlock { // private fields } ``` One block of arena storage, with the bookkeeping for what has been handed out of it. Never constructed by a caller. The payload follows the header immediately, and `capacity` counts only the payload. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Allocator/Src/Arena.rux#L31){rel=""nofollow""} ### `ArenaHandle` ```rux pub struct ArenaHandle { // private fields } ``` A copyable interface adapter pointing at an arena. A handle is cheap to copy and may be stored wherever an allocator is wanted, but it does not own the arena. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Allocator/Src/Arena.rux#L208){rel=""nofollow""} **Implements Allocator** `ArenaHandle` conforms to [`Allocator`](https://rux-lang.dev/docs/api/allocator/allocator). #### `Allocate` ```rux pub func Allocate( self: &ArenaHandle, layout: Layout ) -> (*var opaque) ! AllocError ``` Takes storage matching `layout` by advancing the arena's pointer. `result` receives the address when this reports `None`. A zero-sized layout gives the shared empty block and consumes none of the arena. Takes a new block when the current one cannot serve the request, which is the only path here that can fail. The storage lives until the arena is reset or destroyed, whichever comes first, and not one moment longer. | Name | Type | Description | | -------- | -------- | ----------------------------- | | `layout` | `Layout` | the size and alignment wanted | **Returns**: the address of the storage, or why none was taken [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Allocator/Src/Arena.rux#L222){rel=""nofollow""} #### `Deallocate` ```rux pub func Deallocate( self: &ArenaHandle, block: *var opaque, layout: Layout ) -> ! AllocError ``` Accepts a release and reclaims only what it can. An arena reclaims in one operation, so an ordinary release has nothing to give back and reports `None` having done nothing. The exception is the most recent allocation, whose space is rewound — which is what lets a growing collection in an arena not waste every earlier size it passed through. Accepting rather than refusing is deliberate: it lets an arena stand in for any allocator in generic code that releases what it takes. | Name | Type | Description | | -------- | ------------- | ---------------------------------- | | `block` | `*var opaque` | an address this allocator returned | | `layout` | `Layout` | the layout it was allocated with | **Returns**: nothing when the release was accepted, or why it was refused [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Allocator/Src/Arena.rux#L247){rel=""nofollow""} #### `Reallocate` ```rux pub func Reallocate( self: &ArenaHandle, block: *var opaque, oldLayout: Layout, newLayout: Layout ) -> (*var opaque) ! AllocError ``` Grows or shrinks a block, extending the most recent allocation in place where it can. The two layouts must share an alignment. Growing the most recent allocation extends it without moving when the current block has room; anything else takes new storage and copies, leaving the old space behind for the next reset to reclaim. Shrinking to a zero-sized layout releases the block and reports the shared empty address rather than the one it rewound off of, so the result is releasable with the layout it was asked for. | Name | Type | Description | | ----------- | ------------- | ----------------------------------------------------- | | `block` | `*var opaque` | the existing allocation's address | | `oldLayout` | `Layout` | the layout `block` was allocated with | | `newLayout` | `Layout` | the layout wanted, which must have the same alignment | **Returns**: the address the block is at afterwards, or why it was not resized [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Allocator/Src/Arena.rux#L272){rel=""nofollow""} # Box\<T> One heap-allocated value of `T`, owned by exactly one holder. ```rux pub struct Box<T> { // private fields } ``` Move-only: its copy operation is prohibited and [`~Box`](https://rux-lang.dev/docs/api/allocator/box#destructor) releases its allocation. Transfer one with `<-`; the source is then moved-out and reading it is rejected while compiling rather than at run time. The storage is released when the box is destroyed, at whichever scope exit, return, `break`, `continue` or overwriting assignment the value's life ends at. ## Type parameters | Name | Description | | ---- | ---------------------------- | | `T` | the type the box owns one of | ## Associated functions ### `Create` ```rux pub func Create( allocator: Allocator, value: T ) -> Box<T> ! AllocError ``` Puts `value` on the heap and hands back the box that owns it. `allocator` is borrowed for the call and kept in the box. `value` is consumed: on success the box owns it, and on failure it is destroyed rather than leaked. Runs in whatever time the allocator takes, and allocates exactly one block. | Name | Type | Description | | ----------- | ----------- | ---------------------------- | | `allocator` | `Allocator` | where the storage comes from | | `value` | `T` | the value to move into it | **Returns**: the box, or why the allocator refused [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Allocator/Src/Box.rux#L44){rel=""nofollow""} ## Methods ### `Get` ```rux pub func Get(self: &Box<T>) -> *var T ``` The value this box holds. `self` is borrowed and stays the caller's; the pointer borrows the box's storage and is valid only while the box is. Returns null for a box whose value has been taken out. Cannot fail. Runs in constant time and allocates nothing. The pointer dies with the box. Holding it past a move of the box is holding a pointer into released storage. **Returns**: the address of the held value, or null when the box is empty [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Allocator/Src/Box.rux#L59){rel=""nofollow""} ### `IsEmpty` ```rux pub func IsEmpty(self: &Box<T>) -> bool ``` Whether this box still holds a value. `self` is borrowed. False only for a box whose value [`TryTake`](https://rux-lang.dev/docs/api/allocator/box#try-take) has moved out, which is a box that owns nothing and releases nothing. Cannot fail. Runs in constant time and allocates nothing. **Returns**: whether the box holds nothing [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Allocator/Src/Box.rux#L69){rel=""nofollow""} ### `TryTake` ```rux pub func TryTake( self: &var Box<T>, destination: *var T ) -> bool ``` Moves the value out of the box, leaving the box empty, and releases the storage. `self` is borrowed mutably and is left empty. `destination` receives the value and must not be null; it is left unwritten when this reports `false`, which happens only for a box that is already empty. The storage goes back to the allocator here rather than at the box's destruction, so a caller taking the value out does not have to keep the box alive afterwards. Runs in whatever time the allocator takes. | Name | Type | Description | | ------------- | -------- | ----------------------- | | `destination` | `*var T` | receives the held value | **Returns**: whether there was a value to take [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Allocator/Src/Box.rux#L82){rel=""nofollow""} ## Destructor ```rux func ~Box(self: &var Box<T>) ``` Destroys the value and releases its storage, if the box still holds any. Runs when the box's life ends, and does nothing for a box whose value was taken out. A box that was moved away is not destroyed where it used to live, so the storage is released exactly once. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Allocator/Src/Box.rux#L98){rel=""nofollow""} # FixedBuffer An allocator that advances a pointer through storage it does not own. ```rux pub struct FixedBuffer { // private fields } ``` Owns no storage and has no destructor, but prohibits copying because duplicated bump state could hand the same bytes to two callers. Use [`Handle`](https://rux-lang.dev/docs/api/allocator/fixed-buffer#handle) when a storable [`Allocator`](https://rux-lang.dev/docs/api/allocator/allocator) adapter is needed. ## Constructors ### `FixedBuffer` ```rux pub func FixedBuffer( storage: *var opaque, capacity: uint ) -> FixedBuffer ``` An allocator over `capacity` bytes at `storage`. `storage` is borrowed and kept; nothing is copied and nothing is taken ownership of. A `capacity` of zero, or a null `storage`, gives an allocator that refuses every request with `OutOfMemory` — which is a usable allocator rather than an error, and is what a caller testing exhaustion wants. Cannot fail. Runs in constant time and allocates nothing. The storage must stay valid and untouched by anything else for as long as this allocator or any handle to it is used. Nothing here tracks that. | Name | Type | Description | | ---------- | ------------- | --------------------------------- | | `storage` | `*var opaque` | the caller's bytes to hand out of | | `capacity` | `uint` | how many bytes `storage` holds | **Returns**: the buffer, having handed out nothing [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Allocator/Src/FixedBuffer.rux#L43){rel=""nofollow""} ## Methods ### `Handle` ```rux pub func Handle(self: *var FixedBuffer) -> FixedBufferHandle ``` A copyable interface adapter pointing at this allocator. `self` is borrowed mutably and stays the caller's. Everything allocated through the handle advances this allocator's state rather than a copy of it, which is the whole reason the handle exists. The handle borrows the allocator and must not outlive it or survive it being moved. **Returns**: a copyable adapter pointing at this buffer [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Allocator/Src/FixedBuffer.rux#L59){rel=""nofollow""} ### `Reset` ```rux pub func Reset(self: &var FixedBuffer) ``` Rewinds every allocation, making the whole buffer available again. `self` is borrowed mutably. Every pointer this allocator handed out becomes invalid. Cannot fail. Runs in constant time and allocates nothing. Nothing may be read from or written to any earlier allocation afterwards. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Allocator/Src/FixedBuffer.rux#L68){rel=""nofollow""} ### `BytesUsed` ```rux pub func BytesUsed(self: &FixedBuffer) -> uint ``` How many bytes have been handed out, including alignment padding. `self` is borrowed. **Returns**: how many bytes have been handed out [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Allocator/Src/FixedBuffer.rux#L77){rel=""nofollow""} ### `BytesRemaining` ```rux pub func BytesRemaining(self: &FixedBuffer) -> uint ``` How many bytes remain, before any alignment padding the next request needs. `self` is borrowed. A request of exactly this size succeeds only when it needs no padding. **Returns**: how many bytes are left to hand out [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Allocator/Src/FixedBuffer.rux#L85){rel=""nofollow""} ## Related ### `FixedBufferHandle` ```rux pub struct FixedBufferHandle { // private fields } ``` A copyable interface adapter pointing at a [`FixedBuffer`](https://rux-lang.dev/docs/api/allocator/fixed-buffer). [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Allocator/Src/FixedBuffer.rux#L92){rel=""nofollow""} **Implements Allocator** `FixedBufferHandle` conforms to [`Allocator`](https://rux-lang.dev/docs/api/allocator/allocator). #### `Allocate` ```rux pub func Allocate( self: &FixedBufferHandle, layout: Layout ) -> (*var opaque) ! AllocError ``` Takes storage matching `layout` from the buffer. `result` receives the address when this reports `None`. A zero-sized layout gives the shared empty block and consumes nothing. Reports `OutOfMemory` when what remains cannot hold the request, counting the padding its alignment needs -- so a request the size of [`BytesRemaining`](https://rux-lang.dev/docs/api/allocator/fixed-buffer#bytes-remaining) can still fail when it has to be aligned first. Runs in constant time and allocates nothing beyond the buffer. The storage lives until the allocator is reset, and no longer. | Name | Type | Description | | -------- | -------- | ----------------------------- | | `layout` | `Layout` | the size and alignment wanted | **Returns**: the address of the storage, or why none was taken [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Allocator/Src/FixedBuffer.rux#L108){rel=""nofollow""} #### `Deallocate` ```rux pub func Deallocate( self: &FixedBufferHandle, block: *var opaque, layout: Layout ) -> ! AllocError ``` Accepts a release and rewinds only the most recent allocation. Everything else is reclaimed by `Reset` rather than one block at a time, so an ordinary release reports `None` having done nothing. Accepting rather than refusing lets this allocator stand in for any other in generic code that releases what it takes. | Name | Type | Description | | -------- | ------------- | ---------------------------------- | | `block` | `*var opaque` | an address this allocator returned | | `layout` | `Layout` | the layout it was allocated with | **Returns**: nothing when the release was accepted, or why it was refused [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Allocator/Src/FixedBuffer.rux#L135){rel=""nofollow""} #### `Reallocate` ```rux pub func Reallocate( self: &FixedBufferHandle, block: *var opaque, oldLayout: Layout, newLayout: Layout ) -> (*var opaque) ! AllocError ``` Grows or shrinks a block, extending the most recent allocation in place where the buffer has room. The two layouts must share an alignment. Anything that is not the most recent allocation takes new storage and copies, leaving the old space behind until the next reset. Shrinking to a zero-sized layout releases the block and reports the shared empty address rather than the one it rewound off of, so the result is releasable with the layout it was asked for. | Name | Type | Description | | ----------- | ------------- | ----------------------------------------------------- | | `block` | `*var opaque` | the existing allocation's address | | `oldLayout` | `Layout` | the layout `block` was allocated with | | `newLayout` | `Layout` | the layout wanted, which must have the same alignment | **Returns**: the address the block is at afterwards, or why it was not resized [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Allocator/Src/FixedBuffer.rux#L158){rel=""nofollow""} # Layout A validated allocation request: a size, and the alignment its address must satisfy. ```rux pub struct Layout { pub size: uint; pub alignment: uint; } ``` Copy and owns nothing. Every instance is valid, because [`New`](https://rux-lang.dev/docs/api/allocator/layout#new) refuses to build an invalid one: the alignment is a power of two, and the size rounded up to that alignment does not pass the end of the address space. A size of zero is valid and is not an allocation of nothing — see `Allocate` for what an allocator does with it. ## Fields | Name | Type | Description | | ----------- | ------ | ----------------------------------------------------------------------- | | `size` | `uint` | The number of bytes asked for, before any rounding. | | `alignment` | `uint` | The alignment the address must be a multiple of. Always a power of two. | ## Associated functions ### `ForValue` ```rux pub func ForValue<T>() -> Layout ``` A layout for one value of `T`, using its actual size and alignment. No value is copied or consumed. Cannot fail, runs in constant time, and allocates nothing. | Type parameter | Description | | -------------- | -------------------- | | `T` | the type to describe | **Returns**: `T`'s own size and alignment [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Allocator/Src/Layout.rux#L31){rel=""nofollow""} ### `ForArray` ```rux pub func ForArray<T>(count: uint) -> Layout? ``` A layout for `count` consecutive values of `T`, or absent when the size would overflow. No value is copied or consumed. A zero count describes empty storage at `T`'s alignment. Runs in constant time and allocates nothing. | Type parameter | Description | | -------------- | ---------------- | | `T` | the element type | | Name | Type | Description | | ------- | ------ | ----------------- | | `count` | `uint` | how many elements | **Returns**: the array layout, or `none` if its size cannot be represented [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Allocator/Src/Layout.rux#L42){rel=""nofollow""} ### `New` ```rux pub func New(size: uint, alignment: uint) -> Layout? ``` A layout for `size` bytes at `alignment`, or nothing when the pair cannot be one. `size` and `alignment` are read by value; the layout is returned by copy. Reports `none` when `alignment` is zero or not a power of two, and when rounding `size` up to `alignment` would pass the end of the address space — which is the case that turns into an allocation far smaller than the caller asked for if it is not caught here. Runs in constant time and allocates nothing. | Name | Type | Description | | ----------- | ------ | ---------------------------------------------- | | `size` | `uint` | how many bytes are wanted | | `alignment` | `uint` | the boundary the address must be a multiple of | **Returns**: the layout, or `none` when `alignment` is not a usable power of two [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Allocator/Src/Layout.rux#L58){rel=""nofollow""} ### `ForBytes` ```rux pub func ForBytes(size: uint) -> Layout? ``` A layout for `size` bytes at the alignment a machine word wants. `size` is read by value. Reports `none` only when rounding `size` up would pass the end of the address space, since the alignment is known good. This is the layout for storage whose contents are bytes rather than a typed value: an allocation aligned to a word suits anything the machine loads in one instruction. Runs in constant time and allocates nothing. | Name | Type | Description | | ------ | ------ | ------------------------- | | `size` | `uint` | how many bytes are wanted | **Returns**: a layout of that size at its natural alignment, or `none` when there is none [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Allocator/Src/Layout.rux#L74){rel=""nofollow""} ## Methods ### `PaddedSize` ```rux pub func PaddedSize(self: &Layout) -> uint ``` The size this layout occupies once rounded up to its own alignment. `self` is borrowed. This is the stride between two of these laid out one after another, and is what an arena advances by. Cannot overflow, because [`New`](https://rux-lang.dev/docs/api/allocator/layout#new) refused every size for which it would. Runs in constant time and allocates nothing. **Returns**: the size rounded up to a whole number of alignments [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Allocator/Src/Layout.rux#L85){rel=""nofollow""} ### `IsSatisfiedBy` ```rux pub func IsSatisfiedBy(self: &Layout, address: uint) -> bool ``` Whether `address` satisfies this layout's alignment. `self` is borrowed and `address` is read by value and never dereferenced. Cannot fail. Runs in constant time and allocates nothing. | Name | Type | Description | | --------- | ------ | ------------------- | | `address` | `uint` | the address to test | **Returns**: whether `address` meets this layout's alignment [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Allocator/Src/Layout.rux#L97){rel=""nofollow""} ## Operators ### `==` ```rux pub func ==(self: &Layout, other: Layout) -> bool ``` Whether two layouts ask for the same thing. `self` is borrowed and `other` is read by value. | Name | Type | Description | | ------- | -------- | ----------------------------- | | `other` | `Layout` | the layout to compare against | **Returns**: whether both the size and the alignment match [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Allocator/Src/Layout.rux#L106){rel=""nofollow""} ### `!=` ```rux pub func !=(self: &Layout, other: Layout) -> bool ``` Whether two layouts ask for different things. | Name | Type | Description | | ------- | -------- | ----------------------------- | | `other` | `Layout` | the layout to compare against | **Returns**: whether either the size or the alignment differs [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Allocator/Src/Layout.rux#L114){rel=""nofollow""} ## Related ### `NaturalAlignment` ```rux pub func NaturalAlignment(size: uint) -> uint ``` The alignment a value of `size` bytes naturally wants. `size` is read by value. Returns the largest power of two that divides a value of this size, capped at a machine word, which is what every supported target's ABI requires of an ordinary value. A size of zero reports one, since a zero-sized value has nothing to align. Runs in time proportional to the word size and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Allocator/Src/Layout.rux#L127){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------ | ------ | ----------------------------------- | | `size` | `uint` | the size to choose an alignment for | **Returns**: the largest useful power-of-two alignment for that size # Pool An allocator that serves small blocks from per-class free lists. ```rux pub struct Pool { // private fields } ``` Move-only, because it owns its chunks. Pass it to something expecting an [`Allocator`](https://rux-lang.dev/docs/api/allocator/allocator) through [`Handle`](https://rux-lang.dev/docs/api/allocator/pool#handle), which borrows rather than moves. ## Constructors ### `Pool` ```rux pub func Pool( backing: Allocator, blocksPerChunk: uint ) -> Pool ``` A pool that will take its chunks from `backing`. `backing` is borrowed for the call and kept. `blocksPerChunk` is how many blocks each chunk is carved into; zero asks for the default. Cannot fail and allocates nothing: the first chunk is taken when the first request arrives, so a pool that is never used costs nothing. | Name | Type | Description | | ---------------- | ----------- | -------------------------------------------------------------- | | `backing` | `Allocator` | where the pool's chunks come from | | `blocksPerChunk` | `uint` | how many blocks a chunk carves into; zero asks for the default | **Returns**: the pool, holding no chunk yet [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Allocator/Src/Pool.rux#L92){rel=""nofollow""} ## Methods ### `Handle` ```rux pub func Handle(self: *var Pool) -> PoolHandle ``` A copyable interface adapter pointing at this pool. `self` stays the caller's. Allocations through the handle update this pool rather than copied state. Cannot fail. Runs in constant time and allocates nothing. The handle borrows the pool and must not outlive it, nor survive the pool being moved. **Returns**: a copyable adapter pointing at this pool [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Allocator/Src/Pool.rux#L110){rel=""nofollow""} ### `Reset` ```rux pub func Reset(self: &var Pool) ``` Takes every pooled block back at once, keeping the chunks for the next round of work. `self` is borrowed mutably. Every pooled pointer the pool handed out becomes invalid, including any a caller still holds. The chunks are kept and carved again, so a second round of the same work asks the backing allocator for nothing. Blocks that went to the backing allocator because they were too large or too strictly aligned are not touched, and are still the caller's to release. Runs in time proportional to the number of blocks. Cannot fail. Nothing may be read from or written to any pooled allocation afterwards. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Allocator/Src/Pool.rux#L123){rel=""nofollow""} ### `LiveBlocks` ```rux pub func LiveBlocks(self: &Pool) -> uint ``` How many pooled blocks are currently handed out. `self` is borrowed. Blocks that went to the backing allocator are not counted, because the pool does not track them. **Returns**: how many blocks are currently handed out [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Allocator/Src/Pool.rux#L150){rel=""nofollow""} ### `ChunkCount` ```rux pub func ChunkCount(self: &Pool) -> uint ``` How many chunks the pool has taken from its backing allocator. `self` is borrowed. Zero before the first request. **Returns**: how many chunks the pool holds [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Allocator/Src/Pool.rux#L158){rel=""nofollow""} ### `ClassSize` ```rux pub func ClassSize(self: &Pool, index: uint) -> uint ``` The block size of class `index`, or zero for an index past the last class. `self` is borrowed. Classes run from [`PoolSmallestClass`](https://rux-lang.dev/docs/api/allocator/pool#pool-smallest-class) to [`PoolLargestClass`](https://rux-lang.dev/docs/api/allocator/pool#pool-largest-class), doubling. | Name | Type | Description | | ------- | ------ | ---------------- | | `index` | `uint` | which size class | **Returns**: the block size that class serves [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Allocator/Src/Pool.rux#L167){rel=""nofollow""} ## Destructor ```rux func ~Pool(self: &var Pool) ``` Gives every chunk back to the backing allocator. Runs when the pool's life ends. Every pooled pointer the pool handed out becomes invalid. Blocks that went to the backing allocator directly are not released here and are still the caller's. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Allocator/Src/Pool.rux#L219){rel=""nofollow""} ## Related ### `PoolClassCount` ```rux pub const PoolClassCount: uint = 5; ``` How many size classes a pool serves. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Allocator/Src/Pool.rux#L23){rel=""nofollow""} ### `PoolSmallestClass` ```rux pub const PoolSmallestClass: uint = 16; ``` The smallest size class, and so the block a one-byte request occupies. Large enough to hold the link a free block stores in its own storage, which is what lets a free list cost nothing beyond the blocks already on it. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Allocator/Src/Pool.rux#L29){rel=""nofollow""} ### `PoolLargestClass` ```rux pub const PoolLargestClass: uint = 256; ``` The largest size class. A request past this goes to the backing allocator instead. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Allocator/Src/Pool.rux#L33){rel=""nofollow""} ### `PoolAlignment` ```rux pub const PoolAlignment: uint = 16; ``` The alignment every chunk is taken at, and so the strictest alignment a pooled block can satisfy. Every class is a multiple of this, so every block carved from a chunk is aligned to it as well. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Allocator/Src/Pool.rux#L38){rel=""nofollow""} ### `DefaultPoolBlocksPerChunk` ```rux pub const DefaultPoolBlocksPerChunk: uint = 32; ``` How many blocks a chunk holds when the caller does not say. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Allocator/Src/Pool.rux#L42){rel=""nofollow""} ### `PoolChunk` ```rux pub struct PoolChunk { // private fields } ``` One chunk of pool storage, carved into blocks of a single class. Never constructed by a caller. The blocks follow the header, and the header records what the chunk was taken with so that releasing or re-carving it needs nothing else. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Allocator/Src/Pool.rux#L48){rel=""nofollow""} ### `PoolHandle` ```rux pub struct PoolHandle { // private fields } ``` A copyable interface adapter pointing at a pool. A handle is cheap to copy and may be stored wherever an allocator is wanted, but it does not own the pool. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Allocator/Src/Pool.rux#L241){rel=""nofollow""} **Implements Allocator** `PoolHandle` conforms to [`Allocator`](https://rux-lang.dev/docs/api/allocator/allocator). #### `Allocate` ```rux pub func Allocate( self: &PoolHandle, layout: Layout ) -> (*var opaque) ! AllocError ``` Takes a block of the smallest class that holds `layout`. `result` receives the address when this reports `None`. A zero-sized layout gives the shared empty block. A layout too large for the largest class, or needing an alignment stricter than [`PoolAlignment`](https://rux-lang.dev/docs/api/allocator/pool#pool-alignment), is passed to the backing allocator unchanged. Takes a chunk when the class has no free block, which is the only path here that can fail. Otherwise runs in constant time. The block lives until it is released, the pool is reset, or the pool is destroyed. | Name | Type | Description | | -------- | -------- | ----------------------------- | | `layout` | `Layout` | the size and alignment wanted | **Returns**: the address of the storage, or why none was taken [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Allocator/Src/Pool.rux#L257){rel=""nofollow""} #### `Deallocate` ```rux pub func Deallocate( self: &PoolHandle, block: *var opaque, layout: Layout ) -> ! AllocError ``` Puts a block back on the free list of the class its layout names. `layout` must equal the one the block was taken with, which is what tells the pool whether the block is its own or the backing allocator's. A block that went to the backing allocator is released there. Runs in constant time, and cannot fail for a pooled block. The block may be handed to the next allocation of its class at once. | Name | Type | Description | | -------- | ------------- | ---------------------------------- | | `block` | `*var opaque` | an address this allocator returned | | `layout` | `Layout` | the layout it was allocated with | **Returns**: nothing when the release was accepted, or why it was refused [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Allocator/Src/Pool.rux#L284){rel=""nofollow""} #### `Reallocate` ```rux pub func Reallocate( self: &PoolHandle, block: *var opaque, oldLayout: Layout, newLayout: Layout ) -> (*var opaque) ! AllocError ``` Changes the size of a block, which costs nothing when both sizes land in the same class. The two layouts must share an alignment. A block whose new size fits the class it already occupies comes back unmoved — growing a 20-byte allocation to 30 does not touch storage at all. Anything else takes a new block, copies, and releases the old one. | Name | Type | Description | | ----------- | ------------- | ----------------------------------------------------- | | `block` | `*var opaque` | the existing allocation's address | | `oldLayout` | `Layout` | the layout `block` was allocated with | | `newLayout` | `Layout` | the layout wanted, which must have the same alignment | **Returns**: the address the block is at afterwards, or why it was not resized [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Allocator/Src/Pool.rux#L308){rel=""nofollow""} ### `ClassIndexFor` ```rux pub func ClassIndexFor(layout: Layout) -> uint ``` The class a layout belongs to, or [`PoolClassCount`](https://rux-lang.dev/docs/api/allocator/pool#pool-class-count) for a layout no class can serve. `layout` is read by value. A size past [`PoolLargestClass`](https://rux-lang.dev/docs/api/allocator/pool#pool-largest-class), or an alignment stricter than [`PoolAlignment`](https://rux-lang.dev/docs/api/allocator/pool#pool-alignment), has no class, and the caller passes it to the backing allocator instead. The answer depends only on the layout, which is what lets a release reach the same conclusion as the allocation it matches without the pool recording anything per block. Cannot fail. Runs in time proportional to the number of classes and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Allocator/Src/Pool.rux#L343){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | -------- | ----------------------- | | `layout` | `Layout` | the request to classify | **Returns**: the index of the class that serves it, or the class count when none does # Shared ownership Reference-counted handles: [`Rc`](https://rux-lang.dev/docs/api/allocator/shared#rc) within one thread and [`Arc`](https://rux-lang.dev/docs/api/allocator/shared#arc) across threads. ## `Rc<T>` ```rux pub struct Rc<T> { // private fields } ``` A shared, counted handle to one value, for use on one thread. Copying a handle shares the value. Its count is not atomic, so a handle is not `Sendable`: a thread's context cannot hold one. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Allocator/Src/Shared.rux#L30){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | ---------------- | | `T` | the value's type | **Associated functions** ### `Create` ```rux pub func Create( allocator: Allocator, value: T ) -> Rc<T> ! AllocError ``` The first handle to `value`, moved onto the heap. | Name | Type | Description | | ----------- | ----------- | ---------------------------- | | `allocator` | `Allocator` | where the storage comes from | | `value` | `T` | the value to share | **Returns**: the handle, or why there was no storage; the value is destroyed then [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Allocator/Src/Shared.rux#L50){rel=""nofollow""} **Methods** ### `Get` ```rux pub func Get(self: &Rc<T>) -> *T ``` The shared value, for reading. **Returns**: a pointer to it, valid while any handle exists [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Allocator/Src/Shared.rux#L59){rel=""nofollow""} ### `GetMutable` ```rux pub func GetMutable(self: &var Rc<T>) -> (*var T)? ``` The value for writing, while this is the only handle to it. **Returns**: a pointer to it, or `none` while other handles share it [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Allocator/Src/Shared.rux#L66){rel=""nofollow""} ### `Count` ```rux pub func Count(self: &Rc<T>) -> uint ``` How many handles share the value. **Returns**: the count [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Allocator/Src/Shared.rux#L74){rel=""nofollow""} ### `SameAs` ```rux pub func SameAs(self: &Rc<T>, other: &Rc<T>) -> bool ``` Whether `other` shares the same value, rather than an equal one. | Name | Type | Description | | ------- | -------- | ---------------- | | `other` | `&Rc<T>` | the other handle | **Returns**: whether both point at one value [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Allocator/Src/Shared.rux#L82){rel=""nofollow""} **Operators** ### `=` ```rux pub func =(self: &var Rc<T>, other: &Rc<T>) ``` Another handle to the same value, adding one to the count. | Name | Type | Description | | ------- | -------- | ------------------ | | `other` | `&Rc<T>` | the handle to copy | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Allocator/Src/Shared.rux#L39){rel=""nofollow""} **Destructor** ### `~Rc` ```rux func ~Rc(self: &var Rc<T>) ``` [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Allocator/Src/Shared.rux#L86){rel=""nofollow""} ## `Arc<T>` ```rux pub struct Arc<T> { // private fields } ``` A shared, counted handle to one value whose copies may live on different threads. Copying a handle shares the value, and the count is kept with atomic operations. The value is only read through it, so a value that changes while shared needs its own synchronization, such as a `Sync::Mutex`. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Allocator/Src/Shared.rux#L103){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | ---------------- | | `T` | the value's type | **Associated functions** ### `Create` ```rux pub func Create( allocator: Allocator, value: T ) -> Arc<T> ! AllocError ``` The first handle to `value`, moved onto the heap. | Name | Type | Description | | ----------- | ----------- | ----------------------------------------------------------------------------------- | | `allocator` | `Allocator` | where the storage comes from, which must be usable from every thread a copy reaches | | `value` | `T` | the value to share | **Returns**: the handle, or why there was no storage; the value is destroyed then [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Allocator/Src/Shared.rux#L123){rel=""nofollow""} **Methods** ### `Get` ```rux pub func Get(self: &Arc<T>) -> *T ``` The shared value, for reading. **Returns**: a pointer to it, valid while any handle exists [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Allocator/Src/Shared.rux#L132){rel=""nofollow""} ### `GetMutable` ```rux pub func GetMutable(self: &var Arc<T>) -> (*var T)? ``` The value for writing, while this is the only handle to it. **Returns**: a pointer to it, or `none` while other handles share it [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Allocator/Src/Shared.rux#L139){rel=""nofollow""} ### `Count` ```rux pub func Count(self: &Arc<T>) -> uint ``` How many handles share the value, at some moment while this one existed; another thread may change it. **Returns**: the count [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Allocator/Src/Shared.rux#L147){rel=""nofollow""} ### `SameAs` ```rux pub func SameAs(self: &Arc<T>, other: &Arc<T>) -> bool ``` Whether `other` shares the same value, rather than an equal one. | Name | Type | Description | | ------- | --------- | ---------------- | | `other` | `&Arc<T>` | the other handle | **Returns**: whether both point at one value [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Allocator/Src/Shared.rux#L155){rel=""nofollow""} **Operators** ### `=` ```rux pub func =(self: &var Arc<T>, other: &Arc<T>) ``` Another handle to the same value, adding one to the count atomically. | Name | Type | Description | | ------- | --------- | ------------------ | | `other` | `&Arc<T>` | the handle to copy | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Allocator/Src/Shared.rux#L112){rel=""nofollow""} **Destructor** ### `~Arc` ```rux func ~Arc(self: &var Arc<T>) ``` [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Allocator/Src/Shared.rux#L159){rel=""nofollow""} # SystemAllocator An allocator that asks the operating system for pages. ```rux pub struct SystemAllocator { // private fields } ``` Carries no state: every instance behaves identically, and one may be created wherever it is needed rather than passed around. It is `Copy` for that reason. Page-granular, so a small allocation costs a whole page. Use it as the backing store for an arena or a pool rather than for many small values directly. ## Constructors ### `SystemAllocator` ```rux pub func SystemAllocator() -> SystemAllocator ``` Constructs a stateless system allocator. The result is structural and copyable. Borrow it as `&var Allocator` when a temporary interface view is sufficient; no adapter or owning conversion is required. **Returns**: the allocator, which holds no state of its own [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Allocator/Src/System.rux#L56){rel=""nofollow""} ## Implements Allocator `SystemAllocator` conforms to [`Allocator`](https://rux-lang.dev/docs/api/allocator/allocator). ### `Allocate` ```rux pub func Allocate( self: &SystemAllocator, layout: Layout ) -> (*var opaque) ! AllocError ``` Takes storage matching `layout` from the operating system. `result` receives the address when this reports `None`. A zero-sized layout gives the shared empty block and takes nothing from the system. Reports `Unsupported` for an alignment larger than the total the request would occupy, `OutOfMemory` when the system refuses. The storage is the caller's until [`Deallocate`](https://rux-lang.dev/docs/api/allocator/system-allocator#deallocate) takes it back with an equal layout. | Name | Type | Description | | -------- | -------- | ----------------------------- | | `layout` | `Layout` | the size and alignment wanted | **Returns**: the address of the storage, or why none was taken [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Allocator/Src/System.rux#L72){rel=""nofollow""} ### `Deallocate` ```rux pub func Deallocate( self: &SystemAllocator, block: *var opaque, layout: Layout ) -> ! AllocError ``` Gives the storage behind `block` back to the operating system. `layout` must equal the one the block was allocated with. Reports `InvalidBlock` when the header is not there or does not agree with the layout, which catches a foreign pointer and a mismatched size before either reaches the page layer. Every pointer into the block becomes invalid. | Name | Type | Description | | -------- | ------------- | ---------------------------------- | | `block` | `*var opaque` | an address this allocator returned | | `layout` | `Layout` | the layout it was allocated with | **Returns**: nothing when the release was accepted, or why it was refused [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Allocator/Src/System.rux#L113){rel=""nofollow""} ### `Reallocate` ```rux pub func Reallocate( self: &SystemAllocator, block: *var opaque, oldLayout: Layout, newLayout: Layout ) -> (*var opaque) ! AllocError ``` Changes the size of a block by taking a new one and copying what fits. The two layouts must share an alignment; anything else reports `Unsupported` rather than moving the block to a different one. On success the original block is released and `result` holds the new address, which is generally not the old one. This allocator never grows a block in place, even when the page it sits in has room: doing so would need a free-list it deliberately does not keep. The old pointer is invalid once this succeeds. On failure it is untouched and still the caller's. | Name | Type | Description | | ----------- | ------------- | ----------------------------------------------------- | | `block` | `*var opaque` | the existing allocation's address | | `oldLayout` | `Layout` | the layout `block` was allocated with | | `newLayout` | `Layout` | the layout wanted, which must have the same alignment | **Returns**: the address the block is at afterwards, or why it was not resized [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Allocator/Src/System.rux#L136){rel=""nofollow""} ## Related ### `SystemBlockHeader` ```rux pub struct SystemBlockHeader { // private fields } ``` What a system allocation records about itself, immediately before the address the caller sees. Never constructed by a caller. The magic is checked on release, which is what turns a mismatched or foreign pointer into a reported `InvalidBlock` rather than a corrupted heap. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Allocator/Src/System.rux#L22){rel=""nofollow""} ### `SystemBlockMagic` ```rux pub const SystemBlockMagic: uint64 = 0x52757841_6C6C6F63; ``` The pattern a valid system block header carries. Chosen to be unlikely in ordinary data, so a pointer that was never one of these is very unlikely to look like one. This is a check against a mistake, not against an adversary. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Allocator/Src/System.rux#L37){rel=""nofollow""} # Math Mathematical constants and functions. ## Installation Add `Math` to the `[Dependencies]` table of your package's `Rux.toml`: ```toml [Dependencies] Math = { Namespace = "Rux", Version = "0.1.0" } ``` Standard packages are declared by hand: the registry does not serve them, so `rux add Rux/Math` cannot add them. ## Dependencies - [`Core`](https://rux-lang.dev/docs/api/core) 0.1.0 ## Guide Portable mathematical constants, elementary functions, floating-point utilities, and generic integer operations for Rux. The package implements its elementary functions directly instead of forwarding them to the host system's `libm`. Argument reduction, polynomial kernels, and IEEE 754 edge-case handling therefore remain consistent across supported targets. The implementation allocates no memory and depends only on [`Rux/Core`](https://rux-lang.dev/docs/api/core){rel=""nofollow""}. ### Example ```rux import Math::{ DegToRad, Hypot, SinCos }; let angle = DegToRad(30.0); let (sine, cosine) = SinCos(angle); let diagonal = Hypot(3.0, 4.0); ``` [`SinCos`](https://rux-lang.dev/docs/api/math/trigonometry#sin-cos) performs argument reduction once and returns `(sine, cosine)`, which is more efficient than calling [`Sin`](https://rux-lang.dev/docs/api/math/trigonometry#sin) and [`Cos`](https://rux-lang.dev/docs/api/math/trigonometry#cos) separately for the same angle. ### API overview Most floating-point functions provide both `float64` and `float32` overloads. The `float32` forms use a wide intermediate where doing so improves accuracy, then round once to the requested width. #### Constants and angles - **Exponential and logarithmic** — [`E`](https://rux-lang.dev/docs/api/math/constants#e), [`Ln2`](https://rux-lang.dev/docs/api/math/constants#ln2), [`Log2E`](https://rux-lang.dev/docs/api/math/constants#log2-e), [`Ln10`](https://rux-lang.dev/docs/api/math/constants#ln10), and [`Log10E`](https://rux-lang.dev/docs/api/math/constants#log10-e). - **Circular** — [`Pi`](https://rux-lang.dev/docs/api/math/constants#pi), [`Tau`](https://rux-lang.dev/docs/api/math/constants#tau), [`HalfPi`](https://rux-lang.dev/docs/api/math/constants#half-pi), [`QuarterPi`](https://rux-lang.dev/docs/api/math/constants#quarter-pi), [`InvPi`](https://rux-lang.dev/docs/api/math/constants#inv-pi), and [`InvTau`](https://rux-lang.dev/docs/api/math/constants#inv-tau). - **Radicals** — [`Sqrt2`](https://rux-lang.dev/docs/api/math/constants#sqrt2) and [`InvSqrt2`](https://rux-lang.dev/docs/api/math/constants#inv-sqrt2). - **Angle conversion** — [`RadPerDeg`](https://rux-lang.dev/docs/api/math/constants#rad-per-deg), [`DegPerRad`](https://rux-lang.dev/docs/api/math/constants#deg-per-rad), [`DegToRad`](https://rux-lang.dev/docs/api/math/trigonometry#deg-to-rad), and [`RadToDeg`](https://rux-lang.dev/docs/api/math/trigonometry#rad-to-deg). All constants are `float64` values rounded to the nearest representable value. See the [constants reference](https://rux-lang.dev/docs/api/math/constants){rel=""nofollow""} for the complete list. #### Elementary functions | Category | Functions | | ------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Trigonometric | [`Sin`](https://rux-lang.dev/docs/api/math/trigonometry#sin), [`Cos`](https://rux-lang.dev/docs/api/math/trigonometry#cos), [`Tan`](https://rux-lang.dev/docs/api/math/trigonometry#tan), [`Cotan`](https://rux-lang.dev/docs/api/math/trigonometry#cotan), [`SinCos`](https://rux-lang.dev/docs/api/math/trigonometry#sin-cos) | | Inverse trigonometric | [`ArcSin`](https://rux-lang.dev/docs/api/math/trigonometry#arc-sin), [`ArcCos`](https://rux-lang.dev/docs/api/math/trigonometry#arc-cos), [`ArcTan`](https://rux-lang.dev/docs/api/math/trigonometry#arc-tan), [`ArcTan2`](https://rux-lang.dev/docs/api/math/trigonometry#arc-tan2), [`ArcCot`](https://rux-lang.dev/docs/api/math/trigonometry#arc-cot) | | Hyperbolic | [`Sinh`](https://rux-lang.dev/docs/api/math/hyperbolic#sinh), [`Cosh`](https://rux-lang.dev/docs/api/math/hyperbolic#cosh), [`Tanh`](https://rux-lang.dev/docs/api/math/hyperbolic#tanh), [`Cotanh`](https://rux-lang.dev/docs/api/math/hyperbolic#cotanh) | | Inverse hyperbolic | [`ArcSinh`](https://rux-lang.dev/docs/api/math/hyperbolic#arc-sinh), [`ArcCosh`](https://rux-lang.dev/docs/api/math/hyperbolic#arc-cosh), [`ArcTanh`](https://rux-lang.dev/docs/api/math/hyperbolic#arc-tanh) | | Exponential | `Exp`, [`Exp2`](https://rux-lang.dev/docs/api/math/exponential#exp2), [`Expm1`](https://rux-lang.dev/docs/api/math/exponential#expm1) | | Logarithmic | `Log`, [`Log2`](https://rux-lang.dev/docs/api/math/exponential#log2), [`Log10`](https://rux-lang.dev/docs/api/math/exponential#log10), [`Log1p`](https://rux-lang.dev/docs/api/math/exponential#log1p) | | Powers and roots | `Pow`, [`PowInteger`](https://rux-lang.dev/docs/api/math/powers#pow-integer), `Sqrt`, [`Cbrt`](https://rux-lang.dev/docs/api/math/powers#cbrt), [`Hypot`](https://rux-lang.dev/docs/api/math/powers#hypot) | | Magnitude and comparison | `Abs`, [`Min`](https://rux-lang.dev/docs/api/math/abs-min-max#min), [`Max`](https://rux-lang.dev/docs/api/math/abs-min-max#max) | `Expm1(x)` computes `Exp(x) - 1`, and `Log1p(x)` computes `Log(1 + x)`, without discarding the small result near zero. [`PowInteger`](https://rux-lang.dev/docs/api/math/powers#pow-integer) uses repeated squaring and preserves exact integer powers when the intermediate values are exactly representable; use `Pow` for a general floating-point exponent. #### Rounding and conversion - [`Floor`](https://rux-lang.dev/docs/api/math/rounding#floor), [`Ceil`](https://rux-lang.dev/docs/api/math/rounding#ceil), [`Trunc`](https://rux-lang.dev/docs/api/math/rounding#trunc), and [`Round`](https://rux-lang.dev/docs/api/math/rounding#round) provide the usual directed and ties-away rounding rules. - [`RoundTiesToEven`](https://rux-lang.dev/docs/api/math/rounding#round-ties-to-even) implements IEEE 754's default halfway rule. - [`RoundTo`](https://rux-lang.dev/docs/api/math/rounding#round-to) selects a rule through [`RoundingMode`](https://rux-lang.dev/docs/api/math/rounding#rounding-mode). - [`ToIntegerChecked<T>`](https://rux-lang.dev/docs/api/math/rounding#to-integer-checked) rounds and converts without silently saturating an out-of-range value. - [`Mod`](https://rux-lang.dev/docs/api/math/rounding#mod) computes the exact floating-point remainder with the sign of the dividend. [`ToIntegerChecked<T>`](https://rux-lang.dev/docs/api/math/rounding#to-integer-checked) returns `true` on failure and writes zero to its output. The destination pointer must be non-null and writable: ```rux import Math::{ RoundingMode, ToIntegerChecked }; var answer: int32 = 0; let failed = ToIntegerChecked<int32>(42.5, 0, RoundingMode::ToNearestTiesEven, @answer); ``` #### Floating-point inspection and manipulation | Purpose | API | | ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Classification | [`IsNan`](https://rux-lang.dev/docs/api/math/classification#is-nan), [`IsInfinite`](https://rux-lang.dev/docs/api/math/classification#is-infinite), [`IsFinite`](https://rux-lang.dev/docs/api/math/classification#is-finite), [`IsZero`](https://rux-lang.dev/docs/api/math/classification#is-zero), [`IsSubnormal`](https://rux-lang.dev/docs/api/math/classification#is-subnormal), [`IsNormal`](https://rux-lang.dev/docs/api/math/classification#is-normal), [`Classify`](https://rux-lang.dev/docs/api/math/classification#classify), [`FloatClass`](https://rux-lang.dev/docs/api/math/classification#float-class) | | Sign handling | [`SignBit`](https://rux-lang.dev/docs/api/math/classification#sign-bit), [`CopySign`](https://rux-lang.dev/docs/api/math/float-representation#copy-sign) | | Adjacent values | [`NextAfter`](https://rux-lang.dev/docs/api/math/float-representation#next-after), [`NextUp`](https://rux-lang.dev/docs/api/math/float-representation#next-up), [`NextDown`](https://rux-lang.dev/docs/api/math/float-representation#next-down) | | Special values | [`PositiveInfinity64`](https://rux-lang.dev/docs/api/math/classification#positive-infinity64), [`PositiveInfinity32`](https://rux-lang.dev/docs/api/math/classification#positive-infinity32), [`QuietNan64`](https://rux-lang.dev/docs/api/math/classification#quiet-nan64), [`QuietNan32`](https://rux-lang.dev/docs/api/math/classification#quiet-nan32) | | Decomposition | [`ExponentOf`](https://rux-lang.dev/docs/api/math/float-representation#exponent-of), [`Decompose`](https://rux-lang.dev/docs/api/math/float-representation#decompose), [`SplitIntegral`](https://rux-lang.dev/docs/api/math/float-representation#split-integral) | | Scaling | [`ScaleByPowerOfTwo`](https://rux-lang.dev/docs/api/math/float-representation#scale-by-power-of-two) | | Error measurement | [`UlpDistance`](https://rux-lang.dev/docs/api/math/float-representation#ulp-distance) | [`ExponentOf`](https://rux-lang.dev/docs/api/math/float-representation#exponent-of) reports [`NoExponent`](https://rux-lang.dev/docs/api/math/float-representation#no-exponent) for zero and [`IndeterminateExponent`](https://rux-lang.dev/docs/api/math/float-representation#indeterminate-exponent) for a NaN or infinity. [`UlpDistance`](https://rux-lang.dev/docs/api/math/float-representation#ulp-distance) counts representable steps rather than subtracting values, making it useful for numerical error checks across the full floating-point range. #### Generic integer operations The integer APIs are generic over signed and unsigned integer widths: - [`AbsChecked<T>`](https://rux-lang.dev/docs/api/math/integer#abs-checked) and [`AbsWrapping<T>`](https://rux-lang.dev/docs/api/math/integer#abs-wrapping) compute a magnitude with explicit overflow behavior. - [`Minimum<T>`](https://rux-lang.dev/docs/api/math/integer#minimum), [`Maximum<T>`](https://rux-lang.dev/docs/api/math/integer#maximum), and [`Clamp<T>`](https://rux-lang.dev/docs/api/math/integer#clamp) provide scalar ordering operations. - [`GcdChecked<T>`](https://rux-lang.dev/docs/api/math/integer#gcd-checked) and [`LcmChecked<T>`](https://rux-lang.dev/docs/api/math/integer#lcm-checked) implement number-theory operations. - [`PowChecked<T>`](https://rux-lang.dev/docs/api/math/integer#pow-checked) raises an integer to a non-negative integer power. Checked operations follow the same convention as checked arithmetic in `Rux/Core`: they return `true` when the mathematical result is not representable. Their raw output pointers must be non-null, correctly aligned, and writable for one value for the duration of the call. #### Complex numbers [`Complex`](https://rux-lang.dev/docs/api/math/complex#complex) over `float64` and [`Complex32`](https://rux-lang.dev/docs/api/math/complex#complex32) over `float32` have `+`, `-`, `*` and `/`, `Abs`, [`Arg`](https://rux-lang.dev/docs/api/math/complex#arg), [`Norm`](https://rux-lang.dev/docs/api/math/complex#norm), [`Conjugate`](https://rux-lang.dev/docs/api/math/complex#conjugate), [`Negate`](https://rux-lang.dev/docs/api/math/complex#negate), [`Scale`](https://rux-lang.dev/docs/api/math/complex#scale), [`FromPolar`](https://rux-lang.dev/docs/api/math/complex#from-polar), and `Exp`, `Log`, `Sqrt` and `Pow` on the principal branch. Division uses Smith's method and the magnitude goes through [`Hypot`](https://rux-lang.dev/docs/api/math/powers#hypot), so neither overflows for parts far from one. ### Numerical behavior - **IEEE 754 special values are part of each contract.** Signed zeros, infinities, NaNs, subnormals, and domain errors are handled deliberately rather than left to host-library behavior. - **Accuracy is documented per function.** The primary trigonometric, exponential, logarithmic, and root operations target an error of at most one ulp; inverse hyperbolic functions document a two-ulp bound. - **Large-angle reduction retains precision.** Trigonometric functions reduce large finite inputs without first rounding them to a low-precision multiple of `Pi / 2`. - **No allocation or hidden global state.** Every operation works on ordinary values and caller-provided outputs. The bit-level implementation currently supports x86-64 and AArch64 targets. ### Value and ownership model The package owns no storage. [`FloatClass`](https://rux-lang.dev/docs/api/math/classification#float-class) and [`RoundingMode`](https://rux-lang.dev/docs/api/math/rounding#rounding-mode) are structural `Copy` values, and multi-result operations such as [`SinCos`](https://rux-lang.dev/docs/api/math/trigonometry#sin-cos) return tuples. Ordinary inputs are passed by value. Raw pointers appear only in checked operations and decomposition helpers that write an additional result supplied by the caller. ## Index ### Types | Name | Summary | | ----------------------------------------------------------------------------- | ------------------------------------------------------------ | | [`FloatClass`](https://rux-lang.dev/docs/api/math/classification#float-class) | The five kinds IEEE 754 sorts every value into. | | [`Complex`](https://rux-lang.dev/docs/api/math/complex#complex) | A complex number `real + imaginary·i` over `float64`. | | [`Complex32`](https://rux-lang.dev/docs/api/math/complex#complex32) | A complex number `real + imaginary·i` over `float32`. | | [`RoundingMode`](https://rux-lang.dev/docs/api/math/rounding#rounding-mode) | Which way a value that falls between two integers should go. | ### Functions | Name | Summary | | ---------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------- | | [`Abs`](https://rux-lang.dev/docs/api/math/abs-min-max#abs) | Computes the absolute value of `x` at `float32` precision. | | [`DegToRad`](https://rux-lang.dev/docs/api/math/trigonometry#deg-to-rad) | Converts an angle from degrees to radians. | | [`RadToDeg`](https://rux-lang.dev/docs/api/math/trigonometry#rad-to-deg) | Converts an angle from radians to degrees. | | [`ArcCos`](https://rux-lang.dev/docs/api/math/trigonometry#arc-cos) | Computes the inverse cosine of `x` in radians. | | [`ArcCot`](https://rux-lang.dev/docs/api/math/trigonometry#arc-cot) | Computes the inverse cotangent of `x` in radians. | | [`ArcSinh`](https://rux-lang.dev/docs/api/math/hyperbolic#arc-sinh) | The inverse hyperbolic sine: the value whose hyperbolic sine is `x`. | | [`ArcCosh`](https://rux-lang.dev/docs/api/math/hyperbolic#arc-cosh) | The inverse hyperbolic cosine: the non-negative value whose hyperbolic cosine is `x`. | | [`ArcTanh`](https://rux-lang.dev/docs/api/math/hyperbolic#arc-tanh) | The inverse hyperbolic tangent: the value whose hyperbolic tangent is `x`. | | [`ArcSin`](https://rux-lang.dev/docs/api/math/trigonometry#arc-sin) | Computes the inverse sine of `x` in radians. | | [`ArcTan`](https://rux-lang.dev/docs/api/math/trigonometry#arc-tan) | Computes the inverse tangent of `x` in radians. | | [`ArcTan2`](https://rux-lang.dev/docs/api/math/trigonometry#arc-tan2) | The angle from the positive x axis to the point `(x, y)`, in radians, in `(-Pi, Pi]`. | | [`Cbrt`](https://rux-lang.dev/docs/api/math/powers#cbrt) | Computes the real cube root of `x`. | | [`Ceil`](https://rux-lang.dev/docs/api/math/rounding#ceil) | Rounds `x` toward positive infinity to an integral value. | | [`IsNan`](https://rux-lang.dev/docs/api/math/classification#is-nan) | Whether `value` is a NaN. | | [`IsInfinite`](https://rux-lang.dev/docs/api/math/classification#is-infinite) | Determines whether `value` is an infinity at `float32` precision. | | [`IsFinite`](https://rux-lang.dev/docs/api/math/classification#is-finite) | Whether `value` is an ordinary number: neither a NaN nor an infinity. | | [`IsZero`](https://rux-lang.dev/docs/api/math/classification#is-zero) | Whether `value` is either zero. | | [`IsSubnormal`](https://rux-lang.dev/docs/api/math/classification#is-subnormal) | Whether `value` is subnormal: nonzero, but too small to carry a full significand. | | [`IsNormal`](https://rux-lang.dev/docs/api/math/classification#is-normal) | Whether `value` is an ordinary value at full precision. | | [`Classify`](https://rux-lang.dev/docs/api/math/classification#classify) | Which of the five kinds `value` belongs to. | | [`SignBit`](https://rux-lang.dev/docs/api/math/classification#sign-bit) | Whether `value`'s sign bit is set. | | [`CopySign`](https://rux-lang.dev/docs/api/math/float-representation#copy-sign) | `magnitude` carrying the sign of `sign`. | | [`NextAfter`](https://rux-lang.dev/docs/api/math/float-representation#next-after) | The value adjacent to `from` in the direction of `toward`. | | [`NextUp`](https://rux-lang.dev/docs/api/math/float-representation#next-up) | Finds the next `float32` value above `value`. | | [`NextDown`](https://rux-lang.dev/docs/api/math/float-representation#next-down) | Finds the next `float32` value below `value`. | | [`PositiveInfinity64`](https://rux-lang.dev/docs/api/math/classification#positive-infinity64) | Positive infinity. | | [`PositiveInfinity32`](https://rux-lang.dev/docs/api/math/classification#positive-infinity32) | Positive infinity at the narrow width. | | [`QuietNan64`](https://rux-lang.dev/docs/api/math/classification#quiet-nan64) | A quiet NaN. | | [`QuietNan32`](https://rux-lang.dev/docs/api/math/classification#quiet-nan32) | A quiet NaN at the narrow width. | | [`ScaleByPowerOfTwo`](https://rux-lang.dev/docs/api/math/float-representation#scale-by-power-of-two) | `value` multiplied by two raised to `exponent`, with one rounding. | | [`ExponentOf`](https://rux-lang.dev/docs/api/math/float-representation#exponent-of) | The exponent of `value`: the power of two of its most significant bit. | | [`Decompose`](https://rux-lang.dev/docs/api/math/float-representation#decompose) | Splits `value` into a fraction in `[0.5, 1)` and a power of two, so that `fraction * 2^exponent == value`. | | [`SplitIntegral`](https://rux-lang.dev/docs/api/math/float-representation#split-integral) | Splits `value` into its integral and fractional parts, both carrying its sign. | | [`UlpDistance`](https://rux-lang.dev/docs/api/math/float-representation#ulp-distance) | How many representable values lie between `left` and `right`. | | [`Cos`](https://rux-lang.dev/docs/api/math/trigonometry#cos) | Computes the cosine of `x`, where `x` is in radians. | | [`Cosh`](https://rux-lang.dev/docs/api/math/hyperbolic#cosh) | Computes the hyperbolic cosine of `x`. | | [`Cotan`](https://rux-lang.dev/docs/api/math/trigonometry#cotan) | Computes the cotangent of `x`, where `x` is in radians. | | [`Cotanh`](https://rux-lang.dev/docs/api/math/hyperbolic#cotanh) | Computes the hyperbolic cotangent of `x`. | | [`Exp`](https://rux-lang.dev/docs/api/math/exponential#exp) | Computes `e` raised to `x`. | | [`Exp2`](https://rux-lang.dev/docs/api/math/exponential#exp2) | Computes two raised to `x`. | | [`Expm1`](https://rux-lang.dev/docs/api/math/exponential#expm1) | Computes `Exp(x) - 1` without losing precision near zero. | | [`Floor`](https://rux-lang.dev/docs/api/math/rounding#floor) | Rounds `x` toward negative infinity to an integral value. | | [`Hypot`](https://rux-lang.dev/docs/api/math/powers#hypot) | Computes the Euclidean length `Sqrt(x * x + y * y)` without intermediate overflow or underflow. | | [`AbsChecked<T>`](https://rux-lang.dev/docs/api/math/integer#abs-checked) | The magnitude of `value`, reporting whether it is representable. | | [`AbsWrapping<T>`](https://rux-lang.dev/docs/api/math/integer#abs-wrapping) | The magnitude of `value`, wrapping where it is not representable. | | [`Minimum<T>`](https://rux-lang.dev/docs/api/math/integer#minimum) | The smaller of two integers. | | [`Maximum<T>`](https://rux-lang.dev/docs/api/math/integer#maximum) | The larger of two integers. | | [`Clamp<T>`](https://rux-lang.dev/docs/api/math/integer#clamp) | `value` brought into `[low, high]`. | | [`GcdChecked<T>`](https://rux-lang.dev/docs/api/math/integer#gcd-checked) | The greatest common divisor of `left` and `right`, reporting whether it is representable. | | [`LcmChecked<T>`](https://rux-lang.dev/docs/api/math/integer#lcm-checked) | The least common multiple of `left` and `right`, reporting whether it is representable. | | [`PowChecked<T>`](https://rux-lang.dev/docs/api/math/integer#pow-checked) | `base` raised to `exponent`, reporting whether the true power is representable. | | [`Log`](https://rux-lang.dev/docs/api/math/exponential#log) | Computes the natural logarithm of `x`. | | [`Log10`](https://rux-lang.dev/docs/api/math/exponential#log10) | Computes the base-ten logarithm of `x`. | | [`Log1p`](https://rux-lang.dev/docs/api/math/exponential#log1p) | Computes `Log(1 + x)` without losing precision near zero. | | [`Log2`](https://rux-lang.dev/docs/api/math/exponential#log2) | Computes the base-two logarithm of `x`. | | [`Max`](https://rux-lang.dev/docs/api/math/abs-min-max#max) | Selects the larger of `a` and `b`. | | [`Min`](https://rux-lang.dev/docs/api/math/abs-min-max#min) | Selects the smaller of `a` and `b`. | | [`Mod`](https://rux-lang.dev/docs/api/math/rounding#mod) | Computes the floating-point remainder of `x / y`, with the sign of `x`. | | [`Pow`](https://rux-lang.dev/docs/api/math/powers#pow) | Raises `x` to the power `y`. | | [`PowInteger`](https://rux-lang.dev/docs/api/math/powers#pow-integer) | `base` raised to the integer power `exponent`. | | [`Round`](https://rux-lang.dev/docs/api/math/rounding#round) | Rounds `x` to the nearest integral value, with halfway cases away from zero. | | [`RoundTiesToEven`](https://rux-lang.dev/docs/api/math/rounding#round-ties-to-even) | The nearest integer to `value`, with a halfway value going to the even neighbour. | | [`RoundTo`](https://rux-lang.dev/docs/api/math/rounding#round-to) | Rounds `value` in the requested direction at `float32` precision. | | [`ToIntegerChecked<T>`](https://rux-lang.dev/docs/api/math/rounding#to-integer-checked) | `value` rounded in the named direction and converted to an integer, reporting whether it fits. | | [`Sin`](https://rux-lang.dev/docs/api/math/trigonometry#sin) | Computes the sine of `x`, where `x` is in radians. | | [`SinCos`](https://rux-lang.dev/docs/api/math/trigonometry#sin-cos) | Computes the sine and cosine of `angle` from one argument reduction. | | [`Sinh`](https://rux-lang.dev/docs/api/math/hyperbolic#sinh) | Computes the hyperbolic sine of `x`. | | [`Sqrt`](https://rux-lang.dev/docs/api/math/powers#sqrt) | Computes the correctly rounded square root of `x` at `float32` precision. | | [`Tan`](https://rux-lang.dev/docs/api/math/trigonometry#tan) | Computes the tangent of `x`, where `x` is in radians. | | [`Tanh`](https://rux-lang.dev/docs/api/math/hyperbolic#tanh) | Computes the hyperbolic tangent of `x`. | | [`Trunc`](https://rux-lang.dev/docs/api/math/rounding#trunc) | Rounds `x` toward zero to an integral value at `float32` precision. | ### Constants | Name | Summary | | --------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- | | [`NoExponent`](https://rux-lang.dev/docs/api/math/float-representation#no-exponent) | What [`ExponentOf`](https://rux-lang.dev/docs/api/math/float-representation#exponent-of) reports for zero, which has no exponent at all. | | [`IndeterminateExponent`](https://rux-lang.dev/docs/api/math/float-representation#indeterminate-exponent) | What [`ExponentOf`](https://rux-lang.dev/docs/api/math/float-representation#exponent-of) reports for a NaN or an infinity. | | [`E`](https://rux-lang.dev/docs/api/math/constants#e) | Euler's number, the base of the natural logarithm, rounded to the nearest `float64`. | | [`Ln2`](https://rux-lang.dev/docs/api/math/constants#ln2) | The natural logarithm of two, rounded to the nearest `float64`. | | [`Log2E`](https://rux-lang.dev/docs/api/math/constants#log2-e) | The base-two logarithm of [`E`](https://rux-lang.dev/docs/api/math/constants#e), rounded to the nearest `float64`. | | [`Ln10`](https://rux-lang.dev/docs/api/math/constants#ln10) | The natural logarithm of ten, rounded to the nearest `float64`. | | [`Log10E`](https://rux-lang.dev/docs/api/math/constants#log10-e) | The base-ten logarithm of [`E`](https://rux-lang.dev/docs/api/math/constants#e), rounded to the nearest `float64`. | | [`Pi`](https://rux-lang.dev/docs/api/math/constants#pi) | The ratio of a circle's circumference to its diameter, rounded to the nearest `float64`. | | [`Tau`](https://rux-lang.dev/docs/api/math/constants#tau) | One full turn in radians, equal to `2 * Pi` and rounded to the nearest `float64`. | | [`HalfPi`](https://rux-lang.dev/docs/api/math/constants#half-pi) | One quarter turn in radians, equal to `Pi / 2` and rounded to the nearest `float64`. | | [`QuarterPi`](https://rux-lang.dev/docs/api/math/constants#quarter-pi) | One eighth turn in radians, equal to `Pi / 4` and rounded to the nearest `float64`. | | [`InvPi`](https://rux-lang.dev/docs/api/math/constants#inv-pi) | The reciprocal of [`Pi`](https://rux-lang.dev/docs/api/math/constants#pi), rounded to the nearest `float64`. | | [`InvTau`](https://rux-lang.dev/docs/api/math/constants#inv-tau) | The reciprocal of [`Tau`](https://rux-lang.dev/docs/api/math/constants#tau), rounded to the nearest `float64`. | | [`Sqrt2`](https://rux-lang.dev/docs/api/math/constants#sqrt2) | The square root of two, rounded to the nearest `float64`. | | [`InvSqrt2`](https://rux-lang.dev/docs/api/math/constants#inv-sqrt2) | The reciprocal of [`Sqrt2`](https://rux-lang.dev/docs/api/math/constants#sqrt2), rounded to the nearest `float64`. | | [`RadPerDeg`](https://rux-lang.dev/docs/api/math/constants#rad-per-deg) | Radians per degree, equal to `Pi / 180` and rounded to the nearest `float64`. | | [`DegPerRad`](https://rux-lang.dev/docs/api/math/constants#deg-per-rad) | Degrees per radian, equal to `180 / Pi` and rounded to the nearest `float64`. | # Complex numbers Complex numbers at two precisions: arithmetic, polar form, and the elementary functions. ## `Complex` ```rux pub struct Complex { pub real: float64; pub imaginary: float64; } ``` A complex number `real + imaginary·i` over `float64`. `Copy`. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Math/Src/Complex.rux#L13){rel=""nofollow""} **Fields** | Name | Type | Description | | ----------- | --------- | ------------------- | | `real` | `float64` | The real part. | | `imaginary` | `float64` | The imaginary part. | **Associated functions** ### `New` ```rux pub func New(real: float64, imaginary: float64) -> Complex ``` The number `real + imaginary·i`. | Name | Type | Description | | ----------- | --------- | ------------------ | | `real` | `float64` | the real part | | `imaginary` | `float64` | the imaginary part | **Returns**: the number [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Math/Src/Complex.rux#L26){rel=""nofollow""} ### `FromPolar` ```rux pub func FromPolar( magnitude: float64, angle: float64 ) -> Complex ``` The number with magnitude `magnitude` at `angle` radians from the positive real axis. | Name | Type | Description | | ----------- | --------- | ---------------------- | | `magnitude` | `float64` | the distance from zero | | `angle` | `float64` | the angle in radians | **Returns**: the number [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Math/Src/Complex.rux#L35){rel=""nofollow""} **Methods** ### `Abs` ```rux pub func Abs(self: &Complex) -> float64 ``` The distance from zero, computed without overflow or underflow on the way. **Returns**: the magnitude [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Math/Src/Complex.rux#L42){rel=""nofollow""} ### `Arg` ```rux pub func Arg(self: &Complex) -> float64 ``` The angle from the positive real axis, in (-π, π]. **Returns**: the argument in radians [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Math/Src/Complex.rux#L49){rel=""nofollow""} ### `Norm` ```rux pub func Norm(self: &Complex) -> float64 ``` The square of the magnitude, which needs no square root. **Returns**: the squared magnitude [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Math/Src/Complex.rux#L56){rel=""nofollow""} ### `Conjugate` ```rux pub func Conjugate(self: &Complex) -> Complex ``` The number reflected across the real axis. **Returns**: the conjugate [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Math/Src/Complex.rux#L63){rel=""nofollow""} ### `Negate` ```rux pub func Negate(self: &Complex) -> Complex ``` The number with both parts negated. **Returns**: the negation [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Math/Src/Complex.rux#L70){rel=""nofollow""} ### `Scale` ```rux pub func Scale(self: &Complex, factor: float64) -> Complex ``` The number with both parts multiplied by `factor`. | Name | Type | Description | | -------- | --------- | --------------- | | `factor` | `float64` | the real factor | **Returns**: the scaled number [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Math/Src/Complex.rux#L78){rel=""nofollow""} ### `Exp` ```rux pub func Exp(self: &Complex) -> Complex ``` e raised to this number. **Returns**: the exponential [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Math/Src/Complex.rux#L85){rel=""nofollow""} ### `Log` ```rux pub func Log(self: &Complex) -> Complex ``` The natural logarithm on the principal branch: the logarithm of the magnitude, and the argument. **Returns**: the logarithm [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Math/Src/Complex.rux#L93){rel=""nofollow""} ### `Sqrt` ```rux pub func Sqrt(self: &Complex) -> Complex ``` The principal square root, whose real part is never negative. **Returns**: the square root [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Math/Src/Complex.rux#L100){rel=""nofollow""} ### `Pow` ```rux pub func Pow(self: &Complex, exponent: Complex) -> Complex ``` This number raised to `exponent`, as e raised to `exponent` times the logarithm, so on the principal branch. Zero raised to anything is zero. | Name | Type | Description | | ---------- | --------- | ----------- | | `exponent` | `Complex` | the power | **Returns**: the power [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Math/Src/Complex.rux#L113){rel=""nofollow""} **Operators** ### `+` ```rux pub func +(self: &Complex, other: Complex) -> Complex ``` The sum. | Name | Type | Description | | ------- | --------- | ----------------- | | `other` | `Complex` | the number to add | **Returns**: the sum [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Math/Src/Complex.rux#L123){rel=""nofollow""} ### `-` ```rux pub func -(self: &Complex, other: Complex) -> Complex ``` The difference. | Name | Type | Description | | ------- | --------- | ---------------------- | | `other` | `Complex` | the number to subtract | **Returns**: the difference [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Math/Src/Complex.rux#L131){rel=""nofollow""} ### `*` ```rux pub func *(self: &Complex, other: Complex) -> Complex ``` The product. | Name | Type | Description | | ------- | --------- | ------------------------- | | `other` | `Complex` | the number to multiply by | **Returns**: the product [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Math/Src/Complex.rux#L139){rel=""nofollow""} ### `/` ```rux pub func /(self: &Complex, other: Complex) -> Complex ``` The quotient, by Smith's method, so that a divisor with very large or very small parts keeps its precision. Dividing by zero gives infinities or NaN, as floating-point division does. | Name | Type | Description | | ------- | --------- | ----------------------- | | `other` | `Complex` | the number to divide by | **Returns**: the quotient [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Math/Src/Complex.rux#L151){rel=""nofollow""} ## `Complex32` ```rux pub struct Complex32 { pub real: float32; pub imaginary: float32; } ``` A complex number `real + imaginary·i` over `float32`. `Copy`. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Math/Src/Complex.rux#L171){rel=""nofollow""} **Fields** | Name | Type | Description | | ----------- | --------- | ------------------- | | `real` | `float32` | The real part. | | `imaginary` | `float32` | The imaginary part. | **Associated functions** ### `New` ```rux pub func New(real: float32, imaginary: float32) -> Complex32 ``` The number `real + imaginary·i`. | Name | Type | Description | | ----------- | --------- | ------------------ | | `real` | `float32` | the real part | | `imaginary` | `float32` | the imaginary part | **Returns**: the number [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Math/Src/Complex.rux#L184){rel=""nofollow""} ### `FromPolar` ```rux pub func FromPolar( magnitude: float32, angle: float32 ) -> Complex32 ``` The number with magnitude `magnitude` at `angle` radians from the positive real axis. | Name | Type | Description | | ----------- | --------- | ---------------------- | | `magnitude` | `float32` | the distance from zero | | `angle` | `float32` | the angle in radians | **Returns**: the number [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Math/Src/Complex.rux#L193){rel=""nofollow""} **Methods** ### `Abs` ```rux pub func Abs(self: &Complex32) -> float32 ``` The distance from zero, computed without overflow or underflow on the way. **Returns**: the magnitude [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Math/Src/Complex.rux#L200){rel=""nofollow""} ### `Arg` ```rux pub func Arg(self: &Complex32) -> float32 ``` The angle from the positive real axis, in (-π, π]. **Returns**: the argument in radians [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Math/Src/Complex.rux#L207){rel=""nofollow""} ### `Norm` ```rux pub func Norm(self: &Complex32) -> float32 ``` The square of the magnitude, which needs no square root. **Returns**: the squared magnitude [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Math/Src/Complex.rux#L214){rel=""nofollow""} ### `Conjugate` ```rux pub func Conjugate(self: &Complex32) -> Complex32 ``` The number reflected across the real axis. **Returns**: the conjugate [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Math/Src/Complex.rux#L221){rel=""nofollow""} ### `Negate` ```rux pub func Negate(self: &Complex32) -> Complex32 ``` The number with both parts negated. **Returns**: the negation [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Math/Src/Complex.rux#L228){rel=""nofollow""} ### `Scale` ```rux pub func Scale( self: &Complex32, factor: float32 ) -> Complex32 ``` The number with both parts multiplied by `factor`. | Name | Type | Description | | -------- | --------- | --------------- | | `factor` | `float32` | the real factor | **Returns**: the scaled number [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Math/Src/Complex.rux#L236){rel=""nofollow""} ### `Exp` ```rux pub func Exp(self: &Complex32) -> Complex32 ``` e raised to this number. **Returns**: the exponential [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Math/Src/Complex.rux#L243){rel=""nofollow""} ### `Log` ```rux pub func Log(self: &Complex32) -> Complex32 ``` The natural logarithm on the principal branch: the logarithm of the magnitude, and the argument. **Returns**: the logarithm [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Math/Src/Complex.rux#L251){rel=""nofollow""} ### `Sqrt` ```rux pub func Sqrt(self: &Complex32) -> Complex32 ``` The principal square root, whose real part is never negative. **Returns**: the square root [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Math/Src/Complex.rux#L258){rel=""nofollow""} ### `Pow` ```rux pub func Pow( self: &Complex32, exponent: Complex32 ) -> Complex32 ``` This number raised to `exponent`, as e raised to `exponent` times the logarithm, so on the principal branch. Zero raised to anything is zero. | Name | Type | Description | | ---------- | ----------- | ----------- | | `exponent` | `Complex32` | the power | **Returns**: the power [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Math/Src/Complex.rux#L271){rel=""nofollow""} **Operators** ### `+` ```rux pub func +(self: &Complex32, other: Complex32) -> Complex32 ``` The sum. | Name | Type | Description | | ------- | ----------- | ----------------- | | `other` | `Complex32` | the number to add | **Returns**: the sum [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Math/Src/Complex.rux#L281){rel=""nofollow""} ### `-` ```rux pub func -(self: &Complex32, other: Complex32) -> Complex32 ``` The difference. | Name | Type | Description | | ------- | ----------- | ---------------------- | | `other` | `Complex32` | the number to subtract | **Returns**: the difference [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Math/Src/Complex.rux#L289){rel=""nofollow""} ### `*` ```rux pub func *(self: &Complex32, other: Complex32) -> Complex32 ``` The product. | Name | Type | Description | | ------- | ----------- | ------------------------- | | `other` | `Complex32` | the number to multiply by | **Returns**: the product [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Math/Src/Complex.rux#L297){rel=""nofollow""} ### `/` ```rux pub func /(self: &Complex32, other: Complex32) -> Complex32 ``` The quotient, by Smith's method, so that a divisor with very large or very small parts keeps its precision. Dividing by zero gives infinities or NaN, as floating-point division does. | Name | Type | Description | | ------- | ----------- | ----------------------- | | `other` | `Complex32` | the number to divide by | **Returns**: the quotient [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Math/Src/Complex.rux#L309){rel=""nofollow""} # Absolute value, minimum and maximum The magnitude of a floating-point value and the smaller or larger of two. ## `Abs` ```rux pub func Abs(x: float64) -> float64 pub func Abs(x: float32) -> float32 ``` Computes the absolute value of `x` at `float32` precision. Widening a finite `float32` to `float64` and narrowing its magnitude back is exact. As with the wide overload, either signed zero becomes `+0.0`, either infinity becomes positive infinity, and a NaN remains a NaN. | Overload | Summary | | ------------------------------------- | ---------------------------------------------------------- | | `pub func Abs(x: float64) -> float64` | Computes the absolute value of `x`. | | `pub func Abs(x: float32) -> float32` | Computes the absolute value of `x` at `float32` precision. | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Math/Src/Abs.rux#L13){rel=""nofollow""} **Parameters** | Name | Type | Description | | ---- | --------------------- | --------------------------------- | | `x` | `float64` / `float32` | value whose magnitude is returned | **Returns**: `x` without its sign ## `Max` ```rux pub func Max(a: float64, b: float64) -> float64 pub func Max(a: float32, b: float32) -> float32 ``` Selects the larger of `a` and `b`. A NaN loses to a number, so one NaN returns the other argument and two NaNs return a NaN. When both arguments are zeros, a positive zero wins. | Overload | Summary | | ------------------------------------------------- | --------------------------------------------------------- | | `pub func Max(a: float64, b: float64) -> float64` | Selects the larger of `a` and `b`. | | `pub func Max(a: float32, b: float32) -> float32` | Selects the larger of `a` and `b` at `float32` precision. | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Math/Src/Max.rux#L13){rel=""nofollow""} **Parameters** | Name | Type | Description | | ---- | --------------------- | ----------------------- | | `a` | `float64` / `float32` | first value to compare | | `b` | `float64` / `float32` | second value to compare | **Returns**: the larger non-NaN value, or a NaN when both arguments are NaNs ## `Min` ```rux pub func Min(a: float64, b: float64) -> float64 pub func Min(a: float32, b: float32) -> float32 ``` Selects the smaller of `a` and `b`. A NaN loses to a number, so one NaN returns the other argument and two NaNs return a NaN. When both arguments are zeros, a negative zero wins. | Overload | Summary | | ------------------------------------------------- | ---------------------------------------------------------- | | `pub func Min(a: float64, b: float64) -> float64` | Selects the smaller of `a` and `b`. | | `pub func Min(a: float32, b: float32) -> float32` | Selects the smaller of `a` and `b` at `float32` precision. | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Math/Src/Min.rux#L13){rel=""nofollow""} **Parameters** | Name | Type | Description | | ---- | --------------------- | ----------------------- | | `a` | `float64` / `float32` | first value to compare | | `b` | `float64` / `float32` | second value to compare | **Returns**: the smaller non-NaN value, or a NaN when both arguments are NaNs # Classification and special values Telling NaNs, infinities, zeros, subnormals and normal values apart, and making the special ones. ## `FloatClass` ```rux pub enum FloatClass: int32 { NotANumber = 0, Infinite = 1, Zero = 2, Subnormal = 3, Normal = 4 } ``` The five kinds IEEE 754 sorts every value into. `Copy`. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Math/Src/Classify.rux#L28){rel=""nofollow""} **Cases** | Name | Value | Description | | ------------ | ----- | ------------------------------------------------------------------------------------ | | `NotANumber` | `0` | Not a number: the result of an operation with no meaningful answer. | | `Infinite` | `1` | One of the two infinities. | | `Zero` | `2` | Positive or negative zero. | | `Subnormal` | `3` | A value too small to carry a full significand, whose precision degrades toward zero. | | `Normal` | `4` | An ordinary value at full precision. | ## `IsNan` ```rux pub func IsNan(value: float64) -> bool pub func IsNan(value: float32) -> bool ``` Whether `value` is a NaN. A NaN is the only value not equal to itself, which is why this needs no bit pattern. | Overload | Summary | | ---------------------------------------- | ----------------------------------------------------------- | | `pub func IsNan(value: float64) -> bool` | Whether `value` is a NaN. | | `pub func IsNan(value: float32) -> bool` | Determines whether `value` is a NaN at `float32` precision. | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Math/Src/Classify.rux#L46){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------- | --------------------- | ------------- | | `value` | `float64` / `float32` | value to test | **Returns**: `true` when `value` is a NaN ## `IsInfinite` ```rux pub func IsInfinite(value: float64) -> bool pub func IsInfinite(value: float32) -> bool ``` Determines whether `value` is an infinity at `float32` precision. | Overload | Summary | | --------------------------------------------- | ----------------------------------------------------------------- | | `pub func IsInfinite(value: float64) -> bool` | Whether `value` is one of the two infinities. | | `pub func IsInfinite(value: float32) -> bool` | Determines whether `value` is an infinity at `float32` precision. | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Math/Src/Classify.rux#L62){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------- | --------------------- | ------------- | | `value` | `float64` / `float32` | value to test | **Returns**: `true` when `value` is positive or negative infinity ## `IsFinite` ```rux pub func IsFinite(value: float64) -> bool pub func IsFinite(value: float32) -> bool ``` Whether `value` is an ordinary number: neither a NaN nor an infinity. | Overload | Summary | | ------------------------------------------- | --------------------------------------------------------------------- | | `pub func IsFinite(value: float64) -> bool` | Whether `value` is an ordinary number: neither a NaN nor an infinity. | | `pub func IsFinite(value: float32) -> bool` | Determines whether `value` is finite at `float32` precision. | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Math/Src/Classify.rux#L78){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------- | --------------------- | ------------- | | `value` | `float64` / `float32` | value to test | **Returns**: `true` when `value` is neither a NaN nor an infinity ## `IsZero` ```rux pub func IsZero(value: float64) -> bool pub func IsZero(value: float32) -> bool ``` Whether `value` is either zero. Both zeros answer `true`; [`SignBit`](https://rux-lang.dev/docs/api/math/classification#sign-bit) is what tells them apart. | Overload | Summary | | ----------------------------------------- | ------------------------------------------------------------------------ | | `pub func IsZero(value: float64) -> bool` | Whether `value` is either zero. | | `pub func IsZero(value: float32) -> bool` | Determines whether `value` is either signed zero at `float32` precision. | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Math/Src/Classify.rux#L95){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------- | --------------------- | ------------- | | `value` | `float64` / `float32` | value to test | **Returns**: `true` when `value` is positive or negative zero ## `IsSubnormal` ```rux pub func IsSubnormal(value: float64) -> bool pub func IsSubnormal(value: float32) -> bool ``` Whether `value` is subnormal: nonzero, but too small to carry a full significand. | Overload | Summary | | ---------------------------------------------- | --------------------------------------------------------------------------------- | | `pub func IsSubnormal(value: float64) -> bool` | Whether `value` is subnormal: nonzero, but too small to carry a full significand. | | `pub func IsSubnormal(value: float32) -> bool` | Determines whether `value` is subnormal at `float32` precision. | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Math/Src/Classify.rux#L111){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------- | --------------------- | ------------- | | `value` | `float64` / `float32` | value to test | **Returns**: `true` when `value` is subnormal ## `IsNormal` ```rux pub func IsNormal(value: float64) -> bool pub func IsNormal(value: float32) -> bool ``` Whether `value` is an ordinary value at full precision. Zero is **not** normal, which surprises people and is the definition every IEEE 754 implementation uses. | Overload | Summary | | ------------------------------------------- | ------------------------------------------------------------ | | `pub func IsNormal(value: float64) -> bool` | Whether `value` is an ordinary value at full precision. | | `pub func IsNormal(value: float32) -> bool` | Determines whether `value` is normal at `float32` precision. | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Math/Src/Classify.rux#L130){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------- | --------------------- | ------------- | | `value` | `float64` / `float32` | value to test | **Returns**: `true` when `value` is normal ## `Classify` ```rux pub func Classify(value: float64) -> FloatClass pub func Classify(value: float32) -> FloatClass ``` Which of the five kinds `value` belongs to. | Overload | Summary | | ------------------------------------------------- | ------------------------------------------- | | `pub func Classify(value: float64) -> FloatClass` | Which of the five kinds `value` belongs to. | | `pub func Classify(value: float32) -> FloatClass` | Classifies `value` at `float32` precision. | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Math/Src/Classify.rux#L148){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------- | --------------------- | ----------------- | | `value` | `float64` / `float32` | value to classify | **Returns**: the IEEE-754 class of `value` ## `SignBit` ```rux pub func SignBit(value: float64) -> bool pub func SignBit(value: float32) -> bool ``` Whether `value`'s sign bit is set. This is the sign bit, not a comparison: `SignBit(-0.0)` is `true` where `-0.0 < 0.0` is false, and a negative NaN answers `true` where every comparison against it answers false. That is the whole reason to ask by bit. | Overload | Summary | | ------------------------------------------ | ------------------------------------------------------------------------- | | `pub func SignBit(value: float64) -> bool` | Whether `value`'s sign bit is set. | | `pub func SignBit(value: float32) -> bool` | Determines whether the sign bit of `value` is set at `float32` precision. | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Math/Src/Classify.rux#L174){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------- | --------------------- | ----------------------------- | | `value` | `float64` / `float32` | value whose sign is inspected | **Returns**: `true` when the sign bit is set ## `PositiveInfinity64` ```rux pub func PositiveInfinity64() -> float64 ``` Positive infinity. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Math/Src/Classify.rux#L277){rel=""nofollow""} **Returns**: positive infinity at `float64` precision ## `PositiveInfinity32` ```rux pub func PositiveInfinity32() -> float32 ``` Positive infinity at the narrow width. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Math/Src/Classify.rux#L284){rel=""nofollow""} **Returns**: positive infinity at `float32` precision ## `QuietNan64` ```rux pub func QuietNan64() -> float64 ``` A quiet NaN. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Math/Src/Classify.rux#L291){rel=""nofollow""} **Returns**: A quiet NaN at `float64` precision ## `QuietNan32` ```rux pub func QuietNan32() -> float32 ``` A quiet NaN at the narrow width. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Math/Src/Classify.rux#L298){rel=""nofollow""} **Returns**: A quiet NaN at `float32` precision # Exponentials and logarithms Powers of e and two, and logarithms in base e, two and ten. ## `Exp` ```rux pub func Exp(x: float64) -> float64 pub func Exp(x: float32) -> float32 ``` Computes `e` raised to `x`. The error is at most one ulp. Positive infinity returns positive infinity, negative infinity returns `+0.0`, and a NaN remains a NaN. Finite results overflow to infinity or underflow to zero when required by `float64`. | Overload | Summary | | ------------------------------------- | -------------------------------------------------- | | `pub func Exp(x: float64) -> float64` | Computes `e` raised to `x`. | | `pub func Exp(x: float32) -> float32` | Computes `e` raised to `x` at `float32` precision. | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Math/Src/Exp.rux#L33){rel=""nofollow""} **Parameters** | Name | Type | Description | | ---- | --------------------- | ----------- | | `x` | `float64` / `float32` | exponent | **Returns**: `e` raised to `x` ## `Exp2` ```rux pub func Exp2(x: float64) -> float64 pub func Exp2(x: float32) -> float32 ``` Computes two raised to `x`. The error is at most one ulp, and an in-range integer exponent is exact. Positive infinity returns positive infinity, negative infinity returns zero, and a NaN remains a NaN. | Overload | Summary | | -------------------------------------- | -------------------------------------------------- | | `pub func Exp2(x: float64) -> float64` | Computes two raised to `x`. | | `pub func Exp2(x: float32) -> float32` | Computes two raised to `x` at `float32` precision. | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Math/Src/Exp2.rux#L12){rel=""nofollow""} **Parameters** | Name | Type | Description | | ---- | --------------------- | --------------- | | `x` | `float64` / `float32` | binary exponent | **Returns**: two raised to `x` ## `Expm1` ```rux pub func Expm1(x: float64) -> float64 pub func Expm1(x: float32) -> float32 ``` Computes `Exp(x) - 1` without losing precision near zero. The error is at most one ulp and remains small relative to the result as `x` approaches zero. A signed zero returns itself, positive infinity returns positive infinity, negative infinity returns `-1.0`, and a NaN remains a NaN. | Overload | Summary | | --------------------------------------- | -------------------------------------------------------------------------------- | | `pub func Expm1(x: float64) -> float64` | Computes `Exp(x) - 1` without losing precision near zero. | | `pub func Expm1(x: float32) -> float32` | Computes `Exp(x) - 1` at `float32` precision without losing precision near zero. | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Math/Src/Expm1.rux#L13){rel=""nofollow""} **Parameters** | Name | Type | Description | | ---- | --------------------- | ----------- | | `x` | `float64` / `float32` | exponent | **Returns**: `e` raised to `x`, minus one ## `Log` ```rux pub func Log(x: float64) -> float64 pub func Log(x: float32) -> float32 ``` Computes the natural logarithm of `x`. The error is at most one ulp. Either signed zero returns negative infinity, a negative value returns a NaN, positive infinity returns itself, and a NaN remains a NaN. | Overload | Summary | | ------------------------------------- | ------------------------------------------------------------- | | `pub func Log(x: float64) -> float64` | Computes the natural logarithm of `x`. | | `pub func Log(x: float32) -> float32` | Computes the natural logarithm of `x` at `float32` precision. | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Math/Src/Log.rux#L69){rel=""nofollow""} **Parameters** | Name | Type | Description | | ---- | --------------------- | ------------------------------------------ | | `x` | `float64` / `float32` | positive value whose logarithm is computed | **Returns**: the base-`e` logarithm of `x` ## `Log10` ```rux pub func Log10(x: float64) -> float64 pub func Log10(x: float32) -> float32 ``` Computes the base-ten logarithm of `x`. The error is at most one ulp, and an exact power of ten returns its exact exponent. Either signed zero returns negative infinity, a negative value returns a NaN, positive infinity returns itself, and a NaN remains a NaN. | Overload | Summary | | --------------------------------------- | -------------------------------------------------------------- | | `pub func Log10(x: float64) -> float64` | Computes the base-ten logarithm of `x`. | | `pub func Log10(x: float32) -> float32` | Computes the base-ten logarithm of `x` at `float32` precision. | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Math/Src/Log10.rux#L14){rel=""nofollow""} **Parameters** | Name | Type | Description | | ---- | --------------------- | ------------------------------------------ | | `x` | `float64` / `float32` | positive value whose logarithm is computed | **Returns**: the base-ten logarithm of `x` ## `Log1p` ```rux pub func Log1p(x: float64) -> float64 pub func Log1p(x: float32) -> float32 ``` Computes `Log(1 + x)` without losing precision near zero. `Log1p(0.0)` is zero with the argument's sign, `Log1p(-1.0)` is negative infinity, and an argument below -1 has no real logarithm and gives a NaN. | Overload | Summary | | --------------------------------------- | -------------------------------------------------------------------------------- | | `pub func Log1p(x: float64) -> float64` | Computes `Log(1 + x)` without losing precision near zero. | | `pub func Log1p(x: float32) -> float32` | Computes `Log(1 + x)` at `float32` precision without losing precision near zero. | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Math/Src/Log1p.rux#L26){rel=""nofollow""} **Parameters** | Name | Type | Description | | ---- | --------------------- | ---------------------------------------------- | | `x` | `float64` / `float32` | value added to one before taking the logarithm | **Returns**: the natural logarithm of `1 + x` ## `Log2` ```rux pub func Log2(x: float64) -> float64 pub func Log2(x: float32) -> float32 ``` Computes the base-two logarithm of `x`. The error is at most one ulp, and an exact power of two returns its exact exponent. Either signed zero returns negative infinity, a negative value returns a NaN, positive infinity returns itself, and a NaN remains a NaN. | Overload | Summary | | -------------------------------------- | -------------------------------------------------------------- | | `pub func Log2(x: float64) -> float64` | Computes the base-two logarithm of `x`. | | `pub func Log2(x: float32) -> float32` | Computes the base-two logarithm of `x` at `float32` precision. | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Math/Src/Log2.rux#L14){rel=""nofollow""} **Parameters** | Name | Type | Description | | ---- | --------------------- | ------------------------------------------ | | `x` | `float64` / `float32` | positive value whose logarithm is computed | **Returns**: the base-two logarithm of `x` # Floating-point representation Signs, exponents, neighbouring values and ulp distances of floating-point values. ## `CopySign` ```rux pub func CopySign( magnitude: float64, sign: float64 ) -> float64 pub func CopySign( magnitude: float32, sign: float32 ) -> float32 ``` `magnitude` carrying the sign of `sign`. Works on every value including NaNs and zeros, since it moves one bit and reads no others. | Overload | Summary | | ----------------------------------------------------------------- | ------------------------------------------------------------------ | | `pub func CopySign(magnitude: float64, sign: float64) -> float64` | `magnitude` carrying the sign of `sign`. | | `pub func CopySign(magnitude: float32, sign: float32) -> float32` | Copies the sign of `sign` onto `magnitude` at `float32` precision. | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Math/Src/Classify.rux#L192){rel=""nofollow""} **Parameters** | Name | Type | Description | | ----------- | --------------------- | ----------------------------------------- | | `magnitude` | `float64` / `float32` | value supplying every bit except the sign | | `sign` | `float64` / `float32` | value supplying the sign bit | **Returns**: the magnitude of `magnitude` with the sign of `sign` ## `NextAfter` ```rux pub func NextAfter( from: float64, toward: float64 ) -> float64 pub func NextAfter( from: float32, toward: float32 ) -> float32 ``` The value adjacent to `from` in the direction of `toward`. One representable value in that direction, subnormals and zeros included: stepping down from the smallest positive normal lands in the subnormals rather than jumping to zero, and stepping down from `+0.0` gives the smallest negative subnormal rather than `-0.0`. `from` equal to `toward` returns `toward`, which is what makes the sign of a zero come from the destination. A NaN in either argument gives a NaN. | Overload | Summary | | --------------------------------------------------------------- | -------------------------------------------------------------------------- | | `pub func NextAfter(from: float64, toward: float64) -> float64` | The value adjacent to `from` in the direction of `toward`. | | `pub func NextAfter(from: float32, toward: float32) -> float32` | Finds the `float32` value adjacent to `from` in the direction of `toward`. | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Math/Src/Classify.rux#L214){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | --------------------- | ----------------------------------- | | `from` | `float64` / `float32` | starting value | | `toward` | `float64` / `float32` | direction selected by another value | **Returns**: the value adjacent to `from` toward `toward`, or `toward` when they compare equal ## `NextUp` ```rux pub func NextUp(value: float64) -> float64 pub func NextUp(value: float32) -> float32 ``` Finds the next `float32` value above `value`. | Overload | Summary | | -------------------------------------------- | --------------------------------------------- | | `pub func NextUp(value: float64) -> float64` | The next representable value above `value`. | | `pub func NextUp(value: float32) -> float32` | Finds the next `float32` value above `value`. | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Math/Src/Classify.rux#L246){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------- | --------------------- | -------------- | | `value` | `float64` / `float32` | starting value | **Returns**: the adjacent value toward positive infinity ## `NextDown` ```rux pub func NextDown(value: float64) -> float64 pub func NextDown(value: float32) -> float32 ``` Finds the next `float32` value below `value`. | Overload | Summary | | ---------------------------------------------- | --------------------------------------------- | | `pub func NextDown(value: float64) -> float64` | The next representable value below `value`. | | `pub func NextDown(value: float32) -> float32` | Finds the next `float32` value below `value`. | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Math/Src/Classify.rux#L262){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------- | --------------------- | -------------- | | `value` | `float64` / `float32` | starting value | **Returns**: the adjacent value toward negative infinity ## `ScaleByPowerOfTwo` ```rux pub func ScaleByPowerOfTwo( value: float64, exponent: int64 ) -> float64 pub func ScaleByPowerOfTwo( value: float32, exponent: int64 ) -> float32 ``` `value` multiplied by two raised to `exponent`, with one rounding. The obvious spelling - multiplying by a computed power of two - overflows for large exponents and rounds twice when the answer lands in the subnormals. This steps in bounded pieces so neither happens: the result is correctly rounded once, and an exponent far outside the range saturates to an infinity or a zero rather than wrapping the exponent field into a wrong answer. | Overload | Summary | | ------------------------------------------------------------------------ | ---------------------------------------------------------------------- | | `pub func ScaleByPowerOfTwo(value: float64, exponent: int64) -> float64` | `value` multiplied by two raised to `exponent`, with one rounding. | | `pub func ScaleByPowerOfTwo(value: float32, exponent: int64) -> float32` | Multiplies `value` by two raised to `exponent` at `float32` precision. | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Math/Src/Classify.rux#L311){rel=""nofollow""} **Parameters** | Name | Type | Description | | ---------- | --------------------- | -------------------------------- | | `value` | `float64` / `float32` | value to scale | | `exponent` | `int64` | binary exponent added to `value` | **Returns**: `value * 2^exponent`, rounded once ## `ExponentOf` ```rux pub func ExponentOf(value: float64) -> int64 pub func ExponentOf(value: float32) -> int64 ``` The exponent of `value`: the power of two of its most significant bit. A normal value's exponent is such that its magnitude lies in `[2^e, 2^(e+1))`; a subnormal reports the exponent it would have with unbounded range, so the relationship keeps holding into the subnormals. Zero has no exponent and reports [`NoExponent`](https://rux-lang.dev/docs/api/math/float-representation#no-exponent), and a NaN or infinity reports [`IndeterminateExponent`](https://rux-lang.dev/docs/api/math/float-representation#indeterminate-exponent); both are values far outside any real exponent, so neither can be mistaken for one. | Overload | Summary | | ---------------------------------------------- | ---------------------------------------------------------------------- | | `pub func ExponentOf(value: float64) -> int64` | The exponent of `value`: the power of two of its most significant bit. | | `pub func ExponentOf(value: float32) -> int64` | Extracts the binary exponent of `value` at `float32` precision. | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Math/Src/Classify.rux#L339){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------- | --------------------- | --------------------------------- | | `value` | `float64` / `float32` | value whose exponent is extracted | **Returns**: its binary exponent, [`NoExponent`](https://rux-lang.dev/docs/api/math/float-representation#no-exponent) for zero, or [`IndeterminateExponent`](https://rux-lang.dev/docs/api/math/float-representation#indeterminate-exponent) for a NaN or infinity ## `NoExponent` ```rux pub const NoExponent: int64 = int64::Min; ``` What [`ExponentOf`](https://rux-lang.dev/docs/api/math/float-representation#exponent-of) reports for zero, which has no exponent at all. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Math/Src/Classify.rux#L363){rel=""nofollow""} ## `IndeterminateExponent` ```rux pub const IndeterminateExponent: int64 = int64::Max; ``` What [`ExponentOf`](https://rux-lang.dev/docs/api/math/float-representation#exponent-of) reports for a NaN or an infinity. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Math/Src/Classify.rux#L367){rel=""nofollow""} ## `Decompose` ```rux pub func Decompose( value: float64, exponent: *var int64 ) -> float64 pub func Decompose( value: float32, exponent: *var int64 ) -> float32 ``` Splits `value` into a fraction in `[0.5, 1)` and a power of two, so that `fraction * 2^exponent == value`. The classic decomposition. Zero gives zero with an exponent of zero, and a NaN or infinity is returned unchanged with an exponent of zero - neither has a decomposition, and inventing one would be worse than returning the value itself. The sign stays with the fraction. `exponent` must be non-null and writable. | Overload | Summary | | --------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------- | | `pub func Decompose(value: float64, exponent: *var int64) -> float64` | Splits `value` into a fraction in `[0.5, 1)` and a power of two, so that `fraction * 2^exponent == value`. | | `pub func Decompose(value: float32, exponent: *var int64) -> float32` | Decomposes `value` into a `float32` fraction and a binary exponent. | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Math/Src/Classify.rux#L377){rel=""nofollow""} **Parameters** | Name | Type | Description | | ---------- | --------------------- | ---------------------------- | | `value` | `float64` / `float32` | value to decompose | | `exponent` | `*var int64` | receives the binary exponent | **Returns**: the signed fraction, normally with magnitude in `[0.5, 1)` ## `SplitIntegral` ```rux pub func SplitIntegral( value: float64, integral: *var float64 ) -> float64 pub func SplitIntegral( value: float32, integral: *var float32 ) -> float32 ``` Splits `value` into its integral and fractional parts, both carrying its sign. `integral` receives the part toward zero and the fractional part is returned, so the two always sum back to `value` exactly. An infinity puts itself in `integral` and returns a zero of the same sign; a NaN puts a NaN in both. `integral` must be non-null and writable. | Overload | Summary | | --------------------------------------------------------------------------- | ------------------------------------------------------------------------------ | | `pub func SplitIntegral(value: float64, integral: *var float64) -> float64` | Splits `value` into its integral and fractional parts, both carrying its sign. | | `pub func SplitIntegral(value: float32, integral: *var float32) -> float32` | Splits `value` into integral and fractional `float32` parts. | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Math/Src/Classify.rux#L406){rel=""nofollow""} **Parameters** | Name | Type | Description | | ---------- | ------------------------------- | ------------------------------------- | | `value` | `float64` / `float32` | value to split | | `integral` | `*var float64` / `*var float32` | receives the part rounded toward zero | **Returns**: the signed fractional part ## `UlpDistance` ```rux pub func UlpDistance( left: float64, right: float64 ) -> uint64 pub func UlpDistance( left: float32, right: float32 ) -> uint64 ``` How many representable values lie between `left` and `right`. The natural way to state a floating-point error bound: two values are one ulp apart when nothing is representable between them, and a function accurate to half an ulp returns the nearest representable value to the true answer. Counting steps rather than subtracting is what makes the measure meaningful near zero, where the absolute difference between neighbours is vanishingly small, and near the maximum, where it is enormous. Values of opposite sign are counted through zero, with the two zeros treated as one value - the step from the smallest negative subnormal to the smallest positive one is two, not three. A NaN in either argument has no distance and reports the largest `uint64`, which no real distance can reach. | Overload | Summary | | --------------------------------------------------------------- | --------------------------------------------------------------------- | | `pub func UlpDistance(left: float64, right: float64) -> uint64` | How many representable values lie between `left` and `right`. | | `pub func UlpDistance(left: float32, right: float32) -> uint64` | Counts the representable `float32` values between `left` and `right`. | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Math/Src/Classify.rux#L445){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------- | --------------------- | ------------ | | `left` | `float64` / `float32` | first value | | `right` | `float64` / `float32` | second value | **Returns**: their distance in representable values, or the largest `uint64` when either is a NaN # Hyperbolic functions Hyperbolic sine, cosine, tangent and their inverses. ## `ArcSinh` ```rux pub func ArcSinh(x: float64) -> float64 pub func ArcSinh(x: float32) -> float32 ``` The inverse hyperbolic sine: the value whose hyperbolic sine is `x`. Defined for every real argument, odd, and unbounded in both directions. A NaN propagates and an infinity gives an infinity of the same sign. | Overload | Summary | | ----------------------------------------- | -------------------------------------------------------------------- | | `pub func ArcSinh(x: float64) -> float64` | The inverse hyperbolic sine: the value whose hyperbolic sine is `x`. | | `pub func ArcSinh(x: float32) -> float32` | Computes the inverse hyperbolic sine of `x` at `float32` precision. | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Math/Src/ArcHyperbolic.rux#L15){rel=""nofollow""} **Parameters** | Name | Type | Description | | ---- | --------------------- | ------------------------------- | | `x` | `float64` / `float32` | hyperbolic sine value to invert | **Returns**: the inverse hyperbolic sine of `x` ## `ArcCosh` ```rux pub func ArcCosh(x: float64) -> float64 pub func ArcCosh(x: float32) -> float32 ``` The inverse hyperbolic cosine: the non-negative value whose hyperbolic cosine is `x`. Defined only for arguments of one and above; anything below has no real answer and gives a NaN. The result is never negative, since the hyperbolic cosine is even and this returns the branch above zero. | Overload | Summary | | ----------------------------------------- | ------------------------------------------------------------------------------------- | | `pub func ArcCosh(x: float64) -> float64` | The inverse hyperbolic cosine: the non-negative value whose hyperbolic cosine is `x`. | | `pub func ArcCosh(x: float32) -> float32` | Computes the inverse hyperbolic cosine of `x` at `float32` precision. | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Math/Src/ArcHyperbolic.rux#L53){rel=""nofollow""} **Parameters** | Name | Type | Description | | ---- | --------------------- | --------------------------------- | | `x` | `float64` / `float32` | hyperbolic cosine value to invert | **Returns**: the non-negative inverse hyperbolic cosine of `x`, or a NaN when `x < 1` ## `ArcTanh` ```rux pub func ArcTanh(x: float64) -> float64 pub func ArcTanh(x: float32) -> float32 ``` The inverse hyperbolic tangent: the value whose hyperbolic tangent is `x`. Defined strictly inside the unit interval. The endpoints are the poles and give infinities of the matching sign; anything beyond them has no real answer and gives a NaN. | Overload | Summary | | ----------------------------------------- | -------------------------------------------------------------------------- | | `pub func ArcTanh(x: float64) -> float64` | The inverse hyperbolic tangent: the value whose hyperbolic tangent is `x`. | | `pub func ArcTanh(x: float32) -> float32` | Computes the inverse hyperbolic tangent of `x` at `float32` precision. | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Math/Src/ArcHyperbolic.rux#L80){rel=""nofollow""} **Parameters** | Name | Type | Description | | ---- | --------------------- | ---------------------------------- | | `x` | `float64` / `float32` | hyperbolic tangent value to invert | **Returns**: the inverse hyperbolic tangent of `x`, an infinity at either endpoint, or a NaN outside `[-1, 1]` ## `Cosh` ```rux pub func Cosh(x: float64) -> float64 pub func Cosh(x: float32) -> float32 ``` Computes the hyperbolic cosine of `x`. The result is at least one. Either infinity returns positive infinity, and a NaN remains a NaN. | Overload | Summary | | -------------------------------------- | ------------------------------------------------------------- | | `pub func Cosh(x: float64) -> float64` | Computes the hyperbolic cosine of `x`. | | `pub func Cosh(x: float32) -> float32` | Computes the hyperbolic cosine of `x` at `float32` precision. | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Math/Src/Cosh.rux#L11){rel=""nofollow""} **Parameters** | Name | Type | Description | | ---- | --------------------- | ---------------- | | `x` | `float64` / `float32` | hyperbolic angle | **Returns**: the hyperbolic cosine of `x` ## `Cotanh` ```rux pub func Cotanh(x: float64) -> float64 pub func Cotanh(x: float32) -> float32 ``` Computes the hyperbolic cotangent of `x`. A signed zero maps to an infinity with the same sign, infinities map to `-1` or `1`, and a NaN remains a NaN. | Overload | Summary | | ---------------------------------------- | ---------------------------------------------------------------- | | `pub func Cotanh(x: float64) -> float64` | Computes the hyperbolic cotangent of `x`. | | `pub func Cotanh(x: float32) -> float32` | Computes the hyperbolic cotangent of `x` at `float32` precision. | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Math/Src/Cotanh.rux#L11){rel=""nofollow""} **Parameters** | Name | Type | Description | | ---- | --------------------- | ---------------- | | `x` | `float64` / `float32` | hyperbolic angle | **Returns**: the hyperbolic cotangent of `x` ## `Sinh` ```rux pub func Sinh(x: float64) -> float64 pub func Sinh(x: float32) -> float32 ``` Computes the hyperbolic sine of `x`. A signed zero or infinity returns itself, and a NaN remains a NaN. | Overload | Summary | | -------------------------------------- | ----------------------------------------------------------- | | `pub func Sinh(x: float64) -> float64` | Computes the hyperbolic sine of `x`. | | `pub func Sinh(x: float32) -> float32` | Computes the hyperbolic sine of `x` at `float32` precision. | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Math/Src/Sinh.rux#L11){rel=""nofollow""} **Parameters** | Name | Type | Description | | ---- | --------------------- | ---------------- | | `x` | `float64` / `float32` | hyperbolic angle | **Returns**: the hyperbolic sine of `x` ## `Tanh` ```rux pub func Tanh(x: float64) -> float64 pub func Tanh(x: float32) -> float32 ``` Computes the hyperbolic tangent of `x`. The result lies in `[-1, 1]`. A signed zero returns itself, infinities map to the matching endpoint, and a NaN remains a NaN. | Overload | Summary | | -------------------------------------- | -------------------------------------------------------------- | | `pub func Tanh(x: float64) -> float64` | Computes the hyperbolic tangent of `x`. | | `pub func Tanh(x: float32) -> float32` | Computes the hyperbolic tangent of `x` at `float32` precision. | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Math/Src/Tanh.rux#L12){rel=""nofollow""} **Parameters** | Name | Type | Description | | ---- | --------------------- | ---------------- | | `x` | `float64` / `float32` | hyperbolic angle | **Returns**: the hyperbolic tangent of `x` # Integer arithmetic Checked and wrapping integer operations: magnitude, extrema, clamping, GCD, LCM and powers. ## `AbsChecked<T>` ```rux pub func AbsChecked<T>(value: T, result: *var T) -> bool ``` The magnitude of `value`, reporting whether it is representable. `result` receives the magnitude the machine produced, which is the true one when this returns `false` and the wrapped one when it returns `true`. Only one input can overflow: the most negative value of a signed type, whose magnitude is one larger than the maximum. An unsigned type never overflows here, since it is already its own magnitude. Runs in constant time and allocates nothing. `result` must be non-null and writable. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Math/Src/Integer.rux#L24){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | ------------ | | `T` | integer type | **Parameters** | Name | Type | Description | | -------- | -------- | ---------------------------------------------------- | | `value` | `T` | value whose magnitude is computed | | `result` | `*var T` | receives the magnitude or its wrapped representation | **Returns**: `true` when the mathematical magnitude is not representable as `T` ## `AbsWrapping<T>` ```rux pub func AbsWrapping<T>(value: T) -> T ``` The magnitude of `value`, wrapping where it is not representable. The most negative value of a signed type comes back unchanged, which is what the machine's own negation does. Use [`AbsChecked`](https://rux-lang.dev/docs/api/math/integer#abs-checked) where that matters. Runs in constant time and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Math/Src/Integer.rux#L43){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | ------------ | | `T` | integer type | **Parameters** | Name | Type | Description | | ------- | ---- | --------------------------------- | | `value` | `T` | value whose magnitude is computed | **Returns**: the magnitude of `value`, wrapping when necessary ## `Minimum<T>` ```rux pub func Minimum<T>(left: T, right: T) -> T ``` The smaller of two integers. Total and exact: integers have no NaN, so unlike the floating-point [`Min`](https://rux-lang.dev/docs/api/math/abs-min-max#min) there is no case to decide. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Math/Src/Integer.rux#L56){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | ------------ | | `T` | integer type | **Parameters** | Name | Type | Description | | ------- | ---- | ----------------------- | | `left` | `T` | first value to compare | | `right` | `T` | second value to compare | **Returns**: the smaller value ## `Maximum<T>` ```rux pub func Maximum<T>(left: T, right: T) -> T ``` The larger of two integers. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Math/Src/Integer.rux#L66){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | ------------ | | `T` | integer type | **Parameters** | Name | Type | Description | | ------- | ---- | ----------------------- | | `left` | `T` | first value to compare | | `right` | `T` | second value to compare | **Returns**: the larger value ## `Clamp<T>` ```rux pub func Clamp<T>(value: T, low: T, high: T) -> T ``` `value` brought into `[low, high]`. A contradictory pair - `low` above `high` - has no correct answer, and this returns `low` rather than pretending otherwise. The behavior is stated so it is at least deterministic; callers who cannot rule the case out should check the bounds themselves. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Math/Src/Integer.rux#L80){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | ------------ | | `T` | integer type | **Parameters** | Name | Type | Description | | ------- | ---- | --------------------- | | `value` | `T` | value to constrain | | `low` | `T` | inclusive lower bound | | `high` | `T` | inclusive upper bound | **Returns**: `value` constrained to `[low, high]`, or `low` when the bounds contradict each other ## `GcdChecked<T>` ```rux pub func GcdChecked<T>( left: T, right: T, result: *var T ) -> bool ``` The greatest common divisor of `left` and `right`, reporting whether it is representable. Defined on magnitudes, so signs do not matter and the answer is never negative. `Gcd(0, 0)` is zero, which is the conventional answer and the only one that keeps `Gcd(x, 0) == |x|` true everywhere. The single overflow is a divisor equal to the magnitude of the most negative value - reachable only as `Gcd(min, 0)` and `Gcd(min, min)` - which no signed type can express. Runs in time proportional to the number of bits and allocates nothing. `result` must be non-null and writable. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Math/Src/Integer.rux#L98){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | ------------ | | `T` | integer type | **Parameters** | Name | Type | Description | | -------- | -------- | ----------------------------------------------------------------------- | | `left` | `T` | first integer | | `right` | `T` | second integer | | `result` | `*var T` | receives the greatest common divisor or its unrepresentable bit pattern | **Returns**: `true` when the non-negative divisor is not representable as `T` ## `LcmChecked<T>` ```rux pub func LcmChecked<T>( left: T, right: T, result: *var T ) -> bool ``` The least common multiple of `left` and `right`, reporting whether it is representable. Zero with anything is zero, which keeps the identity `Gcd(a, b) * Lcm(a, b) == |a * b|` true. Everything else overflows readily - two coprime values multiply - so the flag is the usual case rather than the exception, and the division is done before the multiplication so a representable answer is not lost to an intermediate that is not. `result` must be non-null and writable. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Math/Src/Integer.rux#L131){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | ------------ | | `T` | integer type | **Parameters** | Name | Type | Description | | -------- | -------- | ------------------------------------------------------------ | | `left` | `T` | first integer | | `right` | `T` | second integer | | `result` | `*var T` | receives the least common multiple or a wrapped intermediate | **Returns**: `true` when the least common multiple is not representable as `T` ## `PowChecked<T>` ```rux pub func PowChecked<T>( base: T, exponent: uint, result: *var T ) -> bool ``` `base` raised to `exponent`, reporting whether the true power is representable. The exponent is a plain `uint` because a negative exponent has no integer answer. Anything to the zeroth power is one, including zero: the empty product is one, and every identity that matters depends on it. `result` receives the wrapped power when this returns `true`, so a caller who wants modular arithmetic can use it directly. Runs in time proportional to the number of bits in `exponent`. `result` must be non-null and writable. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Math/Src/Integer.rux#L158){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | ------------ | | `T` | integer type | **Parameters** | Name | Type | Description | | ---------- | -------- | ---------------------------------------- | | `base` | `T` | integer base | | `exponent` | `uint` | non-negative exponent | | `result` | `*var T` | receives the power, wrapping on overflow | **Returns**: `true` when the mathematical power is not representable as `T` # Powers and roots Raising to a power, square and cube roots, and the hypotenuse. ## `Cbrt` ```rux pub func Cbrt(x: float64) -> float64 pub func Cbrt(x: float32) -> float32 ``` Computes the real cube root of `x`. The error is at most one ulp. Negative inputs produce negative roots, a signed zero or infinity returns itself, and a NaN remains a NaN. | Overload | Summary | | -------------------------------------- | ---------------------------------------------------------- | | `pub func Cbrt(x: float64) -> float64` | Computes the real cube root of `x`. | | `pub func Cbrt(x: float32) -> float32` | Computes the real cube root of `x` at `float32` precision. | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Math/Src/Cbrt.rux#L12){rel=""nofollow""} **Parameters** | Name | Type | Description | | ---- | --------------------- | --------------------------------- | | `x` | `float64` / `float32` | value whose cube root is computed | **Returns**: the real cube root of `x` ## `Hypot` ```rux pub func Hypot(x: float64, y: float64) -> float64 pub func Hypot(x: float32, y: float32) -> float32 ``` Computes the Euclidean length `Sqrt(x * x + y * y)` without intermediate overflow or underflow. The error is at most one ulp. An infinity in either argument returns positive infinity even when the other is a NaN; otherwise a NaN remains a NaN. | Overload | Summary | | --------------------------------------------------- | ----------------------------------------------------------------------------------------------- | | `pub func Hypot(x: float64, y: float64) -> float64` | Computes the Euclidean length `Sqrt(x * x + y * y)` without intermediate overflow or underflow. | | `pub func Hypot(x: float32, y: float32) -> float32` | Computes the Euclidean length of `(x, y)` at `float32` precision. | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Math/Src/Hypot.rux#L13){rel=""nofollow""} **Parameters** | Name | Type | Description | | ---- | --------------------- | -------------------------- | | `x` | `float64` / `float32` | first Cartesian component | | `y` | `float64` / `float32` | second Cartesian component | **Returns**: the non-negative length of `(x, y)` ## `Pow` ```rux pub func Pow(x: float64, y: float64) -> float64 pub func Pow(x: float32, y: float32) -> float32 ``` Raises `x` to the power `y`. The error is at most one ulp. A negative base requires an integer exponent; otherwise the result is a NaN. [`PowInteger`](https://rux-lang.dev/docs/api/math/powers#pow-integer) is both faster and able to preserve exact results when the exponent is an integer. | Overload | Summary | | ------------------------------------------------- | --------------------------------------------------- | | `pub func Pow(x: float64, y: float64) -> float64` | Raises `x` to the power `y`. | | `pub func Pow(x: float32, y: float32) -> float32` | Raises `x` to the power `y` at `float32` precision. | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Math/Src/Pow.rux#L164){rel=""nofollow""} **Parameters** | Name | Type | Description | | ---- | --------------------- | ----------- | | `x` | `float64` / `float32` | base | | `y` | `float64` / `float32` | exponent | **Returns**: `x` raised to `y` ## `PowInteger` ```rux pub func PowInteger( base: float64, exponent: int64 ) -> float64 pub func PowInteger( base: float32, exponent: int64 ) -> float32 ``` `base` raised to the integer power `exponent`. A zero exponent gives one for every base, including zero and a NaN, which is the same rule `Pow` follows: the empty product is one. A negative exponent takes the reciprocal at the end rather than dividing as it goes, which keeps the intermediates as large as possible and loses the least. | Overload | Summary | | ---------------------------------------------------------------- | --------------------------------------------------------------------- | | `pub func PowInteger(base: float64, exponent: int64) -> float64` | `base` raised to the integer power `exponent`. | | `pub func PowInteger(base: float32, exponent: int64) -> float32` | Raises `base` to the integer power `exponent` at `float32` precision. | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Math/Src/PowInteger.rux#L17){rel=""nofollow""} **Parameters** | Name | Type | Description | | ---------- | --------------------- | -------------- | | `base` | `float64` / `float32` | value to raise | | `exponent` | `int64` | integer power | **Returns**: `base` raised to `exponent` ## `Sqrt` ```rux pub func Sqrt(x: float32) -> float32 pub func Sqrt(x: float64) -> float64 ``` Computes the correctly rounded square root of `x` at `float32` precision. A signed zero, positive infinity, or NaN passes through; a negative finite value returns a NaN. | Overload | Summary | | -------------------------------------- | ------------------------------------------------------------------------- | | `pub func Sqrt(x: float32) -> float32` | Computes the correctly rounded square root of `x` at `float32` precision. | | `pub func Sqrt(x: float64) -> float64` | Computes the correctly rounded square root of `x`. | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Math/Src/Sqrt.rux#L18){rel=""nofollow""} **Parameters** | Name | Type | Description | | ---- | --------------------- | ----------------------------------- | | `x` | `float32` / `float64` | value whose square root is computed | **Returns**: the non-negative square root of `x`, or a NaN when `x` is negative # Rounding and remainders Rounding to an integral value in a chosen direction, and the floating-point remainder. ## `Ceil` ```rux pub func Ceil(x: float64) -> float64 pub func Ceil(x: float32) -> float32 ``` Rounds `x` toward positive infinity to an integral value. A negative value between zero and negative one becomes `-0.0`. A NaN or infinity passes through unchanged. | Overload | Summary | | -------------------------------------- | ----------------------------------------------------------- | | `pub func Ceil(x: float64) -> float64` | Rounds `x` toward positive infinity to an integral value. | | `pub func Ceil(x: float32) -> float32` | Rounds `x` toward positive infinity at `float32` precision. | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Math/Src/Ceil.rux#L12){rel=""nofollow""} **Parameters** | Name | Type | Description | | ---- | --------------------- | --------------------- | | `x` | `float64` / `float32` | value to round upward | **Returns**: the smallest integral value greater than or equal to `x` ## `Floor` ```rux pub func Floor(x: float64) -> float64 pub func Floor(x: float32) -> float32 ``` Rounds `x` toward negative infinity to an integral value. The sign of zero is preserved. A NaN or infinity passes through unchanged. | Overload | Summary | | --------------------------------------- | ----------------------------------------------------------- | | `pub func Floor(x: float64) -> float64` | Rounds `x` toward negative infinity to an integral value. | | `pub func Floor(x: float32) -> float32` | Rounds `x` toward negative infinity at `float32` precision. | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Math/Src/Floor.rux#L10){rel=""nofollow""} **Parameters** | Name | Type | Description | | ---- | --------------------- | ----------------------- | | `x` | `float64` / `float32` | value to round downward | **Returns**: the largest integral value less than or equal to `x` ## `Mod` ```rux pub func Mod(x: float64, y: float64) -> float64 pub func Mod(x: float32, y: float32) -> float32 ``` Computes the floating-point remainder of `x / y`, with the sign of `x`. The result is `x - n * y`, where `n` is `x / y` truncated toward zero. Its magnitude is less than `|y|`. A zero divisor, an infinite dividend, or a NaN operand returns a NaN; an infinite divisor returns `x`. The significands are reduced with integer long division so the intermediate product cannot discard the remainder. | Overload | Summary | | ------------------------------------------------- | ---------------------------------------------------------------------------------------------- | | `pub func Mod(x: float64, y: float64) -> float64` | Computes the floating-point remainder of `x / y`, with the sign of `x`. | | `pub func Mod(x: float32, y: float32) -> float32` | Computes the floating-point remainder of `x / y` at `float32` precision, with the sign of `x`. | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Math/Src/Mod.rux#L14){rel=""nofollow""} **Parameters** | Name | Type | Description | | ---- | --------------------- | ----------- | | `x` | `float64` / `float32` | dividend | | `y` | `float64` / `float32` | divisor | **Returns**: the exact remainder, or a NaN when no remainder is defined ## `Round` ```rux pub func Round(x: float64) -> float64 pub func Round(x: float32) -> float32 ``` Rounds `x` to the nearest integral value, with halfway cases away from zero. Thus `Round(2.5)` is `3.0` and `Round(-2.5)` is `-3.0`. The sign of zero is preserved, and a NaN or infinity passes through unchanged. The fractional part is compared directly instead of adding one half, which avoids prematurely rounding the largest representable value below `0.5` up to `1.0`. | Overload | Summary | | --------------------------------------- | --------------------------------------------------------------------------------------------------- | | `pub func Round(x: float64) -> float64` | Rounds `x` to the nearest integral value, with halfway cases away from zero. | | `pub func Round(x: float32) -> float32` | Rounds `x` to the nearest integral value at `float32` precision, with halfway cases away from zero. | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Math/Src/Round.rux#L13){rel=""nofollow""} **Parameters** | Name | Type | Description | | ---- | --------------------- | -------------- | | `x` | `float64` / `float32` | value to round | **Returns**: the nearest integral value ## `RoundingMode` ```rux pub enum RoundingMode: int32 { TowardZero = 0, TowardNegative = 1, TowardPositive = 2, ToNearestTiesAway = 3, ToNearestTiesEven = 4 } ``` Which way a value that falls between two integers should go. `Copy`. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Math/Src/Rounding.rux#L16){rel=""nofollow""} **Cases** | Name | Value | Description | | ------------------- | ----- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `TowardZero` | `0` | Toward zero, discarding the fraction: [`Trunc`](https://rux-lang.dev/docs/api/math/rounding#trunc). | | `TowardNegative` | `1` | Downward, toward negative infinity: [`Floor`](https://rux-lang.dev/docs/api/math/rounding#floor). | | `TowardPositive` | `2` | Upward, toward positive infinity: [`Ceil`](https://rux-lang.dev/docs/api/math/rounding#ceil). | | `ToNearestTiesAway` | `3` | To the nearest, with a halfway value going away from zero: [`Round`](https://rux-lang.dev/docs/api/math/rounding#round). What most people mean by rounding, and what school teaches. | | `ToNearestTiesEven` | `4` | To the nearest, with a halfway value going to the even neighbour. IEEE 754's default, and the one that keeps a long run of roundings from drifting: ties away from zero rounds up half the time and down never. | ## `RoundTiesToEven` ```rux pub func RoundTiesToEven(value: float64) -> float64 pub func RoundTiesToEven(value: float32) -> float32 ``` The nearest integer to `value`, with a halfway value going to the even neighbour. `RoundTiesToEven(2.5)` is 2 and `RoundTiesToEven(3.5)` is 4, where [`Round`](https://rux-lang.dev/docs/api/math/rounding#round) gives 3 and 4. The sign of a zero is preserved, and a NaN or infinity passes through unchanged. | Overload | Summary | | ----------------------------------------------------- | ------------------------------------------------------------------------------------------------- | | `pub func RoundTiesToEven(value: float64) -> float64` | The nearest integer to `value`, with a halfway value going to the even neighbour. | | `pub func RoundTiesToEven(value: float32) -> float32` | Rounds `value` to the nearest integral `float32`, with halfway cases going to the even neighbour. | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Math/Src/Rounding.rux#L38){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------- | --------------------- | -------------- | | `value` | `float64` / `float32` | value to round | **Returns**: the nearest integral value, resolving halfway cases toward the even neighbour ## `RoundTo` ```rux pub func RoundTo( value: float64, mode: RoundingMode ) -> float64 pub func RoundTo( value: float32, mode: RoundingMode ) -> float32 ``` Rounds `value` in the requested direction at `float32` precision. | Overload | Summary | | ----------------------------------------------------------------- | ----------------------------------------------------------------- | | `pub func RoundTo(value: float64, mode: RoundingMode) -> float64` | `value` rounded to an integer in the named direction. | | `pub func RoundTo(value: float32, mode: RoundingMode) -> float32` | Rounds `value` in the requested direction at `float32` precision. | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Math/Src/Rounding.rux#L68){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------- | --------------------- | --------------------------------- | | `value` | `float64` / `float32` | value to round | | `mode` | `RoundingMode` | direction and halfway rule to use | **Returns**: the integral value selected by `mode` ## `ToIntegerChecked<T>` ```rux pub func ToIntegerChecked<T>( value: float64, sample: T, mode: RoundingMode, result: *var T ) -> bool ``` `value` rounded in the named direction and converted to an integer, reporting whether it fits. `sample` is read by value and only its type matters, exactly as `Core`'s `MaximumOf` reads one. Returns `true` when the rounded value is not representable in the integer type — because it is a NaN, an infinity, or simply out of range — and leaves `result` zero in that case. This is the only place a float becomes an integer, and it refuses rather than saturating, because a caller who has not thought about the out-of-range case is better served by a flag than by a plausible wrong number. `result` must be non-null and writable. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Math/Src/Rounding.rux#L102){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | ------------------------ | | `T` | destination integer type | **Parameters** | Name | Type | Description | | -------- | -------------- | ------------------------------------------------- | | `value` | `float64` | floating-point value to convert | | `sample` | `T` | value used only to select `T` | | `mode` | `RoundingMode` | rounding rule applied before conversion | | `result` | `*var T` | receives the converted integer or zero on failure | **Returns**: `true` when the rounded value is not representable as `T` ## `Trunc` ```rux pub func Trunc(x: float64) -> float64 pub func Trunc(x: float32) -> float32 ``` Rounds `x` toward zero to an integral value at `float32` precision. The wide result is exactly representable at the input width, so narrowing it back to `float32` loses nothing. | Overload | Summary | | --------------------------------------- | ------------------------------------------------------------------- | | `pub func Trunc(x: float64) -> float64` | Rounds `x` toward zero to an integral value. | | `pub func Trunc(x: float32) -> float32` | Rounds `x` toward zero to an integral value at `float32` precision. | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Math/Src/Trunc.rux#L11){rel=""nofollow""} **Parameters** | Name | Type | Description | | ---- | --------------------- | ----------------- | | `x` | `float64` / `float32` | value to truncate | **Returns**: the integral part of `x` # Trigonometry Sine, cosine, tangent, their inverses, and conversion between degrees and radians. ## `DegToRad` ```rux pub func DegToRad(x: float64) -> float64 pub func DegToRad(x: float32) -> float32 ``` Converts an angle from degrees to radians. The conversion scales by the nearest `float64` to `Pi / 180`, making `DegToRad(180.0)` exactly [`Pi`](https://rux-lang.dev/docs/api/math/constants#pi). A signed zero keeps its sign, infinities keep their sign, and a NaN remains a NaN. | Overload | Summary | | ------------------------------------------ | ----------------------------------------------------------------- | | `pub func DegToRad(x: float64) -> float64` | Converts an angle from degrees to radians. | | `pub func DegToRad(x: float32) -> float32` | Converts an angle from degrees to radians at `float32` precision. | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Math/Src/Angle.rux#L12){rel=""nofollow""} **Parameters** | Name | Type | Description | | ---- | --------------------- | ---------------- | | `x` | `float64` / `float32` | angle in degrees | **Returns**: the equivalent angle in radians ## `RadToDeg` ```rux pub func RadToDeg(x: float64) -> float64 pub func RadToDeg(x: float32) -> float32 ``` Converts an angle from radians to degrees. The conversion scales by the nearest `float64` to `180 / Pi`, making `RadToDeg(Pi)` exactly `180.0`. A signed zero keeps its sign, infinities keep their sign, and a NaN remains a NaN. | Overload | Summary | | ------------------------------------------ | ----------------------------------------------------------------- | | `pub func RadToDeg(x: float64) -> float64` | Converts an angle from radians to degrees. | | `pub func RadToDeg(x: float32) -> float32` | Converts an angle from radians to degrees at `float32` precision. | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Math/Src/Angle.rux#L31){rel=""nofollow""} **Parameters** | Name | Type | Description | | ---- | --------------------- | ---------------- | | `x` | `float64` / `float32` | angle in radians | **Returns**: the equivalent angle in degrees ## `ArcCos` ```rux pub func ArcCos(x: float64) -> float64 pub func ArcCos(x: float32) -> float32 ``` Computes the inverse cosine of `x` in radians. The result lies in `[0, Pi]`: `1.0` maps to zero, either signed zero maps to `Pi / 2`, and `-1.0` maps to [`Pi`](https://rux-lang.dev/docs/api/math/constants#pi). An input outside `[-1, 1]` returns a NaN, and a NaN remains a NaN. | Overload | Summary | | ---------------------------------------- | --------------------------------------------------------------------- | | `pub func ArcCos(x: float64) -> float64` | Computes the inverse cosine of `x` in radians. | | `pub func ArcCos(x: float32) -> float32` | Computes the inverse cosine of `x` in radians at `float32` precision. | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Math/Src/ArcCos.rux#L14){rel=""nofollow""} **Parameters** | Name | Type | Description | | ---- | --------------------- | ---------------------- | | `x` | `float64` / `float32` | cosine value to invert | **Returns**: the angle in radians whose cosine is `x`, or a NaN when `x` is outside the function's domain ## `ArcCot` ```rux pub func ArcCot(x: float64) -> float64 pub func ArcCot(x: float32) -> float32 ``` Computes the inverse cotangent of `x` in radians. The result lies in `[0, Pi]`: positive infinity maps to zero, either signed zero maps to `Pi / 2`, and negative infinity maps to [`Pi`](https://rux-lang.dev/docs/api/math/constants#pi). A NaN remains a NaN. | Overload | Summary | | ---------------------------------------- | ------------------------------------------------------------------------ | | `pub func ArcCot(x: float64) -> float64` | Computes the inverse cotangent of `x` in radians. | | `pub func ArcCot(x: float32) -> float32` | Computes the inverse cotangent of `x` in radians at `float32` precision. | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Math/Src/ArcCot.rux#L12){rel=""nofollow""} **Parameters** | Name | Type | Description | | ---- | --------------------- | ------------------------- | | `x` | `float64` / `float32` | cotangent value to invert | **Returns**: the angle in radians whose cotangent is `x` ## `ArcSin` ```rux pub func ArcSin(x: float64) -> float64 pub func ArcSin(x: float32) -> float32 ``` Computes the inverse sine of `x` in radians. The result lies in `[-Pi / 2, Pi / 2]`. A signed zero returns itself, either endpoint maps to the matching endpoint of the result range, an input outside `[-1, 1]` returns a NaN, and a NaN remains a NaN. | Overload | Summary | | ---------------------------------------- | ------------------------------------------------------------------- | | `pub func ArcSin(x: float64) -> float64` | Computes the inverse sine of `x` in radians. | | `pub func ArcSin(x: float32) -> float32` | Computes the inverse sine of `x` in radians at `float32` precision. | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Math/Src/ArcSin.rux#L14){rel=""nofollow""} **Parameters** | Name | Type | Description | | ---- | --------------------- | -------------------- | | `x` | `float64` / `float32` | sine value to invert | **Returns**: the angle in radians whose sine is `x`, or a NaN when `x` is outside the function's domain ## `ArcTan` ```rux pub func ArcTan(x: float64) -> float64 pub func ArcTan(x: float32) -> float32 ``` Computes the inverse tangent of `x` in radians. The result lies in `[-Pi / 2, Pi / 2]`. A signed zero returns itself, infinities approach the matching endpoint, and a NaN remains a NaN. | Overload | Summary | | ---------------------------------------- | ---------------------------------------------------------------------- | | `pub func ArcTan(x: float64) -> float64` | Computes the inverse tangent of `x` in radians. | | `pub func ArcTan(x: float32) -> float32` | Computes the inverse tangent of `x` in radians at `float32` precision. | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Math/Src/ArcTan.rux#L13){rel=""nofollow""} **Parameters** | Name | Type | Description | | ---- | --------------------- | ----------------------- | | `x` | `float64` / `float32` | tangent value to invert | **Returns**: the angle in radians whose tangent is `x` ## `ArcTan2` ```rux pub func ArcTan2(y: float64, x: float64) -> float64 pub func ArcTan2(y: float32, x: float32) -> float32 ``` The angle from the positive x axis to the point `(x, y)`, in radians, in `(-Pi, Pi]`. The sign of `y` decides the sign of the result, including when `y` is a zero — which is what makes the function continuous as a point crosses the negative x axis from below, and why a signed zero matters here more than almost anywhere else. | Overload | Summary | | ----------------------------------------------------- | ------------------------------------------------------------------------------------- | | `pub func ArcTan2(y: float64, x: float64) -> float64` | The angle from the positive x axis to the point `(x, y)`, in radians, in `(-Pi, Pi]`. | | `pub func ArcTan2(y: float32, x: float32) -> float32` | Computes the angle from the positive x axis to `(x, y)` at `float32` precision. | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Math/Src/ArcTan2.rux#L18){rel=""nofollow""} **Parameters** | Name | Type | Description | | ---- | --------------------- | --------------------- | | `y` | `float64` / `float32` | vertical coordinate | | `x` | `float64` / `float32` | horizontal coordinate | **Returns**: the signed angle from the positive x axis to `(x, y)` ## `Cos` ```rux pub func Cos(x: float64) -> float64 pub func Cos(x: float32) -> float32 ``` Computes the cosine of `x`, where `x` is in radians. The error is at most one ulp for every finite argument. Exact argument reduction keeps a large angle no less accurate than a small one. Either signed zero returns `1.0`; an infinity returns a NaN, and a NaN remains a NaN. | Overload | Summary | | ------------------------------------- | --------------------------------------------------------------------------- | | `pub func Cos(x: float64) -> float64` | Computes the cosine of `x`, where `x` is in radians. | | `pub func Cos(x: float32) -> float32` | Computes the cosine of `x` at `float32` precision, where `x` is in radians. | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Math/Src/Cos.rux#L14){rel=""nofollow""} **Parameters** | Name | Type | Description | | ---- | --------------------- | ---------------- | | `x` | `float64` / `float32` | angle in radians | **Returns**: the cosine of `x`, in `[-1, 1]`, or a NaN when `x` is not finite ## `Cotan` ```rux pub func Cotan(x: float64) -> float64 pub func Cotan(x: float32) -> float32 ``` Computes the cotangent of `x`, where `x` is in radians. The reciprocal is computed directly instead of as `1 / Tan(x)`, avoiding a second rounding near a pole. A signed zero maps to an infinity with the same sign; an infinite input returns a NaN, and a NaN remains a NaN. | Overload | Summary | | --------------------------------------- | ------------------------------------------------------------------------------ | | `pub func Cotan(x: float64) -> float64` | Computes the cotangent of `x`, where `x` is in radians. | | `pub func Cotan(x: float32) -> float32` | Computes the cotangent of `x` at `float32` precision, where `x` is in radians. | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Math/Src/Cotan.rux#L14){rel=""nofollow""} **Parameters** | Name | Type | Description | | ---- | --------------------- | ---------------- | | `x` | `float64` / `float32` | angle in radians | **Returns**: the cotangent of `x`, or a NaN when `x` is not finite ## `Sin` ```rux pub func Sin(x: float64) -> float64 pub func Sin(x: float32) -> float32 ``` Computes the sine of `x`, where `x` is in radians. The error is at most one ulp for every finite argument. Exact argument reduction keeps a large angle no less accurate than a small one. A signed zero returns itself; an infinity returns a NaN, and a NaN remains a NaN. | Overload | Summary | | ------------------------------------- | ------------------------------------------------------------------------- | | `pub func Sin(x: float64) -> float64` | Computes the sine of `x`, where `x` is in radians. | | `pub func Sin(x: float32) -> float32` | Computes the sine of `x` at `float32` precision, where `x` is in radians. | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Math/Src/Sin.rux#L14){rel=""nofollow""} **Parameters** | Name | Type | Description | | ---- | --------------------- | ---------------- | | `x` | `float64` / `float32` | angle in radians | **Returns**: the sine of `x`, in `[-1, 1]`, or a NaN when `x` is not finite ## `SinCos` ```rux pub func SinCos(angle: float64) -> (float64, float64) pub func SinCos(angle: float32) -> (float32, float32) ``` Computes the sine and cosine of `angle` from one argument reduction. Returns `(sine, cosine)`. Equivalent to calling [`Sin`](https://rux-lang.dev/docs/api/math/trigonometry#sin) and [`Cos`](https://rux-lang.dev/docs/api/math/trigonometry#cos) separately, at roughly half the cost. | Overload | Summary | | ------------------------------------------------------- | -------------------------------------------------------------------- | | `pub func SinCos(angle: float64) -> (float64, float64)` | Computes the sine and cosine of `angle` from one argument reduction. | | `pub func SinCos(angle: float32) -> (float32, float32)` | Computes the sine and cosine of `angle` at `float32` precision. | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Math/Src/SinCos.rux#L21){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------- | --------------------- | ---------------- | | `angle` | `float64` / `float32` | angle in radians | **Returns**: `(sine, cosine)` for `angle` ## `Tan` ```rux pub func Tan(x: float64) -> float64 pub func Tan(x: float32) -> float32 ``` Computes the tangent of `x`, where `x` is in radians. The error is at most one ulp for finite arguments away from poles. Exact argument reduction retains all available information near an odd multiple of `Pi / 2`. A signed zero returns itself; an infinity returns a NaN, and a NaN remains a NaN. | Overload | Summary | | ------------------------------------- | ---------------------------------------------------------------------------- | | `pub func Tan(x: float64) -> float64` | Computes the tangent of `x`, where `x` is in radians. | | `pub func Tan(x: float32) -> float32` | Computes the tangent of `x` at `float32` precision, where `x` is in radians. | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Math/Src/Tan.rux#L15){rel=""nofollow""} **Parameters** | Name | Type | Description | | ---- | --------------------- | ---------------- | | `x` | `float64` / `float32` | angle in radians | **Returns**: the tangent of `x`, or a NaN when `x` is not finite # Constants Mathematical constants, rounded to the nearest float64. ## `E` ```rux pub const E: float64 = 2.718281828459045; ``` Euler's number, the base of the natural logarithm, rounded to the nearest `float64`. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Math/Src/Const.rux#L8){rel=""nofollow""} ## `Ln2` ```rux pub const Ln2: float64 = 0.6931471805599453; ``` The natural logarithm of two, rounded to the nearest `float64`. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Math/Src/Const.rux#L12){rel=""nofollow""} ## `Log2E` ```rux pub const Log2E: float64 = 1.4426950408889634; ``` The base-two logarithm of [`E`](https://rux-lang.dev/docs/api/math/constants#e), rounded to the nearest `float64`. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Math/Src/Const.rux#L16){rel=""nofollow""} ## `Ln10` ```rux pub const Ln10: float64 = 2.302585092994046; ``` The natural logarithm of ten, rounded to the nearest `float64`. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Math/Src/Const.rux#L20){rel=""nofollow""} ## `Log10E` ```rux pub const Log10E: float64 = 0.4342944819032518; ``` The base-ten logarithm of [`E`](https://rux-lang.dev/docs/api/math/constants#e), rounded to the nearest `float64`. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Math/Src/Const.rux#L24){rel=""nofollow""} ## `Pi` ```rux pub const Pi: float64 = 3.141592653589793; ``` The ratio of a circle's circumference to its diameter, rounded to the nearest `float64`. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Math/Src/Const.rux#L28){rel=""nofollow""} ## `Tau` ```rux pub const Tau: float64 = 6.283185307179586; ``` One full turn in radians, equal to `2 * Pi` and rounded to the nearest `float64`. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Math/Src/Const.rux#L32){rel=""nofollow""} ## `HalfPi` ```rux pub const HalfPi: float64 = 1.5707963267948966; ``` One quarter turn in radians, equal to `Pi / 2` and rounded to the nearest `float64`. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Math/Src/Const.rux#L36){rel=""nofollow""} ## `QuarterPi` ```rux pub const QuarterPi: float64 = 0.7853981633974483; ``` One eighth turn in radians, equal to `Pi / 4` and rounded to the nearest `float64`. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Math/Src/Const.rux#L40){rel=""nofollow""} ## `InvPi` ```rux pub const InvPi: float64 = 0.3183098861837907; ``` The reciprocal of [`Pi`](https://rux-lang.dev/docs/api/math/constants#pi), rounded to the nearest `float64`. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Math/Src/Const.rux#L44){rel=""nofollow""} ## `InvTau` ```rux pub const InvTau: float64 = 0.15915494309189535; ``` The reciprocal of [`Tau`](https://rux-lang.dev/docs/api/math/constants#tau), rounded to the nearest `float64`. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Math/Src/Const.rux#L48){rel=""nofollow""} ## `Sqrt2` ```rux pub const Sqrt2: float64 = 1.4142135623730951; ``` The square root of two, rounded to the nearest `float64`. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Math/Src/Const.rux#L52){rel=""nofollow""} ## `InvSqrt2` ```rux pub const InvSqrt2: float64 = 0.7071067811865476; ``` The reciprocal of [`Sqrt2`](https://rux-lang.dev/docs/api/math/constants#sqrt2), rounded to the nearest `float64`. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Math/Src/Const.rux#L56){rel=""nofollow""} ## `RadPerDeg` ```rux pub const RadPerDeg: float64 = 0.017453292519943295; ``` Radians per degree, equal to `Pi / 180` and rounded to the nearest `float64`. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Math/Src/Const.rux#L60){rel=""nofollow""} ## `DegPerRad` ```rux pub const DegPerRad: float64 = 57.29577951308232; ``` Degrees per radian, equal to `180 / Pi` and rounded to the nearest `float64`. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Math/Src/Const.rux#L64){rel=""nofollow""} # Text Strings and fundamental text manipulation. ## Installation Add `Text` to the `[Dependencies]` table of your package's `Rux.toml`: ```toml [Dependencies] Text = { Namespace = "Rux", Version = "0.1.0" } ``` Standard packages are declared by hand: the registry does not serve them, so `rux add Rux/Text` cannot add them. ## Dependencies - [`Allocator`](https://rux-lang.dev/docs/api/allocator) 0.1.0 - [`Core`](https://rux-lang.dev/docs/api/core) 0.1.0 - [`Memory`](https://rux-lang.dev/docs/api/memory) 0.1.0 - [`Unicode`](https://rux-lang.dev/docs/api/unicode) 0.1.0 ## Guide ### What it provides - **[`StringView`](https://rux-lang.dev/docs/api/text/string-view)** — a borrowed run of bytes checked once to be UTF-8, so everything downstream may assume text and be right. Byte-indexed; a cut off a character boundary is refused rather than rounded. Search, trim, split and the walk over lines live here, since they answer questions about bytes that already exist and allocate nothing. - **[`String`](https://rux-lang.dev/docs/api/text/string)** — immutable text with value semantics. Language copies allocate an independent block from the same allocator; [`Clone`](https://rux-lang.dev/docs/api/text/string#clone) reports allocation failure when it must be handled explicitly. - **[`StringBuilder`](https://rux-lang.dev/docs/api/text/string-builder)** — where text is assembled. Keeps spare room and doubles it, holds well-formed UTF-8 at every moment, and hands its block over through [`IntoString`](https://rux-lang.dev/docs/api/text/string-builder#into-string) without copying it. Copying is prohibited. - **UTF-8** — validation, decoding and encoding by Table 3-7 of the Unicode standard, so overlong forms, surrogate halves and values past U+10FFFF are refused structurally. [`Encode`](https://rux-lang.dev/docs/api/text/utf8#encode) returns `uint ! Utf8Error`, [`DecodeAt`](https://rux-lang.dev/docs/api/text/utf8#decode-at) returns a [`DecodedScalar`](https://rux-lang.dev/docs/api/text/utf8#decoded-scalar) (the scalar and its width) `! Utf8Error`, and [`Validate`](https://rux-lang.dev/docs/api/text/utf8#validate) returns `! Utf8Failure`, which says where the bytes stopped being UTF-8 as well as why. - **[`CString`](https://rux-lang.dev/docs/api/text/c-string)** — move-only, NUL-checked interop with C: text holding a zero byte is refused rather than truncated on the way out, and bytes from C are bounded and validated on the way in. - **Transforms** — [`Concat`](https://rux-lang.dev/docs/api/text/transform#concat), [`Join`](https://rux-lang.dev/docs/api/text/transform#join), [`Repeat`](https://rux-lang.dev/docs/api/text/transform#repeat), [`Replace`](https://rux-lang.dev/docs/api/text/transform#replace), the ASCII-only case conversions, and [`ToUpper`](https://rux-lang.dev/docs/api/text/transform#to-upper), [`ToLower`](https://rux-lang.dev/docs/api/text/transform#to-lower) and [`FoldCase`](https://rux-lang.dev/docs/api/text/transform#fold-case) by Unicode's full, unconditional mappings from [`Rux/Unicode`](https://github.com/rux-lang/Rux/blob/main/Packages/Text/../Unicode){rel=""nofollow""}. - **The presentation contracts** — [`Display`](https://rux-lang.dev/docs/api/text/display) and [`Debug`](https://rux-lang.dev/docs/api/text/debug) are what a value implements to describe itself, [`TextWriter`](https://rux-lang.dev/docs/api/text/text-writer) is where the text goes, and [`FormatSpec`](https://rux-lang.dev/docs/api/text/format-spec) is what a placeholder asked for. They live here rather than in [`Rux/Format`](https://github.com/rux-lang/Rux/blob/main/Packages/Text/../Format){rel=""nofollow""} so that a package can describe its own values without depending on the numeric conversion engine: `Time`, `Uuid` and `Path` all implement them and none of them needs to know how a float is rounded. [`WriteAligned`](https://rux-lang.dev/docs/api/text/format-spec#write-aligned) applies a spec's width, fill and alignment, which is the one part every type applies the same way, to text already rendered; [`WriteDisplayAligned`](https://rux-lang.dev/docs/api/text/format-spec#write-display-aligned) applies them around a value that writes its text in pieces, as dates and identifiers do. - **Text presents itself** — [`String`](https://rux-lang.dev/docs/api/text/string) and [`StringView`](https://rux-lang.dev/docs/api/text/string-view) implement [`Display`](https://rux-lang.dev/docs/api/text/display) as their own characters and [`Debug`](https://rux-lang.dev/docs/api/text/debug) as those characters quoted and escaped. What is escaped is narrow on purpose: the quote and the backslash, which collide with the quoting, and the C0 and C1 controls, which act on a terminal instead of being read. All ordinary non-ASCII text is left alone, because escaping it would make most of the world's scripts unreadable in the one place a reader is trying to read them. - **[`BufferWriter`](https://rux-lang.dev/docs/api/text/buffer-writer)** — a fixed buffer that holds text at every moment. Every write is validated as UTF-8 before any of it lands, and a write that does not fit lands not at all, so what has been written is always the concatenation of the runs that succeeded. That second promise is what makes the buffer usable after a failure: a caller who runs out of room writes the same run somewhere larger without first working out how much of it went in. - **[`FormatSpec`](https://rux-lang.dev/docs/api/text/format-spec) and [`ParseFormatSpec`](https://rux-lang.dev/docs/api/text/format-spec#parse-format-spec)** — what a placeholder asked for, parsed once by the grammar `[[fill]align][+][#][0][width][.precision][style]`. A style is an identifier, so `x` and `iso8601` parse by the same rule; the parser recognizes syntax and the value decides whether the style means anything, refusing what it does not support with `UnsupportedRequest`. An integer understands the bases `b`, `o`, `x` and `X`, and renders a negative value in any of them as a minus sign and the magnitude rather than as two's-complement bits: `{:b}` of `-5` is `-101`. A float understands `e` and `E`, which ask for scientific notation. A malformed specification reports the byte offset where parsing stopped. - **Errors describe themselves** — [`TextError`](https://rux-lang.dev/docs/api/text/text-error), [`TextFailureKind`](https://rux-lang.dev/docs/api/text/format-error#text-failure-kind), [`FormatError`](https://rux-lang.dev/docs/api/text/format-error) and [`Utf8Error`](https://rux-lang.dev/docs/api/text/utf8-error) implement [`Display`](https://rux-lang.dev/docs/api/text/display) and [`Debug`](https://rux-lang.dev/docs/api/text/debug), and so do `AllocError` and `PageError`, which surface through [`TextError`](https://rux-lang.dev/docs/api/text/text-error) and whose owning packages do not depend on this one. [`Display`](https://rux-lang.dev/docs/api/text/display) is the stable description a reader is shown, short enough to sit inside a sentence a program is already writing; [`Debug`](https://rux-lang.dev/docs/api/text/debug) names the case and its payload, so `FormatError::InvalidSpecification(12)` says where. The descriptions are stable and are not a parsing contract: a program branches on the case, not the words. `EntropyError` is deliberately absent — presenting it would need a dependency edge the layering forbids in both directions — and callers handle its cases or wrap it in a diagnostic type of their own. - **Outcomes and runs show what is inside them** — [`WriteOptionalDebug`](https://rux-lang.dev/docs/api/text/debug#write-optional-debug), [`WriteFallibleDebug`](https://rux-lang.dev/docs/api/text/debug#write-fallible-debug) and [`WriteSliceDebug`](https://rux-lang.dev/docs/api/text/debug#write-slice-debug) write an optional `T?` as `Some(value)` or `none`, a fallible `T ! E` as `Success(value)` or `Failure(reason)`, and a run of elements as `[first, second, third]`. None of the three can be an interface implementation, because native forms implement no interface and what a `T?` looks like is entirely a question about `T`; they are handwritten functions carrying the bound, resolved at each instantiation with nothing dispatched at run time. They borrow, which is the point: `??` and `?` consume the optional because taking a payload out is a transfer of ownership, while showing one is not, so an optional holding a move-only value can be written as often as wanted and still holds it. The specification reaches the elements unchanged; the brackets, commas and case names are punctuation and are never padded. Sequential containers are [`Rux/Collections`](https://github.com/rux-lang/Rux/blob/main/Packages/Text/../Collections){rel=""nofollow""}' own writers, built on [`WriteSliceDebug`](https://rux-lang.dev/docs/api/text/debug#write-slice-debug). - **[`FormatError`](https://rux-lang.dev/docs/api/text/format-error)** — why a value could not be turned into text, with no case for success. [`TextError`](https://rux-lang.dev/docs/api/text/text-error) next door is the same shape for this package's storage and validation operations, which return `T ! TextError`; [`FromTextError`](https://rux-lang.dev/docs/api/text/format-error#from-text-error) is the one sanctioned crossing between the two, used as a mapper: `builder.Append(view)? else (e => FromTextError(e))`. ### Example ```rux import Allocator::{ Allocator, SystemAllocator }; import Io::PrintLine; import Text::{ String, TextError }; func Main() -> ! TextError { var system = SystemAllocator(); let allocator: Allocator = system; let greeting = String::FromBytes(allocator, "Hello")?; PrintLine(greeting); } ``` Use `String(allocator)`, `StringBuilder(allocator)`, and [`StringView()`](https://rux-lang.dev/docs/api/text/string-view) for empty values. Move builders and C strings explicitly with `<-`. Ordinary [`String`](https://rux-lang.dev/docs/api/text/string) copy syntax is infallible and terminates on allocation failure; use [`Clone()`](https://rux-lang.dev/docs/api/text/string#clone), which returns `String ! TextError`, in recoverable paths. ## Index ### Interfaces | Name | Summary | | ------------------------------------------------------------------ | --------------------------------------------------------- | | [`Display`](https://rux-lang.dev/docs/api/text/display) | The text a value has for a reader. | | [`Debug`](https://rux-lang.dev/docs/api/text/debug) | The text a value has for whoever is inspecting a program. | | [`ParseFailure`](https://rux-lang.dev/docs/api/text/parse-failure) | A parsing failure that can say where it happened. | | [`TextWriter`](https://rux-lang.dev/docs/api/text/text-writer) | Somewhere formatted text can be written. | ### Types | Name | Summary | | -------------------------------------------------------------------------------------- | -------------------------------------------------------------------------- | | [`BufferWriter`](https://rux-lang.dev/docs/api/text/buffer-writer) | A fixed buffer being filled with text from the front. | | [`CString`](https://rux-lang.dev/docs/api/text/c-string) | Text carrying the terminator C expects, in storage of its own. | | [`TextFailureKind`](https://rux-lang.dev/docs/api/text/format-error#text-failure-kind) | The ways text handling fails, with no case for success. | | [`FormatError`](https://rux-lang.dev/docs/api/text/format-error) | Why a formatting operation did not produce the text it was asked for. | | [`SplitIterator`](https://rux-lang.dev/docs/api/text/string-view#split-iterator) | A walk over the parts of a view between occurrences of a separator. | | [`LineIterator`](https://rux-lang.dev/docs/api/text/string-view#line-iterator) | A walk over the lines of a view, each without its line break. | | [`FormatAlign`](https://rux-lang.dev/docs/api/text/format-spec#format-align) | Where the padding goes when the rendering is narrower than the width. | | [`FormatBase`](https://rux-lang.dev/docs/api/text/format-spec#format-base) | The base an integer renders in. | | [`FormatSpec`](https://rux-lang.dev/docs/api/text/format-spec) | Everything a placeholder asked for. | | [`String`](https://rux-lang.dev/docs/api/text/string) | Text that owns its bytes. | | [`StringBuilder`](https://rux-lang.dev/docs/api/text/string-builder) | A growable buffer of text. | | [`StringView`](https://rux-lang.dev/docs/api/text/string-view) | A borrowed run of bytes that has been checked to be UTF-8. | | [`ScalarIterator`](https://rux-lang.dev/docs/api/text/string-view#scalar-iterator) | A walk over the scalar values of a view, first to last. | | [`TextError`](https://rux-lang.dev/docs/api/text/text-error) | What went wrong. | | [`Utf8Error`](https://rux-lang.dev/docs/api/text/utf8-error) | What was wrong with a byte sequence. | | [`DecodedScalar`](https://rux-lang.dev/docs/api/text/utf8#decoded-scalar) | One scalar value decoded from UTF-8, with the number of bytes it occupied. | | [`Utf8Failure`](https://rux-lang.dev/docs/api/text/utf8#utf8-failure) | Where and why a byte sequence stopped being well-formed UTF-8. | ### Functions | Name | Summary | | --------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | [`PaddingAround`](https://rux-lang.dev/docs/api/text/format-spec#padding-around) | How many fill characters go on each side of a rendering that occupies `occupied` scalars. | | [`WriteFill`](https://rux-lang.dev/docs/api/text/format-spec#write-fill) | Writes `count` copies of the spec's fill byte. | | [`WriteAligned`](https://rux-lang.dev/docs/api/text/format-spec#write-aligned) | Writes `rendered` into `writer` under `spec`'s width, fill and alignment. | | [`WriteDisplayAligned`](https://rux-lang.dev/docs/api/text/format-spec#write-display-aligned) | Writes `value`'s text under `spec`, applying the spec's width, fill and alignment around the text the value writes itself. | | [`WriteValue`](https://rux-lang.dev/docs/api/text/display#write-value) | Writes `value` under `spec` through its [`Display`](https://rux-lang.dev/docs/api/text/display) implementation. | | [`WriteDebugValue`](https://rux-lang.dev/docs/api/text/debug#write-debug-value) | Writes `value` under `spec` through its [`Debug`](https://rux-lang.dev/docs/api/text/debug) implementation. | | [`TextFailureOf`](https://rux-lang.dev/docs/api/text/format-error#text-failure-of) | The failure-only kind corresponding to `error`. | | [`FromTextError`](https://rux-lang.dev/docs/api/text/format-error#from-text-error) | `error` translated across the boundary between this package's status convention and the formatting protocol. | | [`WriteEscaped`](https://rux-lang.dev/docs/api/text/debug#write-escaped) | Writes `text` with the characters that would be ambiguous or invisible replaced by escapes. | | [`IsAsciiSpace`](https://rux-lang.dev/docs/api/text/string-view#is-ascii-space) | Whether `byte` is ASCII whitespace: space, tab, newline, carriage return, form feed or vertical tab. | | [`ParseFormatSpec`](https://rux-lang.dev/docs/api/text/format-spec#parse-format-spec) | Parses the text between `{:` and `}`. | | [`RejectStyle`](https://rux-lang.dev/docs/api/text/format-spec#reject-style) | Refuses a specification that names any style. | | [`RejectNonBaseStyle`](https://rux-lang.dev/docs/api/text/format-spec#reject-non-base-style) | Refuses a specification whose style is not one of the integer bases. | | [`WriteOptionalDebug<T>`](https://rux-lang.dev/docs/api/text/debug#write-optional-debug) | Writes a borrowed optional as `Some(value)` or `none`. | | [`WriteFallibleDebug<T, E>`](https://rux-lang.dev/docs/api/text/debug#write-fallible-debug) | Writes a borrowed fallible as `Success(value)` or `Failure(reason)`. | | [`WriteSliceDebug<T>`](https://rux-lang.dev/docs/api/text/debug#write-slice-debug) | Writes a borrowed run of elements as `[first, second, third]`. | | [`FromAllocError`](https://rux-lang.dev/docs/api/text/text-error#from-alloc-error) | The text error an allocator's failure becomes. | | [`Join`](https://rux-lang.dev/docs/api/text/transform#join) | The text of every part of `parts` in order, with `separator` between each two. | | [`ToUpper`](https://rux-lang.dev/docs/api/text/transform#to-upper) | The text of `view` in upper case by Unicode's full, unconditional mappings, so `ß` becomes `SS` and `ʼn` becomes `ʼN`. | | [`ToLower`](https://rux-lang.dev/docs/api/text/transform#to-lower) | The text of `view` in lower case by Unicode's full, unconditional mappings. | | [`FoldCase`](https://rux-lang.dev/docs/api/text/transform#fold-case) | The text of `view` case-folded by Unicode's full folding, the form for comparing text without regard to case: two texts that differ only in case fold to the same bytes, `Straße` and `STRASSE` included. | | [`Concat`](https://rux-lang.dev/docs/api/text/transform#concat) | The text of `left` followed by the text of `right`. | | [`Repeat`](https://rux-lang.dev/docs/api/text/transform#repeat) | The text of `view` written `count` times. | | [`Replace`](https://rux-lang.dev/docs/api/text/transform#replace) | The text of `view` with every occurrence of `needle` replaced by `replacement`. | | [`IsAsciiLetter`](https://rux-lang.dev/docs/api/text/transform#is-ascii-letter) | Whether `byte` is an ASCII letter. | | [`ToAsciiUpper`](https://rux-lang.dev/docs/api/text/transform#to-ascii-upper) | The text of `view` with every ASCII lower-case letter raised, and everything else left alone. | | [`ToAsciiLower`](https://rux-lang.dev/docs/api/text/transform#to-ascii-lower) | The text of `view` with every ASCII upper-case letter lowered. | | [`IsScalarValue`](https://rux-lang.dev/docs/api/text/utf8#is-scalar-value) | Whether `value` is a Unicode scalar value: at most [`MaxScalarValue`](https://rux-lang.dev/docs/api/text/utf8#max-scalar-value), and not a surrogate half. | | [`EncodedLength`](https://rux-lang.dev/docs/api/text/utf8#encoded-length) | How many bytes `scalar` takes in UTF-8, or zero when it is not a scalar value. | | [`IsContinuation`](https://rux-lang.dev/docs/api/text/utf8#is-continuation) | Whether `byte` is a continuation byte, the `10xxxxxx` shape every byte after a leading one has. | | [`Encode`](https://rux-lang.dev/docs/api/text/utf8#encode) | Writes `scalar` into `into` as UTF-8 and reports how many bytes it took. | | [`DecodeAt`](https://rux-lang.dev/docs/api/text/utf8#decode-at) | Decodes the scalar value starting at `index`, reporting it and how many bytes it occupied. | | [`Validate`](https://rux-lang.dev/docs/api/text/utf8#validate) | Whether `bytes` is well-formed UTF-8 from end to end, reporting where it first is not. | | [`IsBoundary`](https://rux-lang.dev/docs/api/text/utf8#is-boundary) | Whether `index` is where a scalar value starts, and so a place a string may be cut. | | [`CountScalars`](https://rux-lang.dev/docs/api/text/utf8#count-scalars) | How many scalar values `bytes` holds, assuming it is well-formed. | | [`BoundaryAtOrBelow`](https://rux-lang.dev/docs/api/text/utf8#boundary-at-or-below) | The index of the scalar boundary at or below `index`. | | [`WriteBytes`](https://rux-lang.dev/docs/api/text/text-writer#write-bytes) | Writes `bytes` to `writer`. | | [`WriteAscii`](https://rux-lang.dev/docs/api/text/text-writer#write-ascii) | Writes one ASCII byte. | | [`WriteScalar`](https://rux-lang.dev/docs/api/text/text-writer#write-scalar) | Writes one character, encoded as UTF-8. | ### Constants | Name | Summary | | ------------------------------------------------------------------------------------------------------ | --------------------------------------------------------------------- | | [`MinimumBuilderCapacity`](https://rux-lang.dev/docs/api/text/string-builder#minimum-builder-capacity) | The room a builder takes when it first needs any. | | [`MaxScalarValue`](https://rux-lang.dev/docs/api/text/utf8#max-scalar-value) | The largest Unicode scalar value. | | [`FirstSurrogate`](https://rux-lang.dev/docs/api/text/utf8#first-surrogate) | The first value of the surrogate range, which holds no scalar values. | | [`LastSurrogate`](https://rux-lang.dev/docs/api/text/utf8#last-surrogate) | The last value of the surrogate range. | | [`MaxEncodedLength`](https://rux-lang.dev/docs/api/text/utf8#max-encoded-length) | The most bytes any one scalar value takes in UTF-8. | # Debug The text a value has for whoever is inspecting a program. ```rux pub interface Debug { func WriteDebug( writer: &var TextWriter, spec: FormatSpec ) -> ! FormatError; } ``` Debug output is diagnostic, not a serialization format: it may quote, escape, name fields, and show an invalid value by its numeric form where [`Display`](https://rux-lang.dev/docs/api/text/display) would replace it. Nothing promises it can be parsed back. ## Requirements ### `WriteDebug` ```rux func WriteDebug( writer: &var TextWriter, spec: FormatSpec ) -> ! FormatError ``` Writes this value's inspection text under `spec`. The same failures `WriteDisplay` may report, for the same reasons. | Name | Type | Description | | -------- | ----------------- | ------------------------------ | | `writer` | `&var TextWriter` | the destination | | `spec` | `FormatSpec` | what the placeholder asked for | **Returns**: success when the value's complete text was accepted [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/Display.rux#L46){rel=""nofollow""} ## Implementations | Type | Summary | | -------------------------------------------------------------------------------------- | --------------------------------------------------------------------- | | [`TextFailureKind`](https://rux-lang.dev/docs/api/text/format-error#text-failure-kind) | The ways text handling fails, with no case for success. | | [`FormatError`](https://rux-lang.dev/docs/api/text/format-error) | Why a formatting operation did not produce the text it was asked for. | | [`String`](https://rux-lang.dev/docs/api/text/string) | Text that owns its bytes. | | [`StringView`](https://rux-lang.dev/docs/api/text/string-view) | A borrowed run of bytes that has been checked to be UTF-8. | | [`TextError`](https://rux-lang.dev/docs/api/text/text-error) | What went wrong. | | [`Utf8Error`](https://rux-lang.dev/docs/api/text/utf8-error) | What was wrong with a byte sequence. | ## Related ### `WriteDebugValue` ```rux pub func WriteDebugValue( writer: &var TextWriter, value: Debug, spec: FormatSpec ) -> ! FormatError ``` Writes `value` under `spec` through its [`Debug`](https://rux-lang.dev/docs/api/text/debug) implementation. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/Display.rux#L67){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | ----------------- | ------------------------------------------ | | `writer` | `&var TextWriter` | the destination | | `value` | `Debug` | the value to render, borrowed for the call | | `spec` | `FormatSpec` | what to render it under | **Returns**: whatever the value's implementation reported ### `WriteEscaped` ```rux pub func WriteEscaped( writer: &var TextWriter, text: char8[..] ) -> ! FormatError ``` Writes `text` with the characters that would be ambiguous or invisible replaced by escapes. The quote and the backslash are escaped because they collide with the quoting around a debug rendering. The C0 and C1 control ranges are escaped because they act on a terminal rather than being read, and a value containing one should say so rather than doing it. `\n`, `\r`, `\t` and `\0` get their short forms; every other control becomes `\u{XX}`. Everything else, including all ordinary non-ASCII text, is written unchanged. Runs of ordinary bytes are written in one call rather than byte by byte, so escaping costs a pass and not a write per character. Reports whatever the writer reported, stopping at the first refusal. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/Presentation.rux#L87){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | ----------------- | ---------------------------------- | | `writer` | `&var TextWriter` | the destination | | `text` | `char8[..]` | the UTF-8 text to escape and write | **Returns**: success when the escaped text was accepted ### `WriteOptionalDebug<T>` ```rux pub func WriteOptionalDebug<T: Debug>( writer: &var TextWriter, value: &T?, spec: FormatSpec ) -> ! FormatError ``` Writes a borrowed optional as `Some(value)` or `none`. The optional is borrowed and its payload with it, so this can be called on an optional holding a value that cannot be copied, as many times as wanted, and the optional still holds it afterwards. `spec` is handed to the payload's own `WriteDebug` and describes it rather than the wrapper. Reports whatever the writer or the payload's implementation reported, stopping at the first refusal, so a destination that has already refused something is not written to again. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/Structure.rux#L34){rel=""nofollow""} **Type parameters** | Name | Description | | ---------- | ---------------------------------------------------- | | `T: Debug` | the payload type, which must know how to show itself | **Parameters** | Name | Type | Description | | -------- | ----------------- | ------------------------------------------- | | `writer` | `&var TextWriter` | the destination | | `value` | `&T?` | the optional to show, borrowed for the call | | `spec` | `FormatSpec` | what to show the payload under | **Returns**: success when the whole rendering was accepted ### `WriteFallibleDebug<T, E>` ```rux pub func WriteFallibleDebug<T: Debug, E: Debug>( writer: &var TextWriter, value: &(T ! E), spec: FormatSpec ) -> ! FormatError ``` Writes a borrowed fallible as `Success(value)` or `Failure(reason)`. Both payloads are borrowed, so neither channel is consumed by being shown. The names are the native channel names, so what is written names the case a reader would branch on. `spec` is handed to whichever payload is present and describes it rather than the wrapper. Reports whatever the writer or the payload's implementation reported, stopping at the first refusal. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/Structure.rux#L60){rel=""nofollow""} **Type parameters** | Name | Description | | ---------- | ------------------------------------------------------------ | | `T: Debug` | the success payload type, which must know how to show itself | | `E: Debug` | the failure payload type, which must know how to show itself | **Parameters** | Name | Type | Description | | -------- | ----------------- | ------------------------------------------- | | `writer` | `&var TextWriter` | the destination | | `value` | `&(T ! E)` | the fallible to show, borrowed for the call | | `spec` | `FormatSpec` | what to show the payload under | **Returns**: success when the whole rendering was accepted ### `WriteSliceDebug<T>` ```rux pub func WriteSliceDebug<T: Debug>( writer: &var TextWriter, items: T[..], spec: FormatSpec ) -> ! FormatError ``` Writes a borrowed run of elements as `[first, second, third]`. An empty run is `[]`, which is visible where writing nothing would not be. Elements are separated by a comma and a space, and every element is shown, since a diagnostic that elided part of what it was given would be worse than a long one. The run is borrowed and each element is shown through a borrow of it, so a slice of a move-only element type is shown without disturbing a single one of them. `spec` is handed to each element unchanged and means whatever that element type makes of it. The brackets and commas are punctuation and are never padded. Reports whatever the writer or an element's implementation reported, stopping at the first refusal rather than continuing through the rest of the run. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/Structure.rux#L92){rel=""nofollow""} **Type parameters** | Name | Description | | ---------- | ---------------------------------------------------- | | `T: Debug` | the element type, which must know how to show itself | **Parameters** | Name | Type | Description | | -------- | ----------------- | -------------------------------------------------- | | `writer` | `&var TextWriter` | the destination | | `items` | `T[..]` | the run of elements to show, borrowed for the call | | `spec` | `FormatSpec` | what to show each element under | **Returns**: success when the whole rendering was accepted # Display The text a value has for a reader. ```rux pub interface Display { func WriteDisplay( writer: &var TextWriter, spec: FormatSpec ) -> ! FormatError; } ``` An implementation writes into the destination it is handed and allocates no working storage of its own. A value whose rendering genuinely requires scratch space takes an allocator through a separate, explicit conversion instead of implementing this. ## Requirements ### `WriteDisplay` ```rux func WriteDisplay( writer: &var TextWriter, spec: FormatSpec ) -> ! FormatError ``` Writes this value's text under `spec`. Returns whatever the writer reported, or `UnsupportedRequest` when `spec` asks for something this value does not support, or `ValueOutOfRange` when the value cannot be represented in the form requested. An implementation stops at the first failed write rather than continuing to a destination that has already refused something. | Name | Type | Description | | -------- | ----------------- | ------------------------------ | | `writer` | `&var TextWriter` | the destination | | `spec` | `FormatSpec` | what the placeholder asked for | **Returns**: success when the value's complete text was accepted [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/Display.rux#L32){rel=""nofollow""} ## Implementations | Type | Summary | | -------------------------------------------------------------------------------------- | --------------------------------------------------------------------- | | [`TextFailureKind`](https://rux-lang.dev/docs/api/text/format-error#text-failure-kind) | The ways text handling fails, with no case for success. | | [`FormatError`](https://rux-lang.dev/docs/api/text/format-error) | Why a formatting operation did not produce the text it was asked for. | | [`String`](https://rux-lang.dev/docs/api/text/string) | Text that owns its bytes. | | [`StringView`](https://rux-lang.dev/docs/api/text/string-view) | A borrowed run of bytes that has been checked to be UTF-8. | | [`TextError`](https://rux-lang.dev/docs/api/text/text-error) | What went wrong. | | [`Utf8Error`](https://rux-lang.dev/docs/api/text/utf8-error) | What was wrong with a byte sequence. | ## Related ### `WriteValue` ```rux pub func WriteValue( writer: &var TextWriter, value: Display, spec: FormatSpec ) -> ! FormatError ``` Writes `value` under `spec` through its [`Display`](https://rux-lang.dev/docs/api/text/display) implementation. A named entry point for rendering one value, so a caller with a value and a writer needs no placeholder pattern to put them together. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/Display.rux#L57){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | ----------------- | ------------------------------------------ | | `writer` | `&var TextWriter` | the destination | | `value` | `Display` | the value to render, borrowed for the call | | `spec` | `FormatSpec` | what to render it under | **Returns**: whatever the value's implementation reported # ParseFailure A parsing failure that can say where it happened. ```rux pub interface ParseFailure { func Offset() -> uint; } ``` Every domain owns its own parse error, because what went wrong in a UUID and what went wrong in a timestamp are different questions with different answers, and flattening them into one type would lose the distinctions a caller acts on. What they share is the position, and that is what this names. The offset is a zero-based UTF-8 byte offset into the text that was handed to the parser. End of input is the text's length, which is a position and not a failure to have one. A parser embedded in a larger grammar adds the offset of the token it was given, so positions compose. ## Requirements ### `Offset` ```rux func Offset() -> uint ``` Where in the input the failure was found. **Returns**: the zero-based UTF-8 byte offset, which is the text's length at end of input [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/FormatError.rux#L107){rel=""nofollow""} # TextWriter Somewhere formatted text can be written. ```rux pub interface TextWriter { func Write( self: &var Self, bytes: char8[..] ) -> ! FormatError; } ``` Writing advances the writer, so [`Write`](https://rux-lang.dev/docs/api/text/text-writer#write) borrows its receiver mutably and is called through a `&var TextWriter` view, which refers to the caller's own writer rather than a copy that would lose its position. ## Requirements ### `Write` ```rux func Write( self: &var Self, bytes: char8[..] ) -> ! FormatError ``` Writes `bytes`, which must be well-formed UTF-8 and must not end part-way through a character. A successful write accepted the complete run: there is no partial success to report, and a caller may write the next run without asking how much of this one landed. May return only `InsufficientCapacity`, `TextFailure` or `WriterFailure`. An implementation must not originate `InvalidSpecification`, `UnsupportedRequest`, `ArgumentCountMismatch` or `ValueOutOfRange`, none of which a destination is in a position to observe. Whether anything was written before a failure is the implementation's own documented guarantee: a bounded buffer leaves itself unchanged, while a stream may already have emitted a prefix. | Name | Type | Description | | ------- | ----------- | ----------------------------- | | `bytes` | `char8[..]` | the UTF-8 run to write, whole | **Returns**: success when the complete run was accepted [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/Writer.rux#L32){rel=""nofollow""} ## Implementations | Type | Summary | | -------------------------------------------------------------------- | ----------------------------------------------------- | | [`BufferWriter`](https://rux-lang.dev/docs/api/text/buffer-writer) | A fixed buffer being filled with text from the front. | | [`StringBuilder`](https://rux-lang.dev/docs/api/text/string-builder) | A growable buffer of text. | ## Related ### `WriteBytes` ```rux pub func WriteBytes( writer: &var TextWriter, bytes: char8[..] ) -> ! FormatError ``` Writes `bytes` to `writer`. The writer is borrowed exclusively for the call, so position changes remain visible to its owner. This forwards without inspecting the bytes, which is what keeps the writer's permitted failures exactly the writer's. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/Writer.rux#L42){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | ----------------- | ----------------------------- | | `writer` | `&var TextWriter` | the destination | | `bytes` | `char8[..]` | the UTF-8 run to write, whole | **Returns**: whatever the writer reported ### `WriteAscii` ```rux pub func WriteAscii( writer: &var TextWriter, byte: char8 ) -> ! FormatError ``` Writes one ASCII byte. Reports `TextFailure(InvalidUtf8)` for a byte above 0x7F: a single byte above that is never a whole character, and a writer takes whole characters. [`WriteScalar`](https://rux-lang.dev/docs/api/text/text-writer#write-scalar) is what writes one that needs more than a byte. Otherwise reports whatever the writer reported. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/Writer.rux#L54){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | ----------------- | ----------------------- | | `writer` | `&var TextWriter` | the destination | | `byte` | `char8` | the ASCII byte to write | **Returns**: success when the byte was accepted ### `WriteScalar` ```rux pub func WriteScalar( writer: &var TextWriter, scalar: char32 ) -> ! FormatError ``` Writes one character, encoded as UTF-8. Reports `TextFailure(InvalidUtf8)` for a value that is not a Unicode scalar value. This is strict encoding, not presentation: a caller that wants an invalid value shown as U+FFFD replaces it before calling. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/Writer.rux#L70){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | ----------------- | -------------------------------------------- | | `writer` | `&var TextWriter` | the destination | | `scalar` | `char32` | the Unicode scalar value to encode and write | **Returns**: success when the encoded character was accepted # BufferWriter A fixed buffer being filled with text from the front. ```rux pub struct BufferWriter { // private fields } ``` Holds well-formed UTF-8 at every moment. A write either appends its whole run or changes nothing, so what has been written is always the concatenation of the runs that succeeded. Copying is not prohibited, but a copy is a second cursor over the same storage rather than a second buffer, so writes through one are invisible to the other and the two will overwrite each other. Borrow it as `&var TextWriter` and let it be the one writer over its room. The room it was built over must outlive it. It stores the slice, and nothing here tracks that. ## Constructors ### `BufferWriter` ```rux pub func BufferWriter(room: var char8[..]) -> BufferWriter ``` A writer over `room`, filling from its start. Nothing in `room` is read or cleared: what has not been written is not part of the text, and [`Written`](https://rux-lang.dev/docs/api/text/buffer-writer#written) never reaches it. Cannot fail. Runs in constant time and allocates nothing. | Name | Type | Description | | ------ | --------------- | -------------------------------------------------- | | `room` | `var char8[..]` | the storage to fill, which must outlive the writer | **Returns**: a writer holding no text yet [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/BufferWriter.rux#L37){rel=""nofollow""} ## Methods ### `Written` ```rux pub func Written(self: &BufferWriter) -> char8[..] ``` The text written so far. Well-formed UTF-8, and exactly the runs that succeeded: a refused write left nothing behind to appear here. The result borrows the writer's room and must not outlive it. Borrows the writer. Cannot fail; runs in constant time and allocates nothing. **Returns**: the bytes written, which are valid UTF-8 [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/BufferWriter.rux#L47){rel=""nofollow""} ### `Length` ```rux pub func Length(self: &BufferWriter) -> uint ``` How many bytes of text the writer holds. Borrows the writer. Cannot fail; runs in constant time and allocates nothing. **Returns**: the byte count, which is not a character count [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/BufferWriter.rux#L55){rel=""nofollow""} ### `Remaining` ```rux pub func Remaining(self: &BufferWriter) -> uint ``` How many more bytes will fit. A caller sizing a write can ask, but need not: a write that does not fit is refused whole rather than truncated, so asking first is an optimization and never a correctness requirement. Borrows the writer. Cannot fail; runs in constant time and allocates nothing. **Returns**: the remaining capacity in bytes [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/BufferWriter.rux#L65){rel=""nofollow""} ### `Clear` ```rux pub func Clear(self: &var BufferWriter) ``` Discards the text written so far, keeping the room. The bytes are not overwritten, because they are no longer text as far as this writer is concerned and nothing can reach them: [`Written`](https://rux-lang.dev/docs/api/text/buffer-writer#written) stops at the length. A caller clearing secrets wants `ZeroizeBlock` from `Rux/Memory` on the room itself. Borrows the writer exclusively. Cannot fail; runs in constant time and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/BufferWriter.rux#L75){rel=""nofollow""} ## Implements TextWriter `BufferWriter` conforms to [`TextWriter`](https://rux-lang.dev/docs/api/text/text-writer). ### `Write` ```rux pub func Write( self: &var BufferWriter, bytes: char8[..] ) -> ! FormatError ``` Appends `bytes`, whole or not at all. Reports `InsufficientCapacity` when the run does not fit, and `TextFailure(InvalidUtf8)` when it is not well-formed UTF-8. In both cases the buffer is exactly as it was, so a caller may write the same run to a larger destination without first undoing a partial one. Capacity is decided before validity, since a run that cannot land is not worth reading. These are the only two failures this writer produces. There is no destination beyond the buffer, so a `WriterFailure` cannot arise, and the other `TextFailure` reasons belong to allocation and to boundary arithmetic, neither of which a fixed buffer performs. | Name | Type | Description | | ------- | ----------- | ------------------------------ | | `bytes` | `char8[..]` | the UTF-8 run to append, whole | **Returns**: success when the complete run was appended [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/BufferWriter.rux#L92){rel=""nofollow""} # CString Text carrying the terminator C expects, in storage of its own. ```rux pub struct CString { pub data: *var char8; pub length: uint; pub allocator: Allocator; } ``` Move-only: it explicitly prohibits copying, owns its block, and gives it back when it dies. The terminator is part of the block and not part of the text, so [`Length`](https://rux-lang.dev/docs/api/text/c-string#length) answers without it. ## Fields | Name | Type | Description | | ----------- | ------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `data` | `*var char8` | The bytes, ending with the one zero byte the text does not contain. Null only for a `CString` that was consumed by a move; every constructor allocates, since even empty C text is one byte long. | | `length` | `uint` | How many bytes of text come before the terminator. | | `allocator` | `Allocator` | Where the block came from, and where it goes back to. | ## Associated functions ### `FromText` ```rux pub func FromText( allocator: Allocator, text: char8[..] ) -> CString ! TextError ``` A terminated copy of `text`, or why the text cannot cross the boundary. Refuses a zero byte for the reason [`FromView`](https://rux-lang.dev/docs/api/text/c-string#from-view) does: text that ends early on the C side of the boundary is how a checked name and a used name part company. | Name | Type | Description | | ----------- | ----------- | ---------------------------- | | `allocator` | `Allocator` | where the storage comes from | | `text` | `char8[..]` | the text to act on | **Returns**: the terminated copy, or a failure when the text holds an interior zero byte [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/CString.rux#L41){rel=""nofollow""} ### `FromView` ```rux pub func FromView( allocator: Allocator, view: StringView ) -> CString ! TextError ``` A terminated copy of `view`, or why the text cannot cross the boundary. Fails with `InvalidUtf8` when the text contains a zero byte — refused rather than truncated, because text that ends early on the C side of the boundary is the classic way a checked name and a used name part company. Reports `OutOfMemory` when the copy cannot be made. Runs in time proportional to the length — one pass to check, one to copy — and allocates once. | Name | Type | Description | | ----------- | ------------ | ---------------------------- | | `allocator` | `Allocator` | where the storage comes from | | `view` | `StringView` | the borrowed text to act on | **Returns**: the terminated copy, or a failure when the text holds an interior zero byte [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/CString.rux#L54){rel=""nofollow""} ### `FromRaw` ```rux pub func FromRaw( allocator: Allocator, raw: *char8, limit: uint ) -> CString ! TextError ``` A copy of the C text at `raw`, read to its terminator, or why it is not text. `raw` is borrowed for the call and its bytes are copied, so the C side keeps whatever it handed over. `limit` bounds the search for the terminator: C promises one exists, and this is what the promise costs when it is broken — reports `InvalidUtf8` after `limit` bytes rather than reading memory forever. Bytes that are not UTF-8 are refused the same way, since nothing about C promises text. | Name | Type | Description | | ----------- | ----------- | --------------------------------------------------------------- | | `allocator` | `Allocator` | where the storage comes from | | `raw` | `*char8` | the null-terminated bytes to copy | | `limit` | `uint` | the most bytes to read before giving up on finding a terminator | **Returns**: the copy, or a failure when no terminator was found within `limit` [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/CString.rux#L89){rel=""nofollow""} ## Methods ### `Length` ```rux pub func Length(self: &CString) -> uint ``` How many bytes of text come before the terminator. **Returns**: how many bytes precede the terminator [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/CString.rux#L122){rel=""nofollow""} ### `Raw` ```rux pub func Raw(self: &CString) -> *char8 ``` The pointer C expects: the text, then one zero byte. Borrowed. Valid until this [`CString`](https://rux-lang.dev/docs/api/text/c-string) is released or dies, and no longer — C code that keeps it past that is keeping a pointer into a freed block. **Returns**: the address to hand to a C interface, which stays valid while this does [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/CString.rux#L131){rel=""nofollow""} ### `View` ```rux pub func View(self: &CString) -> StringView ``` The text without its terminator, as a view. The view borrows this [`CString`](https://rux-lang.dev/docs/api/text/c-string) and must not outlive it. **Returns**: the bytes as text, without the terminator [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/CString.rux#L139){rel=""nofollow""} ### `Clear` ```rux pub func Clear(self: &var CString) ``` Gives the block back and leaves a [`CString`](https://rux-lang.dev/docs/api/text/c-string) that owns nothing. Safe to call twice, since what it leaves behind owns nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/CString.rux#L146){rel=""nofollow""} ## Destructor ```rux func ~CString(self: &var CString) ``` Gives the block back. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/CString.rux#L159){rel=""nofollow""} # FormatError Why a formatting operation did not produce the text it was asked for. ```rux pub variant FormatError { InvalidSpecification(uint), UnsupportedRequest, ArgumentCountMismatch(uint, uint), InsufficientCapacity, ValueOutOfRange, TextFailure(TextFailureKind), WriterFailure } ``` Failure-only: every case is a failure, and success is the other channel of the `! FormatError` or `T ! FormatError` that reports it rather than a case here. Which case arises says who must fix it, so the categories are not interchangeable and a writer may not invent the ones that belong to the parser or the value. Copy, and cheap to return: the widest payload is a pair of counts. ## Cases | Name | Description | | ----------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `InvalidSpecification(uint)` | The pattern or specification was malformed, at the zero-based UTF-8 byte offset carried here. The offset is into the text that was being parsed, and end-of-input is that text's length. | | `UnsupportedRequest` | The style or flag asked for is not one this value supports. A precision on a boolean, or a base on a string, arrives here rather than being ignored. | | `ArgumentCountMismatch(uint, uint)` | A pattern's placeholders and the arguments supplied did not agree: expected first, supplied second. | | `InsufficientCapacity` | The destination is bounded and cannot accept the whole write. Nothing partial is left behind by a writer that promises otherwise; see the writer's own contract. | | `ValueOutOfRange` | The value is valid but cannot be represented in the form requested, such as a timestamp outside the calendar range a format covers. | | `TextFailure(TextFailureKind)` | Text handling failed, for the reason carried. This is where an allocation failure or rejected UTF-8 arrives. | | `WriterFailure` | The destination failed on its own terms. Its details stay with the adapter that produced it, which is the only thing that knows what a failure of that destination means. | ## Methods ### `IsWriterFailure` ```rux pub func IsWriterFailure(self: &FormatError) -> bool ``` Whether this failure came from the destination rather than from the text or the request. Useful at a boundary that must tell an unusable destination apart from a request that was wrong: the first is worth retrying elsewhere and the second never is. Borrows the error and leaves it untouched. Cannot fail; runs in constant time and allocates nothing. **Returns**: true for `WriterFailure`, false for every other case [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/FormatError.rux#L65){rel=""nofollow""} ## Implements Display `FormatError` conforms to [`Display`](https://rux-lang.dev/docs/api/text/display). ### `WriteDisplay` ```rux pub func WriteDisplay( self: &FormatError, writer: &var TextWriter, spec: FormatSpec ) -> ! FormatError ``` Writes the description of why a value could not be turned into text. The position an `InvalidSpecification` carries, and the two counts an `ArgumentCountMismatch` carries, are deliberately absent: they are what [`Debug`](https://rux-lang.dev/docs/api/text/debug) adds. A description says what happened, and a reader who needs the byte offset is reading a log rather than a message. Reports whatever the writer reported, and `UnsupportedRequest` for any style or precision. | Name | Type | Description | | -------- | ----------------- | ------------------------------ | | `writer` | `&var TextWriter` | the destination | | `spec` | `FormatSpec` | what the placeholder asked for | **Returns**: success when the whole description was accepted [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/FormatError.rux#L147){rel=""nofollow""} ## Implements Debug `FormatError` conforms to [`Debug`](https://rux-lang.dev/docs/api/text/debug). ### `WriteDebug` ```rux pub func WriteDebug( self: &FormatError, writer: &var TextWriter, spec: FormatSpec ) -> ! FormatError ``` Names the case and the payload it carries: `FormatError::InvalidSpecification(12)`. This is where the position and the counts appear, since they are what makes one occurrence of a failure different from another and what a log is read for. Reports whatever the writer reported, and `UnsupportedRequest` for any style or precision. | Name | Type | Description | | -------- | ----------------- | ------------------------------ | | `writer` | `&var TextWriter` | the destination | | `spec` | `FormatSpec` | what the placeholder asked for | **Returns**: success when the whole rendering was accepted [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/FormatError.rux#L170){rel=""nofollow""} ## Related ### `TextFailureKind` ```rux pub variant TextFailureKind { OutOfMemory, LengthOverflow, InvalidUtf8, NotABoundary } ``` The ways text handling fails, with no case for success. A deliberate narrowing of [`TextError`](https://rux-lang.dev/docs/api/text/text-error): the same four failures, minus its `None`. That absence is the point, since this is what a `FormatError::TextFailure` carries and a failure payload must not be able to say "nothing went wrong". Copy, carrying no payload and owning nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/FormatError.rux#L19){rel=""nofollow""} **Cases** | Name | Description | | ---------------- | --------------------------------------------------------------------------------------- | | `OutOfMemory` | The allocator could not supply the storage a write needed. | | `LengthOverflow` | A length or offset computation passed what a `uint` can hold. | | `InvalidUtf8` | The bytes offered were not well-formed UTF-8. | | `NotABoundary` | A byte offset that is not where a character starts, and so not a place text may be cut. | **Implements Display** `TextFailureKind` conforms to [`Display`](https://rux-lang.dev/docs/api/text/display). #### `WriteDisplay` ```rux pub func WriteDisplay( self: &TextFailureKind, writer: &var TextWriter, spec: FormatSpec ) -> ! FormatError ``` The same description [`TextError`](https://rux-lang.dev/docs/api/text/text-error) gives the same failure, which is the point of sharing one writer. Reports whatever the writer reported, and `UnsupportedRequest` for any style or precision. | Name | Type | Description | | -------- | ----------------- | ------------------------------ | | `writer` | `&var TextWriter` | the destination | | `spec` | `FormatSpec` | what the placeholder asked for | **Returns**: success when the whole description was accepted [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/FormatError.rux#L116){rel=""nofollow""} **Implements Debug** `TextFailureKind` conforms to [`Debug`](https://rux-lang.dev/docs/api/text/debug). #### `WriteDebug` ```rux pub func WriteDebug( self: &TextFailureKind, writer: &var TextWriter, spec: FormatSpec ) -> ! FormatError ``` Names the case, qualified by its type: `TextFailureKind::InvalidUtf8`. Reports whatever the writer reported, and `UnsupportedRequest` for any style or precision. | Name | Type | Description | | -------- | ----------------- | ------------------------------ | | `writer` | `&var TextWriter` | the destination | | `spec` | `FormatSpec` | what the placeholder asked for | **Returns**: success when the whole name was accepted [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/FormatError.rux#L130){rel=""nofollow""} ### `TextFailureOf` ```rux pub func TextFailureOf(error: TextError) -> TextFailureKind ``` The failure-only kind corresponding to `error`. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/FormatError.rux#L77){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------- | ----------- | -------------------------------------------------- | | `error` | `TextError` | the text status to narrow, which must be a failure | **Returns**: the matching failure kind ### `FromTextError` ```rux pub func FromTextError(error: TextError) -> FormatError ``` `error` translated across the boundary between this package's status convention and the formatting protocol. This is the only sanctioned crossing: every text failure becomes a `TextFailure` carrying the reason. It is the mapper a formatting operation hands a text operation's failure to, as in `builder.Append(view)? else (e => FromTextError(e))`. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/FormatError.rux#L91){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------- | ----------- | ---------------------------------------------- | | `error` | `TextError` | why the storage or validation operation failed | **Returns**: the matching formatting failure # FormatSpec Everything a placeholder asked for. ```rux pub struct FormatSpec { // private fields } ``` Copy, and cheap to pass: a spec is read, never held. Its representation is private, so a value applying a spec reads it and cannot alter what the placeholder asked for. ## Associated functions ### `Plain` ```rux pub func Plain() -> FormatSpec ``` What a bare `{}` asks for: nothing at all. Cannot fail. Runs in constant time and allocates nothing. **Returns**: a spec with no width, no precision, default alignment and base ten [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/Spec.rux#L84){rel=""nofollow""} ## Methods ### `Fill` ```rux pub func Fill(self: &FormatSpec) -> char8 ``` The byte that pads a rendering narrower than the width. Borrows the spec. Cannot fail; runs in constant time and allocates nothing. **Returns**: the fill byte, a space unless the placeholder named one [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/Spec.rux#L103){rel=""nofollow""} ### `Alignment` ```rux pub func Alignment(self: &FormatSpec) -> FormatAlign ``` Where the padding goes. `Default` means the value chooses, which is why it is a case rather than being resolved here: numbers pad on the left and text on the right, and only the value knows which it is. Borrows the spec. Cannot fail; runs in constant time and allocates nothing. **Returns**: the requested alignment, or `Default` when the placeholder named none [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/Spec.rux#L113){rel=""nofollow""} ### `ShowsSign` ```rux pub func ShowsSign(self: &FormatSpec) -> bool ``` Whether a non-negative number should carry a `+`. Borrows the spec. Cannot fail; runs in constant time and allocates nothing. **Returns**: true when the placeholder wrote `+` [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/Spec.rux#L121){rel=""nofollow""} ### `IsAlternate` ```rux pub func IsAlternate(self: &FormatSpec) -> bool ``` Whether a based integer should carry its `0b`, `0o` or `0x` prefix. Borrows the spec. Cannot fail; runs in constant time and allocates nothing. **Returns**: true when the placeholder wrote `#` [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/Spec.rux#L129){rel=""nofollow""} ### `ZeroPads` ```rux pub func ZeroPads(self: &FormatSpec) -> bool ``` Whether a number pads with zeros inside itself rather than with fill outside itself. Borrows the spec. Cannot fail; runs in constant time and allocates nothing. **Returns**: true when the placeholder wrote a leading `0` [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/Spec.rux#L137){rel=""nofollow""} ### `Width` ```rux pub func Width(self: &FormatSpec) -> uint ``` The fewest Unicode scalar values the rendering should occupy. Counted in scalars rather than bytes, so an accented name pads the same as an unaccented one. Borrows the spec. Cannot fail; runs in constant time and allocates nothing. **Returns**: the requested width, or zero when the placeholder asked for none [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/Spec.rux#L146){rel=""nofollow""} ### `Precision` ```rux pub func Precision(self: &FormatSpec) -> uint ``` How many characters of text to keep, or how many digits a float carries. Meaningful only when [`HasPrecision`](https://rux-lang.dev/docs/api/text/format-spec#has-precision) reports true: zero is a precision a caller can mean, so the value alone cannot say whether one was asked for. Borrows the spec. Cannot fail; runs in constant time and allocates nothing. **Returns**: the requested precision, meaningful only alongside [`HasPrecision`](https://rux-lang.dev/docs/api/text/format-spec#has-precision) [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/Spec.rux#L156){rel=""nofollow""} ### `HasPrecision` ```rux pub func HasPrecision(self: &FormatSpec) -> bool ``` Whether the placeholder named a precision at all. Borrows the spec. Cannot fail; runs in constant time and allocates nothing. **Returns**: true when a precision was written, including `.0` [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/Spec.rux#L164){rel=""nofollow""} ### `Base` ```rux pub func Base(self: &FormatSpec) -> FormatBase ``` The base an integer should render in. Borrows the spec. Cannot fail; runs in constant time and allocates nothing. **Returns**: the requested base, or `Decimal` when the placeholder named none [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/Spec.rux#L172){rel=""nofollow""} ### `Style` ```rux pub func Style(self: &FormatSpec) -> char8[..] ``` The style the specification named, or an empty slice when it named none. A value compares this against the styles it understands and reports `UnsupportedRequest` for anything else. The four single-letter integer bases are also reflected in [`Base`](https://rux-lang.dev/docs/api/text/format-spec#base), so an integer has no reason to read this. The result borrows the specification text this was parsed from and must not outlive it. Borrows the spec. Cannot fail; runs in constant time and allocates nothing. **Returns**: the style bytes, empty when no style was written [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/Spec.rux#L183){rel=""nofollow""} ### `HasStyle` ```rux pub func HasStyle(self: &FormatSpec) -> bool ``` Whether the specification named a style at all. Borrows the spec. Cannot fail; runs in constant time and allocates nothing. **Returns**: true when a style was written [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/Spec.rux#L191){rel=""nofollow""} ### `StyleIs` ```rux pub func StyleIs(self: &FormatSpec, name: char8[..]) -> bool ``` Whether the specification named exactly the style `name`. The comparison a value makes to decide whether a style is one of its own, written once so each renderer does not repeat a byte loop. Borrows the spec. Cannot fail; runs in time proportional to `name`, and allocates nothing. | Name | Type | Description | | ------ | ----------- | ---------------------------- | | `name` | `char8[..]` | the style to compare against | **Returns**: true when the specification named exactly that style [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/Spec.rux#L202){rel=""nofollow""} ## Related ### `PaddingAround` ```rux pub func PaddingAround( spec: FormatSpec, occupied: uint, numeric: bool, before: *var uint, after: *var uint ) ``` How many fill characters go on each side of a rendering that occupies `occupied` scalars. Split out from [`WriteAligned`](https://rux-lang.dev/docs/api/text/format-spec#write-aligned) because a numeric writer needs the two counts before it starts, so that a sign, a base prefix and the digits can go out in order without the rendered text existing anywhere as one run. `numeric` picks the default alignment: numbers sit to the right and text to the left, which is what makes a column of numbers line up its units and a column of names line up its first letters. Cannot fail. Runs in constant time and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/Align.rux#L23){rel=""nofollow""} **Parameters** | Name | Type | Description | | ---------- | ------------ | ---------------------------------------------------------------- | | `spec` | `FormatSpec` | what the placeholder asked for | | `occupied` | `uint` | how many Unicode scalar values the rendering occupies | | `numeric` | `bool` | true when the value aligns like a number by default | | `before` | `*var uint` | receives the count of fill characters that precede the rendering | | `after` | `*var uint` | receives the count that follow it | ### `WriteFill` ```rux pub func WriteFill( writer: &var TextWriter, spec: FormatSpec, count: uint ) -> ! FormatError ``` Writes `count` copies of the spec's fill byte. Reports whatever the writer reported, stopping at the first refusal rather than continuing to a destination that has already said no. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/Align.rux#L49){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | ----------------- | -------------------------------------------- | | `writer` | `&var TextWriter` | the destination | | `spec` | `FormatSpec` | the specification whose fill byte is written | | `count` | `uint` | how many copies to write | **Returns**: success when every copy was accepted ### `WriteAligned` ```rux pub func WriteAligned( writer: &var TextWriter, spec: FormatSpec, rendered: char8[..], numeric: bool ) -> ! FormatError ``` Writes `rendered` into `writer` under `spec`'s width, fill and alignment. Width is measured in Unicode scalar values rather than bytes, so a name with an accent pads the same as one without. A rendering already at or past the requested width is written through unpadded. Reports whatever the writer reported. A failure part-way leaves whatever the destination had already accepted; what that means is the destination's own documented guarantee. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/Align.rux#L69){rel=""nofollow""} **Parameters** | Name | Type | Description | | ---------- | ----------------- | ---------------------------------------------------------- | | `writer` | `&var TextWriter` | the destination | | `spec` | `FormatSpec` | what the placeholder asked for | | `rendered` | `char8[..]` | the already-rendered text, which must be well-formed UTF-8 | | `numeric` | `bool` | true when the value aligns like a number by default | **Returns**: success when the padded rendering was accepted in full ### `WriteDisplayAligned` ```rux pub func WriteDisplayAligned( writer: &var TextWriter, value: &Display, spec: FormatSpec ) -> ! FormatError ``` Writes `value`'s text under `spec`, applying the spec's width, fill and alignment around the text the value writes itself. For a value whose `WriteDisplay` writes its text in pieces, which [`WriteAligned`](https://rux-lang.dev/docs/api/text/format-spec#write-aligned) cannot pad: such a value calls this first when `spec` has a width. The value writes into 256 bytes of local room under the spec with no width, which is what keeps its own call from coming back here, and the room is then padded into `writer`. A rendering too long for the room is written through unpadded, since a width that short would add no padding anyway. Reports whatever the value or the writer reported. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/Align.rux#L94){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | ----------------- | ------------------------------ | | `writer` | `&var TextWriter` | the destination | | `value` | `&Display` | the value to render | | `spec` | `FormatSpec` | what the placeholder asked for | **Returns**: success when the padded rendering was accepted in full ### `FormatAlign` ```rux pub enum FormatAlign: int32 { Default = 0, Left = 1, Center = 2, Right = 3 } ``` Where the padding goes when the rendering is narrower than the width. Copy, carrying no payload. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/Spec.rux#L18){rel=""nofollow""} **Cases** | Name | Value | Description | | --------- | ----- | ------------------------------------------------------------------------- | | `Default` | `0` | The type's own default: numbers to the right, text to the left. | | `Left` | `1` | The value at the start, fill after it. | | `Center` | `2` | The value in the middle, fill on both sides, the odd column on the right. | | `Right` | `3` | The value at the end, fill before it. | ### `FormatBase` ```rux pub enum FormatBase: int32 { Decimal = 0, Binary = 1, Octal = 2, LowerHex = 3, UpperHex = 4 } ``` The base an integer renders in. Copy, carrying no payload. A negative signed integer renders in every base as a minus sign followed by the digits of its magnitude, not as its two's-complement bits: `{:b}` of `-5` is `-101` and `{:#x}` of `-255` is `-0xff`. That keeps the text of a value independent of the width of the type it happens to be stored in. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/Spec.rux#L34){rel=""nofollow""} **Cases** | Name | Value | Description | | ---------- | ----- | ------------------------------------------------------------------ | | `Decimal` | `0` | Base ten, the default. | | `Binary` | `1` | Base two, `b`, prefixed `0b` under `#`. | | `Octal` | `2` | Base eight, `o`, prefixed `0o` under `#`. | | `LowerHex` | `3` | Base sixteen with lower-case digits, `x`, prefixed `0x` under `#`. | | `UpperHex` | `4` | Base sixteen with upper-case digits, `X`, prefixed `0x` under `#`. | ### `ParseFormatSpec` ```rux pub func ParseFormatSpec(text: char8[..]) -> FormatSpec ! FormatError ``` Parses the text between `{:` and `}`. The grammar is `[[fill]align][+][#][0][width][.precision][style]`, every piece optional, so the empty specification is well-formed and asks for nothing. A style is an identifier: an ASCII letter followed by letters, digits, `_` or `-`. That covers the single-letter integer bases `b`, `o`, `x` and `X`, which also set [`Base`](https://rux-lang.dev/docs/api/text/format-spec#base) so an integer need not inspect the style text, the float styles `e` and `E` for scientific notation, and the domain styles such as `iso8601` and `hyphenated` that a value interprets for itself. Syntax is recognized here once; whether a style or flag *applies* is the value's question, since only the value knows whether a precision means digits, characters or nothing at all. A specification this accepts may still be refused with `UnsupportedRequest` by the value it is handed to. The returned specification's style borrows `text`. It must not outlive the specification text it was parsed from, and nothing here tracks that. Reports `InvalidSpecification` carrying the zero-based byte offset into `text` where parsing stopped: an unprintable or brace fill, a `.` with no digits after it, a width or precision whose arithmetic will not fit a `uint`, or any byte that can begin none of the remaining pieces. Nothing is written and no partial specification escapes. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/Spec.rux#L300){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------ | ----------- | ------------------------------------------------------------------- | | `text` | `char8[..]` | the specification body, without the surrounding braces or the colon | **Returns**: the parsed specification, or where it was malformed ### `RejectStyle` ```rux pub func RejectStyle(spec: FormatSpec) -> ! FormatError ``` Refuses a specification that names any style. The parser recognizes a style wherever the grammar allows one; whether it *means* anything is the value's question. A value with no styles of its own calls this so that `{:q}` is refused rather than silently rendered as though nothing had been asked for. Reports `UnsupportedRequest` when a style was written. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/Spec.rux#L383){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------ | ------------ | -------------------------- | | `spec` | `FormatSpec` | the specification to check | **Returns**: success when no style was named ### `RejectNonBaseStyle` ```rux pub func RejectNonBaseStyle(spec: FormatSpec) -> ! FormatError ``` Refuses a specification whose style is not one of the integer bases. What an integer supports is exactly `b`, `o`, `x` and `X`, and each of those is already reflected in [`Base`](https://rux-lang.dev/docs/api/text/format-spec#base). So a style that left the base decimal is one this value has no meaning for, which is what this refuses. It is the integer counterpart of [`RejectStyle`](https://rux-lang.dev/docs/api/text/format-spec#reject-style) and exists for the same reason. Reports `UnsupportedRequest` for a style that names no base. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/Spec.rux#L396){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------ | ------------ | -------------------------- | | `spec` | `FormatSpec` | the specification to check | **Returns**: success when no style was named, or the style named a base # String Text that owns its bytes. ```rux pub struct String { pub data: *var char8; pub length: uint; // private fields } ``` Copyable with value semantics: each copy owns an independent block and gives it back when it dies. ## Fields | Name | Type | Description | | -------- | ------------ | -------------------------------------------------- | | `data` | `*var char8` | The bytes, or null for text of no length. | | `length` | `uint` | How many bytes there are. Not how many characters. | ## Constructors ### `String` ```rux pub func String(allocator: Allocator) -> String ``` Text of no length, which has allocated nothing. `allocator` is borrowed for the call and kept, so an empty string can still grow into one that allocates. Cannot fail. Runs in constant time and allocates nothing. | Name | Type | Description | | ----------- | ----------- | ---------------------------- | | `allocator` | `Allocator` | where the storage comes from | **Returns**: an empty string that has taken no storage yet [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/String.rux#L60){rel=""nofollow""} ## Associated functions ### `FromValidated` ```rux pub func FromValidated( allocator: Allocator, bytes: char8[..] ) -> String ! TextError ``` A copy of bytes the caller vouches are UTF-8. Skips the pass [`FromBytes`](https://rux-lang.dev/docs/api/text/string#from-bytes) makes, which is what to use when the bytes came from something that already guarantees it — another string, a view, this package's own output. Fails with `OutOfMemory` when the copy cannot be made. The bytes must be well-formed UTF-8. Everything downstream assumes it, so bytes that are not produce wrong answers rather than errors. | Name | Type | Description | | ----------- | ----------- | ---------------------------- | | `allocator` | `Allocator` | where the storage comes from | | `bytes` | `char8[..]` | the bytes to act on | **Returns**: a string over those bytes, taken as valid without checking [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/String.rux#L74){rel=""nofollow""} ### `FromBytes` ```rux pub func FromBytes( allocator: Allocator, bytes: char8[..] ) -> String ! TextError ``` A copy of `bytes` as text, or why it could not be made. `bytes` is borrowed and copied, so what it names stays the caller's. It fails with `InvalidUtf8` when the bytes are not text and `OutOfMemory` when the copy cannot be made. Runs in time proportional to the length — one pass to check, one to copy — and allocates once. | Name | Type | Description | | ----------- | ----------- | ---------------------------- | | `allocator` | `Allocator` | where the storage comes from | | `bytes` | `char8[..]` | the bytes to act on | **Returns**: a string over those bytes, or an empty one when they are not valid UTF-8 [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/String.rux#L99){rel=""nofollow""} ### `FromView` ```rux pub func FromView( allocator: Allocator, view: StringView ) -> String ! TextError ``` A copy of what `view` spans. The view was checked when it was made, so this copies without checking again. | Name | Type | Description | | ----------- | ------------ | ---------------------------- | | `allocator` | `Allocator` | where the storage comes from | | `view` | `StringView` | the borrowed text to act on | **Returns**: a copy of that text this string owns [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/String.rux#L110){rel=""nofollow""} ## Methods ### `Length` ```rux pub func Length(self: &String) -> uint ``` How many bytes the text spans. Not how many characters: that is [`ScalarCount`](https://rux-lang.dev/docs/api/text/string#scalar-count), and it costs a pass. **Returns**: how many bytes the text occupies [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/String.rux#L118){rel=""nofollow""} ### `IsEmpty` ```rux pub func IsEmpty(self: &String) -> bool ``` Whether the text spans no bytes. **Returns**: whether the text has no bytes [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/String.rux#L125){rel=""nofollow""} ### `Bytes` ```rux pub func Bytes(self: &String) -> char8[..] ``` The bytes themselves, borrowed. **Returns**: the text's bytes, borrowed [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/String.rux#L132){rel=""nofollow""} ### `View` ```rux pub func View(self: &String) -> StringView ``` A view over this string, which is what to pass to anything that only reads. Copies nothing. The view borrows this string and must not outlive it. **Returns**: a borrowed view of the text [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/String.rux#L140){rel=""nofollow""} ### `ScalarCount` ```rux pub func ScalarCount(self: &String) -> uint ``` How many characters the text holds. **Returns**: how many Unicode scalar values the text holds, which is not its byte length [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/String.rux#L147){rel=""nofollow""} ### `IsBoundary` ```rux pub func IsBoundary(self: &String, index: uint) -> bool ``` Whether `index` is where a character starts, and so a place the text may be cut. | Name | Type | Description | | ------- | ------ | --------------- | | `index` | `uint` | the byte offset | **Returns**: whether `index` falls between two scalar values rather than inside one [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/String.rux#L155){rel=""nofollow""} ### `Part` ```rux pub func Part( self: &String, start: uint, end: uint ) -> StringView? ``` A borrowed view of the part from `start` up to `end`, or `none` when either end is not a boundary. Borrows rather than copying, since a part of a string is bytes the string already owns. [`Substring`](https://rux-lang.dev/docs/api/text/string#substring) is what makes an owning copy. | Name | Type | Description | | ------- | ------ | -------------------------------------------- | | `start` | `uint` | the first byte offset, inclusive | | `end` | `uint` | the byte offset one past the last, exclusive | **Returns**: the text between the two offsets, or `none` when either is not a boundary [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/String.rux#L166){rel=""nofollow""} ### `Substring` ```rux pub func Substring( self: &String, start: uint, end: uint ) -> String ! TextError ``` An owning copy of the part from `start` up to `end`. Fails with `NotABoundary` when either end would cut a character in half. | Name | Type | Description | | ------- | ------ | -------------------------------------------- | | `start` | `uint` | the first byte offset, inclusive | | `end` | `uint` | the byte offset one past the last, exclusive | **Returns**: an owned copy of that range, or why it could not be made [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/String.rux#L177){rel=""nofollow""} ### `Clone` ```rux pub func Clone(self: &String) -> String ! TextError ``` An independent copy, with a block of its own from the same allocator. **Returns**: an independent copy [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/String.rux#L185){rel=""nofollow""} ### `Equals` ```rux pub func Equals(self: &String, other: &String) -> bool ``` Whether two strings hold the same bytes. | Name | Type | Description | | ------- | --------- | ---------------------------- | | `other` | `&String` | the value to compare against | **Returns**: whether both hold the same bytes [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/String.rux#L193){rel=""nofollow""} ### `Compare` ```rux pub func Compare(self: &String, other: &String) -> Ordering ``` How this string orders against `other`, by bytes, which for UTF-8 is also by code point. | Name | Type | Description | | ------- | --------- | ---------------------------- | | `other` | `&String` | the value to compare against | **Returns**: how the two order byte by byte, which is code-point order for UTF-8 [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/String.rux#L203){rel=""nofollow""} ### `Clear` ```rux pub func Clear(self: &var String) ``` Gives the block back and leaves text of no length behind. Rarely needed: a string releases itself when it dies. This is for releasing one early, and is safe to call twice because what it leaves behind owns nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/String.rux#L213){rel=""nofollow""} ### `ReplaceWith` ```rux pub func ReplaceWith(self: &var String, value: String) ``` Replaces this string with `value`, transferring its block after releasing the old one. A fresh value transfers directly. Passing a named string first invokes its deep copy, so the caller keeps an independent original. | Name | Type | Description | | ------- | -------- | ------------------- | | `value` | `String` | the value to act on | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/String.rux#L230){rel=""nofollow""} ## Operators ### `=` ```rux pub func =(self: &var String, other: &String) ``` Deep-copies `other` into independent storage from the same allocator. The special copy operation cannot report allocation failure, so it terminates on exhaustion. Use [`Clone`](https://rux-lang.dev/docs/api/text/string#clone) when failure must be handled. The source remains valid and unchanged. | Name | Type | Description | | ------- | --------- | ---------------------------- | | `other` | `&String` | the value to compare against | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/String.rux#L40){rel=""nofollow""} ## Implements Display `String` conforms to [`Display`](https://rux-lang.dev/docs/api/text/display). ### `WriteDisplay` ```rux pub func WriteDisplay( self: &String, writer: &var TextWriter, spec: FormatSpec ) -> ! FormatError ``` Writes this string's bytes. Reports whatever the writer reported, and `UnsupportedRequest` for a style, since text has none. | Name | Type | Description | | -------- | ----------------- | ------------------------------ | | `writer` | `&var TextWriter` | the destination | | `spec` | `FormatSpec` | what the placeholder asked for | **Returns**: success when the string's text was accepted [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/String.rux#L22){rel=""nofollow""} ## Implements Debug `String` conforms to [`Debug`](https://rux-lang.dev/docs/api/text/debug). ### `WriteDebug` ```rux pub func WriteDebug( self: &String, writer: &var TextWriter, spec: FormatSpec ) -> ! FormatError ``` Writes this string quoted and escaped. Reports whatever the writer reported, and `UnsupportedRequest` for a style. | Name | Type | Description | | -------- | ----------------- | ------------------------------ | | `writer` | `&var TextWriter` | the destination | | `spec` | `FormatSpec` | what the placeholder asked for | **Returns**: success when the quoted string was accepted [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/String.rux#L35){rel=""nofollow""} ## Destructor ```rux func ~String(self: &var String) ``` Gives the block back. Runs when the string dies. Copies have independent blocks, so each destructor releases exactly its own. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/String.rux#L245){rel=""nofollow""} # StringBuilder A growable buffer of text. ```rux pub struct StringBuilder { // private fields } ``` Move-only: it explicitly prohibits copying and owns its block. Holds well-formed UTF-8 at every moment. ## Constructors ### `StringBuilder` ```rux pub func StringBuilder(allocator: Allocator) -> StringBuilder ``` A builder that has allocated nothing. `allocator` is borrowed for the call and kept. Cannot fail. Runs in constant time and allocates nothing. | Name | Type | Description | | ----------- | ----------- | ---------------------------- | | `allocator` | `Allocator` | where the storage comes from | **Returns**: an empty builder that has taken no storage yet [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/StringBuilder.rux#L44){rel=""nofollow""} ## Associated functions ### `WithCapacity` ```rux pub func WithCapacity( allocator: Allocator, capacity: uint ) -> StringBuilder ! TextError ``` A builder with room for `capacity` bytes already taken. Worth using when the size is known or can be guessed well: appends that stay within the room never reallocate. Fails with `OutOfMemory` when the room cannot be had. | Name | Type | Description | | ----------- | ----------- | ---------------------------------- | | `allocator` | `Allocator` | where the storage comes from | | `capacity` | `uint` | how many bytes to reserve up front | **Returns**: an empty builder with room for that many bytes already taken [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/StringBuilder.rux#L55){rel=""nofollow""} ## Methods ### `Length` ```rux pub func Length(self: &StringBuilder) -> uint ``` How many bytes are in use. **Returns**: how many bytes have been appended [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/StringBuilder.rux#L64){rel=""nofollow""} ### `Capacity` ```rux pub func Capacity(self: &StringBuilder) -> uint ``` How many bytes the block holds. **Returns**: how many bytes fit before the next growth [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/StringBuilder.rux#L71){rel=""nofollow""} ### `IsEmpty` ```rux pub func IsEmpty(self: &StringBuilder) -> bool ``` Whether nothing has been appended. **Returns**: whether nothing has been appended [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/StringBuilder.rux#L78){rel=""nofollow""} ### `Bytes` ```rux pub func Bytes(self: &StringBuilder) -> char8[..] ``` The bytes in use, borrowed. **Returns**: the appended bytes, borrowed [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/StringBuilder.rux#L85){rel=""nofollow""} ### `View` ```rux pub func View(self: &StringBuilder) -> StringView ``` A view over what has been appended so far. Free, and needs no checking: everything the builder accepts is whole characters, so what it holds is well-formed at every moment rather than only once it is finished. **Returns**: a borrowed view of what has been appended [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/StringBuilder.rux#L94){rel=""nofollow""} ### `Reserve` ```rux pub func Reserve( self: &var StringBuilder, additional: uint ) -> ! TextError ``` Makes sure there is room for `additional` more bytes. Reports `OutOfMemory` when the room cannot be had and `LengthOverflow` when the size needed cannot be expressed, having in both cases changed nothing: a builder that fails to grow still holds what it held. | Name | Type | Description | | ------------ | ------ | ------------------------------------ | | `additional` | `uint` | how many more bytes to make room for | **Returns**: nothing when the room is available, or why not [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/StringBuilder.rux#L104){rel=""nofollow""} ### `AppendValidated` ```rux pub func AppendValidated( self: &var StringBuilder, bytes: char8[..] ) -> ! TextError ``` Appends bytes the caller vouches are UTF-8. The bytes must be well-formed UTF-8 and must not end part-way through a character. The builder's promise that it holds text at every moment rests on this, and everything reading from it relies on that promise. | Name | Type | Description | | ------- | ----------- | ------------------- | | `bytes` | `char8[..]` | the bytes to act on | **Returns**: nothing when the bytes were appended, taken as valid without checking, or why not [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/StringBuilder.rux#L114){rel=""nofollow""} ### `Append` ```rux pub func Append( self: &var StringBuilder, view: StringView ) -> ! TextError pub func Append( self: &var StringBuilder, text: char8[..] ) -> ! TextError ``` Appends `text`. Text was checked before it existed, so nothing is checked again and nothing can fail but the storage. | Overload | Summary | | ---------------------------------------------------------------------------- | -------------------------- | | `pub func Append(self: &var StringBuilder, view: StringView) -> ! TextError` | Appends what `view` spans. | | `pub func Append(self: &var StringBuilder, text: char8[..]) -> ! TextError` | Appends `text`. | | Name | Type | Description | | ------ | ------------ | --------------------------- | | `view` | `StringView` | the borrowed text to act on | | `text` | `char8[..]` | the text to act on | **Returns**: nothing when the text was appended, or why not [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/StringBuilder.rux#L123){rel=""nofollow""} ### `AppendBytes` ```rux pub func AppendBytes( self: &var StringBuilder, bytes: char8[..] ) -> ! TextError ``` Appends `bytes` when they are UTF-8, and reports `InvalidUtf8` when they are not. Costs a pass over the bytes. [`Append`](https://rux-lang.dev/docs/api/text/string-builder#append) of a view costs none, which is the reason views exist. | Name | Type | Description | | ------- | ----------- | ------------------- | | `bytes` | `char8[..]` | the bytes to act on | **Returns**: nothing when the bytes were appended, after checking they are valid UTF-8, or why not [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/StringBuilder.rux#L141){rel=""nofollow""} ### `AppendScalar` ```rux pub func AppendScalar( self: &var StringBuilder, scalar: char32 ) -> ! TextError ``` Appends one character. Reports `InvalidUtf8` for a value that is not a scalar value — a surrogate half, or one past U+10FFFF -- which is what keeps a builder from holding something that is not text. | Name | Type | Description | | -------- | -------- | ------------------------ | | `scalar` | `char32` | the Unicode scalar value | **Returns**: nothing when the scalar's encoding was appended, or why not [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/StringBuilder.rux#L152){rel=""nofollow""} ### `AppendAscii` ```rux pub func AppendAscii( self: &var StringBuilder, byte: char8 ) -> ! TextError ``` Appends one ASCII byte. Reports `InvalidUtf8` for a byte above 0x7F, since a single byte above that is never a whole character; [`AppendScalar`](https://rux-lang.dev/docs/api/text/string-builder#append-scalar) is what appends one that takes more than a byte. | Name | Type | Description | | ------ | ------- | ----------- | | `byte` | `char8` | the byte | **Returns**: nothing when the byte was appended, or why not [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/StringBuilder.rux#L166){rel=""nofollow""} ### `Clear` ```rux pub func Clear(self: &var StringBuilder) ``` Forgets everything appended, keeping the room. The block is kept, so a builder used in a loop allocates once rather than once per pass. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/StringBuilder.rux#L176){rel=""nofollow""} ### `Release` ```rux pub func Release(self: &var StringBuilder) ``` Gives the block back and leaves a builder that owns nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/StringBuilder.rux#L182){rel=""nofollow""} ### `ToString` ```rux pub func ToString(self: &StringBuilder) -> String ! TextError ``` A copy of what has been appended, as a string of its own. The builder is untouched and may be appended to again. [`IntoString`](https://rux-lang.dev/docs/api/text/string-builder#into-string) is what hands the block over instead of copying it, and is what to use when the builder is finished with. **Returns**: a copy of what has been appended, leaving the builder as it was [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/StringBuilder.rux#L199){rel=""nofollow""} ### `IntoString` ```rux pub func IntoString(self: &var StringBuilder) -> String ``` Hands the block over as a string, leaving the builder owning nothing. Copies nothing: the string that comes back is the builder's block, which is why the builder must give it up. The block usually has room to spare, and the string remembers how much so that the allocator gets back the layout it handed out. Cannot fail. Runs in constant time and allocates nothing. **Returns**: what has been appended, taking the builder's storage rather than copying [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/StringBuilder.rux#L210){rel=""nofollow""} ## Implements TextWriter `StringBuilder` conforms to [`TextWriter`](https://rux-lang.dev/docs/api/text/text-writer). ### `Write` ```rux pub func Write( self: &var StringBuilder, bytes: char8[..] ) -> ! FormatError ``` Appends `bytes` to the builder. The bytes are validated here, which [`AppendValidated`](https://rux-lang.dev/docs/api/text/string-builder#append-validated) does not do: that one names bytes a caller has already checked and takes their validity as a precondition. A writer cannot, because what reaches it came from a value that may have produced anything, and the builder's promise to hold text at every moment is what everything reading from it relies on. Reports `TextFailure(InvalidUtf8)` for bytes that are not well-formed UTF-8, and `TextFailure(OutOfMemory)` when the builder cannot make room. In both cases nothing was appended: validity is decided before any byte moves, so the builder is exactly as it was and a caller may retry elsewhere without first undoing a partial write. A `WriterFailure` is impossible here, since there is no destination beyond the allocator, and `InsufficientCapacity` cannot arise because a builder grows. | Name | Type | Description | | ------- | ----------- | ------------------------------ | | `bytes` | `char8[..]` | the UTF-8 run to append, whole | **Returns**: success when the complete run was appended [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/StringBuilder.rux#L92){rel=""nofollow""} ## Destructor ```rux func ~StringBuilder(self: &var StringBuilder) ``` Gives the block back. Runs when the builder dies. A builder whose block was handed over by [`IntoString`](https://rux-lang.dev/docs/api/text/string-builder#into-string) owns nothing, so this is then a no-op rather than a second release. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/StringBuilder.rux#L227){rel=""nofollow""} ## Related ### `MinimumBuilderCapacity` ```rux pub const MinimumBuilderCapacity: uint = 16; ``` The room a builder takes when it first needs any. Small enough that a builder for a short string wastes little, large enough that short strings never grow twice. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/StringBuilder.rux#L18){rel=""nofollow""} # StringView A borrowed run of bytes that has been checked to be UTF-8. ```rux pub struct StringView { // private fields } ``` Copy, owning nothing. The bytes it names must outlive it. ## Constructors ### `StringView` ```rux pub func StringView() -> StringView ``` A view over nothing. Cannot fail. Runs in constant time and allocates nothing. **Returns**: an empty view [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/StringView.rux#L27){rel=""nofollow""} ## Associated functions ### `FromBytes` ```rux pub func FromBytes(bytes: char8[..]) -> StringView? ``` A view over `bytes` when they are UTF-8, and `none` when they are not. `bytes` is borrowed and must outlive the view. This is the only way to make a view out of bytes whose provenance is unknown, and it costs one pass over them. Runs in time proportional to the length and allocates nothing. | Name | Type | Description | | ------- | ----------- | ------------------- | | `bytes` | `char8[..]` | the bytes to act on | **Returns**: a view over those bytes, or `none` when they are not valid UTF-8 [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/StringView.rux#L38){rel=""nofollow""} ### `FromValidated` ```rux pub func FromValidated(bytes: char8[..]) -> StringView ``` A view over bytes the caller vouches are UTF-8. Skips the pass [`FromBytes`](https://rux-lang.dev/docs/api/text/string-view#from-bytes) makes, which is worth having when the bytes came from something that already guarantees it — another view, a [`String`](https://rux-lang.dev/docs/api/text/string), a literal. The bytes must be well-formed UTF-8. Everything downstream assumes it, so bytes that are not produce wrong answers rather than errors: a scalar walk reads past a truncated sequence, and a cut lands mid-character. | Name | Type | Description | | ------- | ----------- | ------------------- | | `bytes` | `char8[..]` | the bytes to act on | **Returns**: a view over those bytes, taken as valid without checking [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/StringView.rux#L51){rel=""nofollow""} ## Methods ### `StartsWith` ```rux pub func StartsWith( self: &StringView, prefix: StringView ) -> bool ``` Whether this view begins with `prefix`. Every view begins with the empty one. Runs in time proportional to the prefix and allocates nothing. | Name | Type | Description | | -------- | ------------ | --------------------------------- | | `prefix` | `StringView` | the text to look for at the start | **Returns**: whether the text begins with `prefix` [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/StringView.rux#L22){rel=""nofollow""} ### `EndsWith` ```rux pub func EndsWith( self: &StringView, suffix: StringView ) -> bool ``` Whether this view ends with `suffix`. | Name | Type | Description | | -------- | ------------ | ------------------------------- | | `suffix` | `StringView` | the text to look for at the end | **Returns**: whether the text ends with `suffix` [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/StringView.rux#L36){rel=""nofollow""} ### `IndexOf` ```rux pub func IndexOf( self: &StringView, needle: StringView ) -> uint? ``` The byte index where `needle` first occurs, or `none`. The empty needle occurs at the start, which is what makes `IndexOf` agree with [`StartsWith`](https://rux-lang.dev/docs/api/text/string-view#starts-with) for it. Runs in time proportional to the product of the lengths in the worst case, which for the short needles this is used with is the same as proportional to the text. | Name | Type | Description | | -------- | ------------ | -------------------- | | `needle` | `StringView` | the text to look for | **Returns**: the byte offset of the first occurrence, or `none` [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/StringView.rux#L54){rel=""nofollow""} ### `LastIndexOf` ```rux pub func LastIndexOf( self: &StringView, needle: StringView ) -> uint? ``` The byte index where `needle` last occurs, or `none`. | Name | Type | Description | | -------- | ------------ | -------------------- | | `needle` | `StringView` | the text to look for | **Returns**: the byte offset of the last occurrence, or `none` [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/StringView.rux#L81){rel=""nofollow""} ### `Contains` ```rux pub func Contains( self: &StringView, needle: StringView ) -> bool ``` Whether `needle` occurs anywhere in this view. | Name | Type | Description | | -------- | ------------ | -------------------- | | `needle` | `StringView` | the text to look for | **Returns**: whether `needle` occurs anywhere in the text [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/StringView.rux#L107){rel=""nofollow""} ### `TrimStart` ```rux pub func TrimStart(self: &StringView) -> StringView ``` This view without the ASCII whitespace at its start. Borrows: what comes back names the same bytes, further in. **Returns**: the text without its leading ASCII spaces [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/StringView.rux#L115){rel=""nofollow""} ### `TrimEnd` ```rux pub func TrimEnd(self: &StringView) -> StringView ``` This view without the ASCII whitespace at its end. **Returns**: the text without its trailing ASCII spaces [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/StringView.rux#L126){rel=""nofollow""} ### `Trim` ```rux pub func Trim(self: &StringView) -> StringView ``` This view without the ASCII whitespace at either end. **Returns**: the text without its leading and trailing ASCII spaces [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/StringView.rux#L137){rel=""nofollow""} ### `Lines` ```rux pub func Lines(self: &StringView) -> LineIterator ``` A walk over the lines of this view, each without its line break. A line ends at `\n` or `\r\n`; a break at the very end does not start another, empty line, so `"a\nb\n"` has two lines and empty text has none. A lone `\r` is part of its line. `self` is borrowed and must outlive the walk. **Returns**: a cursor over the lines [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/StringView.rux#L148){rel=""nofollow""} ### `Split` ```rux pub func Split( self: &StringView, separator: StringView ) -> SplitIterator ``` A walk over the parts of this view between occurrences of `separator`. `self` is borrowed and must outlive the walk, as must `separator`. | Name | Type | Description | | ----------- | ------------ | ---------------------------------- | | `separator` | `StringView` | the text that separates the pieces | **Returns**: a cursor over the pieces between separators [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/StringView.rux#L157){rel=""nofollow""} ### `Length` ```rux pub func Length(self: &StringView) -> uint ``` How many bytes the view spans. Not how many characters: that is [`ScalarCount`](https://rux-lang.dev/docs/api/text/string-view#scalar-count), and it costs a pass. **Returns**: how many bytes the text occupies [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/StringView.rux#L59){rel=""nofollow""} ### `IsEmpty` ```rux pub func IsEmpty(self: &StringView) -> bool ``` Whether the view spans no bytes. **Returns**: whether the text has no bytes [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/StringView.rux#L66){rel=""nofollow""} ### `Bytes` ```rux pub func Bytes(self: &StringView) -> char8[..] ``` The bytes themselves, for handing to something that reads bytes. **Returns**: the text's bytes, borrowed [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/StringView.rux#L73){rel=""nofollow""} ### `ScalarCount` ```rux pub func ScalarCount(self: &StringView) -> uint ``` How many scalar values the view holds. Runs in time proportional to the length: there is no way to know without looking, which is why this is a method rather than a field. **Returns**: how many Unicode scalar values the text holds, which is not its byte length [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/StringView.rux#L82){rel=""nofollow""} ### `IsBoundary` ```rux pub func IsBoundary(self: &StringView, index: uint) -> bool ``` Whether `index` is where a scalar value starts, and so a place this view may be cut. | Name | Type | Description | | ------- | ------ | --------------- | | `index` | `uint` | the byte offset | **Returns**: whether `index` falls between two scalar values rather than inside one [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/StringView.rux#L90){rel=""nofollow""} ### `Part` ```rux pub func Part( self: &StringView, start: uint, end: uint ) -> StringView? ``` The part of this view from `start` up to `end`, or `none` when either is not a boundary or they are the wrong way round. Half-open, so `Part(a, b)` and `Part(b, c)` together are `Part(a, c)`. Refusing a cut that is not on a boundary is the point: the alternative is a view whose first bytes are the tail of a character. Runs in constant time and allocates nothing. | Name | Type | Description | | ------- | ------ | -------------------------------------------- | | `start` | `uint` | the first byte offset, inclusive | | `end` | `uint` | the byte offset one past the last, exclusive | **Returns**: the text between the two offsets, or `none` when either is not a boundary [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/StringView.rux#L102){rel=""nofollow""} ### `ScalarAt` ```rux pub func ScalarAt(self: &StringView, index: uint) -> char32? ``` The scalar value starting at `index`, or `none` when `index` is not a boundary inside the view. | Name | Type | Description | | ------- | ------ | --------------- | | `index` | `uint` | the byte offset | **Returns**: the scalar value beginning at `index`, or `none` when it is not a boundary [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/StringView.rux#L113){rel=""nofollow""} ### `Equals` ```rux pub func Equals( self: &StringView, other: &StringView ) -> bool pub func Equals( self: &StringView, other: StringView ) -> bool ``` Whether two views hold the same bytes. Byte equality, which for well-formed UTF-8 is scalar-by-scalar equality, since each scalar value has exactly one encoding. It is not equality after normalization, which is a different question and a different package. | Overload | Summary | | ---------------------------------------------------------------- | -------------------------------------------------------------------------------------------- | | `pub func Equals(self: &StringView, other: &StringView) -> bool` | Whether two views hold the same bytes. | | `pub func Equals(self: &StringView, other: StringView) -> bool` | Whether this view and `other` hold the same bytes, as `Equals` with a borrowed view answers. | | Name | Type | Description | | ------- | ---------------------------- | ---------------------------- | | `other` | `&StringView` / `StringView` | the value to compare against | **Returns**: whether both hold the same bytes [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/StringView.rux#L126){rel=""nofollow""} ### `Compare` ```rux pub func Compare( self: &StringView, other: &StringView ) -> Ordering pub func Compare( self: &StringView, other: StringView ) -> Ordering ``` How this view orders against `other`, shortest first where one is a prefix of the other. Byte order, which for UTF-8 is also code point order: the encoding is built so that comparing bytes and comparing scalar values give the same answer. It is not alphabetical in any language. | Overload | Summary | | --------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------- | | `pub func Compare(self: &StringView, other: &StringView) -> Ordering` | How this view orders against `other`, shortest first where one is a prefix of the other. | | `pub func Compare(self: &StringView, other: StringView) -> Ordering` | How this view orders against `other`, as `Compare` with a borrowed view answers, taking the view as it stands. | | Name | Type | Description | | ------- | ---------------------------- | ---------------------------- | | `other` | `&StringView` / `StringView` | the value to compare against | **Returns**: how the two order byte by byte, which is code-point order for UTF-8 [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/StringView.rux#L142){rel=""nofollow""} ### `Scalars` ```rux pub func Scalars(self: &StringView) -> ScalarIterator ``` A walk over this view's scalar values. `self` is borrowed and must outlive the walk. **Returns**: a cursor over the text's scalar values [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/StringView.rux#L178){rel=""nofollow""} ## Implements Display `StringView` conforms to [`Display`](https://rux-lang.dev/docs/api/text/display). ### `WriteDisplay` ```rux pub func WriteDisplay( self: &StringView, writer: &var TextWriter, spec: FormatSpec ) -> ! FormatError ``` Writes what this view spans, truncated to the spec's precision and padded to its width. Precision counts Unicode scalar values rather than bytes, and a cut lands on a character boundary by construction: the walk that counts them is the walk that finds where to stop. Reports whatever the writer reported, and `UnsupportedRequest` for a style, since text has none. | Name | Type | Description | | -------- | ----------------- | ------------------------------ | | `writer` | `&var TextWriter` | the destination | | `spec` | `FormatSpec` | what the placeholder asked for | **Returns**: success when the view's text was accepted [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/StringView.rux#L50){rel=""nofollow""} ## Implements Debug `StringView` conforms to [`Debug`](https://rux-lang.dev/docs/api/text/debug). ### `WriteDebug` ```rux pub func WriteDebug( self: &StringView, writer: &var TextWriter, spec: FormatSpec ) -> ! FormatError ``` Writes what this view spans, quoted and escaped. The quotes sit outside the precision: what is kept is text, and the quotes say where it stops. Alignment is not applied, because padding a quoted rendering to a width would put the fill outside the quotes, where it would read as part of the surrounding text rather than as part of the value. Reports whatever the writer reported, stopping at the first refusal, so a failed opening quote is not followed by a body. Reports `UnsupportedRequest` for a style. | Name | Type | Description | | -------- | ----------------- | ------------------------------ | | `writer` | `&var TextWriter` | the destination | | `spec` | `FormatSpec` | what the placeholder asked for | **Returns**: success when the quoted view was accepted [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/StringView.rux#L67){rel=""nofollow""} ## Related ### `IsAsciiSpace` ```rux pub func IsAsciiSpace(byte: char8) -> bool ``` Whether `byte` is ASCII whitespace: space, tab, newline, carriage return, form feed or vertical tab. ASCII only, deliberately. Unicode calls a good many more characters whitespace, and which ones is a question for the tables; every one of them is multi-byte, so trimming by this rule never cuts a character in half. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/Search.rux#L172){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------ | ------- | ----------- | | `byte` | `char8` | the byte | **Returns**: whether the byte is one of ASCII's five space characters ### `SplitIterator` ```rux pub struct SplitIterator { // private fields } ``` A walk over the parts of a view between occurrences of a separator. Every part is a borrow of the original, so splitting allocates nothing however many parts there are. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/Search.rux#L180){rel=""nofollow""} **Implements Iterator** `SplitIterator` conforms to `Iterator`. #### `Next` ```rux pub func Next(self: &var SplitIterator) -> StringView? ``` The next part, or `none` when the walk is over. Two adjacent separators give an empty part between them, and a separator at either end gives an empty part there — so the parts always number one more than the separators, and joining them back with the separator gives what was split. An empty separator gives the whole view as one part, since anything else would be an endless walk. **Returns**: the next piece, or `none` at the end [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/Search.rux#L198){rel=""nofollow""} ### `LineIterator` ```rux pub struct LineIterator { // private fields } ``` A walk over the lines of a view, each without its line break. Every line is a borrow of the original, so walking allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/Search.rux#L220){rel=""nofollow""} **Implements Iterator** `LineIterator` conforms to `Iterator`. #### `Next` ```rux pub func Next(self: &var LineIterator) -> StringView? ``` The next line, without its `\n` or `\r\n`, or `none` after the last. **Returns**: the next line, or `none` at the end [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/Search.rux#L231){rel=""nofollow""} ### `ScalarIterator` ```rux pub struct ScalarIterator { // private fields } ``` A walk over the scalar values of a view, first to last. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/StringView.rux#L185){rel=""nofollow""} **Implements Iterator** `ScalarIterator` conforms to `Iterator`. #### `Next` ```rux pub func Next(self: &var ScalarIterator) -> char32? ``` The next scalar value, or `none` at the end. Bytes that are not well-formed end the walk rather than being reported: a view is validated when it is made, so reaching one means the bytes were vouched for and were not. **Returns**: the next scalar value, or `none` at the end [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/StringView.rux#L198){rel=""nofollow""} # TextError What went wrong. ```rux pub enum TextError: int32 { OutOfMemory = 1, LengthOverflow = 2, InvalidUtf8 = 3, NotABoundary = 4 } ``` Every case is a failure. An operation that can fail returns its result, or nothing, through a native fallible `T ! TextError`, so success is the other channel rather than a case here. ## Cases | Name | Value | Description | | ---------------- | ----- | --------------------------------------------------------------------------------------- | | `OutOfMemory` | `1` | The allocator could not supply the storage. | | `LengthOverflow` | `2` | A length or offset computation passed what a `uint` can hold. | | `InvalidUtf8` | `3` | The bytes are not well-formed UTF-8. | | `NotABoundary` | `4` | A byte offset that is not where a character starts, and so not a place text may be cut. | ## Implements Display `TextError` conforms to [`Display`](https://rux-lang.dev/docs/api/text/display). ### `WriteDisplay` ```rux pub func WriteDisplay( self: &TextError, writer: &var TextWriter, spec: FormatSpec ) -> ! FormatError ``` Writes the description of what went wrong, or `no error` for success. The words are stable: they end up in logs and issue reports, and changing them later breaks every reader quietly. They are a description and not a parsing contract — a program branches on the case, not the text. Reports whatever the writer reported, and `UnsupportedRequest` for any style or precision. | Name | Type | Description | | -------- | ----------------- | ------------------------------ | | `writer` | `&var TextWriter` | the destination | | `spec` | `FormatSpec` | what the placeholder asked for | **Returns**: success when the whole description was accepted [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/TextError.rux#L80){rel=""nofollow""} ## Implements Debug `TextError` conforms to [`Debug`](https://rux-lang.dev/docs/api/text/debug). ### `WriteDebug` ```rux pub func WriteDebug( self: &TextError, writer: &var TextWriter, spec: FormatSpec ) -> ! FormatError ``` Names the case, qualified by its type: `TextError::InvalidUtf8`. Reports whatever the writer reported, and `UnsupportedRequest` for any style or precision. | Name | Type | Description | | -------- | ----------------- | ------------------------------ | | `writer` | `&var TextWriter` | the destination | | `spec` | `FormatSpec` | what the placeholder asked for | **Returns**: success when the whole name was accepted [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/TextError.rux#L98){rel=""nofollow""} ## Related ### `FromAllocError` ```rux pub func FromAllocError(error: AllocError) -> TextError ``` The text error an allocator's failure becomes. Everything an allocator can refuse is a failure to supply storage as far as text is concerned; the distinctions the allocator draws are about the request, and this package makes no requests a caller could have made differently. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/TextError.rux#L31){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------- | ------------ | ------------------------- | | `error` | `AllocError` | why the allocator refused | **Returns**: the same failure as a text error # Utf8Error What was wrong with a byte sequence. ```rux pub enum Utf8Error: int32 { Truncated = 1, InvalidStart = 2, InvalidContinuation = 3 } ``` The cases are distinguished because they mean different things about where the bytes came from. `Truncated` is what a buffer boundary looks like and may just mean read more; the rest mean the bytes are not UTF-8 and no amount of reading will change that. Every case is a failure: the functions here report success through the other channel of the native fallible they return. ## Cases | Name | Value | Description | | --------------------- | ----- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `Truncated` | `1` | A sequence starts but the bytes run out before it ends. | | `InvalidStart` | `2` | A byte that cannot start a sequence: a continuation byte on its own, or one of the values UTF-8 never uses. | | `InvalidContinuation` | `3` | A byte where a continuation byte was required, or a continuation outside the range this leading byte allows — which is what rejects an overlong form, a surrogate half, or a value past the last scalar. | ## Implements Display `Utf8Error` conforms to [`Display`](https://rux-lang.dev/docs/api/text/display). ### `WriteDisplay` ```rux pub func WriteDisplay( self: &Utf8Error, writer: &var TextWriter, spec: FormatSpec ) -> ! FormatError ``` Writes the description of what is wrong with a byte sequence, or `well-formed UTF-8` for success. Reports whatever the writer reported, and `UnsupportedRequest` for any style or precision. | Name | Type | Description | | -------- | ----------------- | ------------------------------ | | `writer` | `&var TextWriter` | the destination | | `spec` | `FormatSpec` | what the placeholder asked for | **Returns**: success when the whole description was accepted [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/Utf8.rux#L212){rel=""nofollow""} ## Implements Debug `Utf8Error` conforms to [`Debug`](https://rux-lang.dev/docs/api/text/debug). ### `WriteDebug` ```rux pub func WriteDebug( self: &Utf8Error, writer: &var TextWriter, spec: FormatSpec ) -> ! FormatError ``` Names the case, qualified by its type: `Utf8Error::Truncated`. Reports whatever the writer reported, and `UnsupportedRequest` for any style or precision. | Name | Type | Description | | -------- | ----------------- | ------------------------------ | | `writer` | `&var TextWriter` | the destination | | `spec` | `FormatSpec` | what the placeholder asked for | **Returns**: success when the whole name was accepted [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/Utf8.rux#L229){rel=""nofollow""} # Transforming text New strings made from old: concatenation, repetition, replacement and ASCII case. ## `Join` ```rux pub func Join( allocator: Allocator, parts: StringView[..], separator: StringView ) -> String ! TextError ``` The text of every part of `parts` in order, with `separator` between each two. No parts give empty text and one part gives that part, so the separator count is always one less than the parts. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/Transform.rux#L21){rel=""nofollow""} **Parameters** | Name | Type | Description | | ----------- | ---------------- | ---------------------------- | | `allocator` | `Allocator` | where the storage comes from | | `parts` | `StringView[..]` | the pieces to join | | `separator` | `StringView` | what goes between them | **Returns**: the joined text, or why it could not be made ## `ToUpper` ```rux pub func ToUpper( allocator: Allocator, view: StringView ) -> String ! TextError ``` The text of `view` in upper case by Unicode's full, unconditional mappings, so `ß` becomes `SS` and `ʼn` becomes `ʼN`. The length may change. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/Transform.rux#L77){rel=""nofollow""} **Parameters** | Name | Type | Description | | ----------- | ------------ | ---------------------------- | | `allocator` | `Allocator` | where the storage comes from | | `view` | `StringView` | the borrowed text to act on | **Returns**: the text in upper case, or why it could not be made ## `ToLower` ```rux pub func ToLower( allocator: Allocator, view: StringView ) -> String ! TextError ``` The text of `view` in lower case by Unicode's full, unconditional mappings. A capital sigma always becomes `σ`, never the final `ς`, since which one is right depends on the letters around it. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/Transform.rux#L87){rel=""nofollow""} **Parameters** | Name | Type | Description | | ----------- | ------------ | ---------------------------- | | `allocator` | `Allocator` | where the storage comes from | | `view` | `StringView` | the borrowed text to act on | **Returns**: the text in lower case, or why it could not be made ## `FoldCase` ```rux pub func FoldCase( allocator: Allocator, view: StringView ) -> String ! TextError ``` The text of `view` case-folded by Unicode's full folding, the form for comparing text without regard to case: two texts that differ only in case fold to the same bytes, `Straße` and `STRASSE` included. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/Transform.rux#L97){rel=""nofollow""} **Parameters** | Name | Type | Description | | ----------- | ------------ | ---------------------------- | | `allocator` | `Allocator` | where the storage comes from | | `view` | `StringView` | the borrowed text to act on | **Returns**: the folded text, or why it could not be made ## `Concat` ```rux pub func Concat( allocator: Allocator, left: StringView, right: StringView ) -> String ! TextError ``` The text of `left` followed by the text of `right`. Fails with what went wrong; no partial text comes back. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/Transform.rux#L108){rel=""nofollow""} **Parameters** | Name | Type | Description | | ----------- | ------------ | ---------------------------- | | `allocator` | `Allocator` | where the storage comes from | | `left` | `StringView` | the first piece | | `right` | `StringView` | the second | **Returns**: the two joined, or why they could not be ## `Repeat` ```rux pub func Repeat( allocator: Allocator, view: StringView, count: uint ) -> String ! TextError ``` The text of `view` written `count` times. A `count` of zero gives empty text, which is what makes repeating agree with joining: repeating twice is the same as joining a thing to itself. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/Transform.rux#L124){rel=""nofollow""} **Parameters** | Name | Type | Description | | ----------- | ------------ | ---------------------------- | | `allocator` | `Allocator` | where the storage comes from | | `view` | `StringView` | the borrowed text to act on | | `count` | `uint` | how many times | **Returns**: the text repeated that many times, or why it could not be ## `Replace` ```rux pub func Replace( allocator: Allocator, view: StringView, needle: StringView, replacement: StringView ) -> String ! TextError ``` The text of `view` with every occurrence of `needle` replaced by `replacement`. Occurrences are found left to right and never overlap, and what is put in their place is not searched again -- so replacing `a` with `aa` terminates rather than growing forever. An empty `needle` matches nothing, since the alternative is a replacement between every pair of characters and before and after every one of them. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/Transform.rux#L150){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------------- | ------------ | ---------------------------- | | `allocator` | `Allocator` | where the storage comes from | | `view` | `StringView` | the borrowed text to act on | | `needle` | `StringView` | the text to look for | | `replacement` | `StringView` | the text to put in its place | **Returns**: the text with every occurrence replaced, or why it could not be ## `IsAsciiLetter` ```rux pub func IsAsciiLetter(byte: char8) -> bool ``` Whether `byte` is an ASCII letter. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/Transform.rux#L180){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------ | ------- | ----------- | | `byte` | `char8` | the byte | **Returns**: whether the byte is an ASCII letter ## `ToAsciiUpper` ```rux pub func ToAsciiUpper( allocator: Allocator, view: StringView ) -> String ! TextError ``` The text of `view` with every ASCII lower-case letter raised, and everything else left alone. ASCII only: every byte above 0x7F passes through untouched, which is why this cannot change the length and cannot produce anything that is not UTF-8. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/Transform.rux#L192){rel=""nofollow""} **Parameters** | Name | Type | Description | | ----------- | ------------ | ---------------------------- | | `allocator` | `Allocator` | where the storage comes from | | `view` | `StringView` | the borrowed text to act on | **Returns**: the text with its ASCII letters uppercased and everything else untouched ## `ToAsciiLower` ```rux pub func ToAsciiLower( allocator: Allocator, view: StringView ) -> String ! TextError ``` The text of `view` with every ASCII upper-case letter lowered. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/Transform.rux#L201){rel=""nofollow""} **Parameters** | Name | Type | Description | | ----------- | ------------ | ---------------------------- | | `allocator` | `Allocator` | where the storage comes from | | `view` | `StringView` | the borrowed text to act on | **Returns**: the text with its ASCII letters lowercased and everything else untouched # UTF-8 Encoding, decoding and validating UTF-8, and the limits of a Unicode scalar value. ## `MaxScalarValue` ```rux pub const MaxScalarValue: uint32 = 0x10FFFF; ``` The largest Unicode scalar value. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/Utf8.rux#L19){rel=""nofollow""} ## `FirstSurrogate` ```rux pub const FirstSurrogate: uint32 = 0xD800; ``` The first value of the surrogate range, which holds no scalar values. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/Utf8.rux#L23){rel=""nofollow""} ## `LastSurrogate` ```rux pub const LastSurrogate: uint32 = 0xDFFF; ``` The last value of the surrogate range. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/Utf8.rux#L27){rel=""nofollow""} ## `MaxEncodedLength` ```rux pub const MaxEncodedLength: uint = 4; ``` The most bytes any one scalar value takes in UTF-8. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/Utf8.rux#L31){rel=""nofollow""} ## `DecodedScalar` ```rux pub struct DecodedScalar { pub scalar: char32; pub width: uint; } ``` One scalar value decoded from UTF-8, with the number of bytes it occupied. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/Utf8.rux#L51){rel=""nofollow""} **Fields** | Name | Type | Description | | -------- | -------- | --------------------------------------------- | | `scalar` | `char32` | The Unicode scalar value. | | `width` | `uint` | How many bytes it occupied, one through four. | ## `Utf8Failure` ```rux pub struct Utf8Failure { pub reason: Utf8Error; pub index: uint; } ``` Where and why a byte sequence stopped being well-formed UTF-8. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/Utf8.rux#L60){rel=""nofollow""} **Fields** | Name | Type | Description | | -------- | ----------- | ---------------------------------------------------------- | | `reason` | `Utf8Error` | What was wrong. | | `index` | `uint` | The offset of the byte that starts the offending sequence. | ## `IsScalarValue` ```rux pub func IsScalarValue(value: uint32) -> bool ``` Whether `value` is a Unicode scalar value: at most [`MaxScalarValue`](https://rux-lang.dev/docs/api/text/utf8#max-scalar-value), and not a surrogate half. Cannot fail. Runs in constant time and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/Utf8.rux#L72){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------- | -------- | ------------------- | | `value` | `uint32` | the value to act on | **Returns**: whether the value is a Unicode scalar value, which excludes the surrogates ## `EncodedLength` ```rux pub func EncodedLength(scalar: char32) -> uint ``` How many bytes `scalar` takes in UTF-8, or zero when it is not a scalar value. Cannot fail. Runs in constant time and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/Utf8.rux#L81){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | -------- | ------------------------ | | `scalar` | `char32` | the Unicode scalar value | **Returns**: how many bytes the scalar's encoding occupies, one through four ## `IsContinuation` ```rux pub func IsContinuation(byte: char8) -> bool ``` Whether `byte` is a continuation byte, the `10xxxxxx` shape every byte after a leading one has. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/Utf8.rux#L94){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------ | ------- | ----------- | | `byte` | `char8` | the byte | **Returns**: whether the byte continues a sequence rather than starting one ## `Encode` ```rux pub func Encode( scalar: char32, into: var char8[..] ) -> uint ! Utf8Error ``` Writes `scalar` into `into` as UTF-8 and reports how many bytes it took. `into` is borrowed mutably and must have room for the encoding — at most [`MaxEncodedLength`](https://rux-lang.dev/docs/api/text/utf8#max-encoded-length) bytes. Fails with `InvalidStart` for a value that is not a scalar value, and `Truncated` when there is not enough room; nothing is written in either case. Cannot allocate. Runs in constant time. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/Utf8.rux#L107){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | --------------- | ------------------------ | | `scalar` | `char32` | the Unicode scalar value | | `into` | `var char8[..]` | receives the bytes | **Returns**: how many bytes were written, or why none were ## `DecodeAt` ```rux pub func DecodeAt( bytes: char8[..], index: uint ) -> DecodedScalar ! Utf8Error ``` Decodes the scalar value starting at `index`, reporting it and how many bytes it occupied. `bytes` is borrowed. On a failure the caller decides what to do — a decoder replacing bad input with U+FFFD advances one byte and carries on, and one rejecting it stops. Cannot allocate. Runs in constant time. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/Utf8.rux#L190){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------- | ----------- | ------------------- | | `bytes` | `char8[..]` | the bytes to act on | | `index` | `uint` | the byte offset | **Returns**: the scalar and its width, or why the bytes there are not one ## `Validate` ```rux pub func Validate(bytes: char8[..]) -> ! Utf8Failure ``` Whether `bytes` is well-formed UTF-8 from end to end, reporting where it first is not. `bytes` is borrowed. A failure carries the index of the byte that starts the offending sequence. Cannot allocate. Runs in time proportional to the length. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/Utf8.rux#L227){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------- | ----------- | ------------------- | | `bytes` | `char8[..]` | the bytes to act on | **Returns**: nothing when every byte is part of a valid sequence, or where and why the first one is not ## `IsBoundary` ```rux pub func IsBoundary(bytes: char8[..], index: uint) -> bool ``` Whether `index` is where a scalar value starts, and so a place a string may be cut. The length counts as a boundary, so the end of a string is always a legal cut. An index past the length is not. Cannot fail. Runs in constant time and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/Utf8.rux#L242){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------- | ----------- | ------------------- | | `bytes` | `char8[..]` | the bytes to act on | | `index` | `uint` | the byte offset | **Returns**: whether `index` falls between two scalar values rather than inside one ## `CountScalars` ```rux pub func CountScalars(bytes: char8[..]) -> uint ``` How many scalar values `bytes` holds, assuming it is well-formed. Counts leading bytes, which is one per scalar value in well-formed UTF-8. Bytes that are not well-formed give a count that means nothing; [`Validate`](https://rux-lang.dev/docs/api/text/utf8#validate) is what answers whether they are. Cannot fail. Runs in time proportional to the length and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/Utf8.rux#L255){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------- | ----------- | ------------------- | | `bytes` | `char8[..]` | the bytes to act on | **Returns**: how many scalar values the bytes encode ## `BoundaryAtOrBelow` ```rux pub func BoundaryAtOrBelow( bytes: char8[..], index: uint ) -> uint ``` The index of the scalar boundary at or below `index`. An index inside a sequence is walked back to the start of that sequence, which is what a caller cutting at an arbitrary byte offset needs. An index at or past the length gives the length. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Text/Src/Utf8.rux#L274){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------- | ----------- | ------------------- | | `bytes` | `char8[..]` | the bytes to act on | | `index` | `uint` | the byte offset | **Returns**: the largest boundary at or below `index`, so a truncation splits nothing # Format String conversion and formatting. ## Installation Add `Format` to the `[Dependencies]` table of your package's `Rux.toml`: ```toml [Dependencies] Format = { Namespace = "Rux", Version = "0.1.0" } ``` Standard packages are declared by hand: the registry does not serve them, so `rux add Rux/Format` cannot add them. ## Dependencies - [`Allocator`](https://rux-lang.dev/docs/api/allocator) 0.1.0 - [`Core`](https://rux-lang.dev/docs/api/core) 0.1.0 - [`Text`](https://rux-lang.dev/docs/api/text) 0.1.0 ## Guide String conversion and formatting: turning values into text, and text back into values. ### What it provides - **Placeholder rendering** — [`WriteFormat`](https://rux-lang.dev/docs/api/format/write-format) fills each `{}` from the next argument into a destination the caller supplies, and [`Render`](https://rux-lang.dev/docs/api/format/render) is the allocating entry point that answers with a `String` of its own. Used by [`Rux/Io`](https://github.com/rux-lang/Rux/blob/main/Packages/Format/../Io){rel=""nofollow""} to implement `Print` and `PrintLine`. - **A pattern that is wrong is refused, not printed** — the grammar is `{}`, `{:spec}`, `{{` and `}}`, and anything else containing a brace is a mistake. A specification that does not parse reports `InvalidSpecification` with its byte offset into the pattern; a placeholder count that does not match the arguments reports `ArgumentCountMismatch` with both numbers. Both are found before anything is written, so a wrong pattern produces no output rather than a prefix of one. A value's own rendering can still fail partway, and what it managed to write stays written. - **Primitive conversion, both directions** — every boolean, character and integer width, and `float8` through `float64`, implements `Display` and `Debug`, and the parsers read text back. `float80` and wider are reached through the wide values below, because their text allocates. The two halves share the digit machinery, the base handling and the exactness argument, which is why they are one package: splitting them would duplicate all three and let the halves disagree about what a value's text is. - **The presentation contracts live in [`Rux/Text`](https://github.com/rux-lang/Rux/blob/main/Packages/Format/../Text){rel=""nofollow""}** — `Display`, `Debug`, `TextWriter`, `FormatSpec` and `FormatError` are declared there, so a package can describe its own values without depending on this conversion engine. What stays here is the numeric spelling of a value: digits, sign, base prefix and zero padding. - **The digit machinery** — [`WriteInt`](https://rux-lang.dev/docs/api/format/integer-text#write-int), [`WriteUint`](https://rux-lang.dev/docs/api/format/integer-text#write-uint), `WriteFloat` and the decimal helpers, writing into a stack buffer through [`ByteCursor`](https://rux-lang.dev/docs/api/format/byte-cursor) so no primitive's rendering allocates. - **Borrowed primitive receivers** — primitive `WriteDisplay` and `WriteDebug` methods take `self: &T`. Their scalar reads preserve the existing output without transferring ownership or allocating; both direct calls and interface views borrow the caller's storage. - **Narrow floats read back exactly** — [`ParseFloat64`](https://rux-lang.dev/docs/api/format/parse-float#parse-float64) and [`ParseFloat32`](https://rux-lang.dev/docs/api/format/parse-float#parse-float32) form the decimal as an exact ratio and take the significand's bits from it, rounding to nearest with ties to even, so what a decimal names is the float nearest it and never one step off. A `float32` is read at its own precision rather than at a `float64`'s and narrowed, which would round twice. Overflow is refused rather than rounded to an infinity; underflow is the signed zero it rounds to. With the renderer this closes the loop: every `float32` and `float64` renders to a decimal that reads back as the same bits, across the whole exponent range. - **Parsing, and where it stopped** — every width has a `Parse*` answering `T ! ParseError`, and every [`ParseError`](https://rux-lang.dev/docs/api/format/parse-error) says where in the text it was found: `InvalidCharacter` at the byte, `Overflow` at the digit that passed the widest magnitude or at the end of a number that does not fit the width asked for, and `Empty` at zero, which is an empty text's only position. [`ParseError`](https://rux-lang.dev/docs/api/format/parse-error) implements `Text::ParseFailure`, so an embedding grammar adds its token's offset and the positions compose. There is no `bool`-and-output-slot overload: a `Result` cannot be ignored the way a returned `bool` could, and it carries why as well as whether. - **An allocation failure is not an overflow** — the wide float parser builds exact big integers to round with, and a failure to get storage for one reports `OutOfMemory` rather than `Overflow`. The two want different responses: one input is too large for the format whatever the machine does, the other reads fine on a less busy machine. - **Two answers for a value that is not a character** — `Display` writes [`ReplacementCharacter`](https://rux-lang.dev/docs/api/format/character-text#replacement-character), U+FFFD, for a `char8` above 0x7F, a `char16` that is half of a surrogate pair, and a `char32` or any wider character cast from a number no character has. `Debug` writes the value itself instead — `'\x{80}'` for a stray byte, `'\u{d800}'` for a lone half — so two values that render alike for a reader are told apart for a program, and a `char128`, `char256` or `char512` holding a number past 2^64 keeps every digit of it in the escape. A `char64` or wider is checked at its own width before anything is narrowed, because `0x100000041` narrows into a perfectly good `A` and the wrong character is harder to notice than a refused one. Neither half is a validation: `Rux/Text`'s strict conversions still refuse what is not text. - **Character slices at all three widths** — `char8[..]` is copied through, and `char16[..]` and `char32[..]` are transcoded to UTF-8 under the same replacement rule, decoding surrogate pairs and replacing a lone half. A width counts the characters a slice renders rather than the units it holds, and nothing is transcoded into a buffer first, so a slice has no length bound. - **Narrow floats render the shortest decimal that reads back as the same bits** — exactly, by the method in [Docs/NarrowFloat.md](https://github.com/rux-lang/Rux/blob/main/Packages/Format/../../Docs/NarrowFloat.md){rel=""nofollow""}: the value and the gaps to its two neighbours are held as exact integer ratios in a fixed workspace, digits come out one at a time, and generation stops the moment what has been written is nearer this value than either neighbour. So `0.1` prints as `0.1` and a third of one prints to the sixteen digits it needs rather than to a fixed fifteen. Nothing allocates and nothing is approximated, so there is no fallback path. `float16` and `float8` render through the same generator at their own precision, so the shortest digits are the ones that read back at that width rather than at a `float32`'s — `float16::Max`, 65504, prints as `65500.0`, since no other `float16` is nearer. `{}` switches to scientific notation from a decimal exponent of 5 for a `float16` and 3 for a `float8`, the digit counts that tell every value of the width apart, as 9 does for a `float32` and 17 for a `float64`. - **A precision is exact, or refused** — `{:.N}` means N digits after the decimal point, rounded to nearest with ties to even, generated from the same exact ratio the shortest form is. A carry runs the whole length of the digits, so `{:.1}` of 9.99 is `10.0`; a value far below the last place is a tail of zeros; and `{:.20}` of `0.1` is the float's own expansion rather than a tenth's. The supported precision is 0 to 1,100 digits, which is exactly enough for every `float64`, and a request past it reports `UnsupportedRequest` — there is no fallback to a different rendering. - **Scientific notation on request** — `{:e}` and `{:E}` write a `float8`, `float16`, `float32` or `float64` as one digit, a point, the remaining digits, the mark and a signed exponent of at least two digits: `{:e}` of `123456.0` is `1.23456e+05` and `{:E}` of `1e300` is `1.0E+300`, the same spelling `{}` falls back to for a value too large or too small for fixed notation. Without a precision the digits are the shortest that read back as the same value, with `.0` after a lone digit; with one, the precision counts the digits after the point, exact and rounded with ties to even, so `{:.3e}` of `1234.5678` is `1.235e+03` and `{:.0e}` of `9.5` is `1e+01`. A zero is `0.0e+00`. Any other style on a float reports `UnsupportedRequest`. - **NaN and infinity are words under every placeholder** — `NaN`, `Inf` and `-Inf`, whatever precision or style was asked for, with the placeholder's sign, width, fill and alignment applied: `{:+.2}` of an infinity is `+Inf`. A NaN shows no sign. - **A based integer keeps its sign** — `{:b}`, `{:o}`, `{:x}` and `{:X}` of a negative signed integer write a minus sign and the magnitude's digits, not two's-complement bits, so `{:b}` of `-5i8` is `-101` and the text does not depend on the type's width. - **Float support** — `IsFinite`, `IsInfinite` and `IsNan` for `float8`, `float16`, `float32` and `float64`, plus `Pow10` and `ScaleByPow10`, so decimal conversion stays exact where it can be. - **The wide widths** — [`Float80`](https://rux-lang.dev/docs/api/format/float80), [`Float128`](https://rux-lang.dev/docs/api/format/float128), [`Float256`](https://rux-lang.dev/docs/api/format/float256) and [`Float512`](https://rux-lang.dev/docs/api/format/float512), held as their bits. A value is made from bits, read from text, or taken from the primitive of its width with `FromValue` — `Float128::FromValue(x)` for a `float128` `x` — and `Value()` hands the primitive back, so a computed value renders with `Float128::FromValue(x).FormatWith(allocator, writer, spec)` and a parsed one is computed with as `ParseFloat128(allocator, text)?.Value()`. Both directions move the bits and nothing else; a [`Float80`](https://rux-lang.dev/docs/api/format/float80) keeps only the low eighty, so the six padding bytes of a `float80`'s storage are neither read nor written. Each answers `IsNan`, `IsInfinite`, `IsFinite` and `IsNegative`, and renders through `FormatWith` as the shortest decimal that reads back to exactly the same bits — found with exact big-integer arithmetic, which allocates. None of the four implements `Display` or `Debug`, and neither do the primitives they bridge: the protocols offer nowhere to pass an allocator, and implementing them anyway would mean a hidden allocation behind an ordinary `{}` and no way for a caller who has chosen an allocator to make this one follow. Where a rendering allocates, the caller says from where. [`ParseFloat80`](https://rux-lang.dev/docs/api/format/parse-float#parse-float80) through [`ParseFloat512`](https://rux-lang.dev/docs/api/format/parse-float#parse-float512) read decimal text to the nearest value with ties to even, and every rendering and reading is held to reference vectors the compiler's own exact float arithmetic produced independently. ### Example ```rux import Allocator::{ Allocator, SystemAllocator }; import Format::{ Render, WriteFormat }; import Text::{ BufferWriter, String, TextWriter }; func Main() -> int ! FormatError { // Into a destination the caller owns, allocating nothing. var storage: char8[64]; var buffer = BufferWriter((@storage[0])[..64]); let writer: &var TextWriter = buffer; WriteFormat(writer, "count={}", 42i64)?; // Or into a string of its own, which is the one place rendering allocates. var system = SystemAllocator(); let allocator: Allocator = system; return match Render(allocator, "pi={:.2}", 3.14159f64) { .Success(_) => 0, .Failure(_) => 1 }; } ``` Both answer with a native fallible: [`WriteFormat`](https://rux-lang.dev/docs/api/format/write-format) with `! FormatError` and [`Render`](https://rux-lang.dev/docs/api/format/render) with `String ! FormatError`. There is no status to forget to read — a result nobody handles is diagnosed as discarded — and no string handed back beside an error that says it is not really there. [`Render`](https://rux-lang.dev/docs/api/format/render) releases its partial text when it fails, so a caller never receives half a rendering and the allocator gets its block back either way. ## Index ### Types | Name | Summary | | ------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------ | | [`ByteCursor`](https://rux-lang.dev/docs/api/format/byte-cursor) | A fixed buffer being filled from the front. | | [`FixedNat`](https://rux-lang.dev/docs/api/format/fixed-nat) | An unsigned integer of fixed capacity, holding no storage of its own. | | [`FloatParts`](https://rux-lang.dev/docs/api/format/float-text#float-parts) | A finite float taken apart: the value is `significand * 2^exponent`. | | [`ParseError`](https://rux-lang.dev/docs/api/format/parse-error) | Why text could not be read as a value. | | [`DecimalReading`](https://rux-lang.dev/docs/api/format/parse-float#decimal-reading) | What a decimal spells, before any format decides what to do with it. | | [`FloatLayout`](https://rux-lang.dev/docs/api/format/float-layout) | The shape of one binary interchange format: where its fields are and what they mean. | | [`WideClass`](https://rux-lang.dev/docs/api/format/float-layout#wide-class) | What kind of value a bit pattern holds. | | [`UnpackedWide`](https://rux-lang.dev/docs/api/format/float-layout#unpacked-wide) | A finite value taken apart: `significand` times two to the `exponent`. | | [`Float80`](https://rux-lang.dev/docs/api/format/float80) | An x87 extended-precision value, held as its eighty bits. | | [`Float128`](https://rux-lang.dev/docs/api/format/float128) | An IEEE binary128 value, held as its bits. | | [`Float256`](https://rux-lang.dev/docs/api/format/float256) | An IEEE binary256 value, held as its bits. | | [`Float512`](https://rux-lang.dev/docs/api/format/float512) | An IEEE binary512 value, held as its bits. | ### Functions | Name | Summary | | ----------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | [`IsWideScalarValue`](https://rux-lang.dev/docs/api/format/character-text#is-wide-scalar-value) | Whether `value`, at whatever width it was read from, is a Unicode scalar value. | | [`WriteInvalidEscape`](https://rux-lang.dev/docs/api/format/character-text#write-invalid-escape) | Writes the escape for a value that is not a character, preserving exactly what it was. | | [`IsScalarValue512`](https://rux-lang.dev/docs/api/format/character-text#is-scalar-value-512) | Whether `value`, read from a character wider than sixty-four bits, is a Unicode scalar value. | | [`WriteWideInvalidEscape`](https://rux-lang.dev/docs/api/format/character-text#write-wide-invalid-escape) | Writes the escape for a value that is not a character, from a character wider than sixty-four bits. | | [`WriteWideCharacterDebug`](https://rux-lang.dev/docs/api/format/character-text#write-wide-character-debug) | Writes the `Debug` form of a character wider than sixty-four bits. | | [`WriteCharacterDebug`](https://rux-lang.dev/docs/api/format/character-text#write-character-debug) | Writes one character's `Debug` form: quoted, and preserved exactly when it is not a character. | | [`WriteEscapedScalar`](https://rux-lang.dev/docs/api/format/character-text#write-escaped-scalar) | Writes one scalar as it appears inside a quoted rendering, escaping what would otherwise be ambiguous. | | [`MeasurePadding`](https://rux-lang.dev/docs/api/format/character-text#measure-padding) | Reports how much fill a spec asks for on each side of a rendering `occupied` characters wide. | | [`WriteDecimal`](https://rux-lang.dev/docs/api/format/float-text#write-decimal) | Provides the public `WriteDecimal` operation. | | [`WriteUint`](https://rux-lang.dev/docs/api/format/integer-text#write-uint) | Writes the decimal digits of an unsigned value. | | [`WriteInt`](https://rux-lang.dev/docs/api/format/integer-text#write-int) | Writes the sign, then the magnitude. | | [`IsNan`](https://rux-lang.dev/docs/api/format/float-bits#is-nan) | Provides the public `IsNan` operation. | | [`IsInfinite`](https://rux-lang.dev/docs/api/format/float-bits#is-infinite) | Provides the public `IsInfinite` operation. | | [`IsFinite`](https://rux-lang.dev/docs/api/format/float-bits#is-finite) | Provides the public `IsFinite` operation. | | [`BitsOfFloat64`](https://rux-lang.dev/docs/api/format/float-bits#bits-of-float64) | The bits of `value`, as they are stored. | | [`BitsOfFloat32`](https://rux-lang.dev/docs/api/format/float-bits#bits-of-float32) | The bits of `value`, as they are stored. | | [`BitsOfFloat16`](https://rux-lang.dev/docs/api/format/float-bits#bits-of-float16) | The bits of `value`, as they are stored. | | [`BitsOfFloat8`](https://rux-lang.dev/docs/api/format/float-bits#bits-of-float8) | The bits of `value`, as they are stored. | | [`DecomposeFloat64`](https://rux-lang.dev/docs/api/format/float-text#decompose-float64) | Takes a `float64` apart into the significand and exponent its digits are generated from. | | [`DecomposeFloat32`](https://rux-lang.dev/docs/api/format/float-text#decompose-float32) | Takes a `float32` apart into the significand and exponent its digits are generated from. | | [`DecomposeFloat16`](https://rux-lang.dev/docs/api/format/float-text#decompose-float16) | Takes a `float16` apart into the significand and exponent its digits are generated from. | | [`DecomposeFloat8`](https://rux-lang.dev/docs/api/format/float-text#decompose-float8) | Takes a `float8` apart into the significand and exponent its digits are generated from. | | [`WriteShortestFloat`](https://rux-lang.dev/docs/api/format/float-text#write-shortest-float) | Writes the shortest decimal text of a finite, non-zero float taken apart by [`DecomposeFloat64`](https://rux-lang.dev/docs/api/format/float-text#decompose-float64) or its narrow counterpart, choosing fixed or scientific notation the way the rest of this package does. | | [`WriteFormat`](https://rux-lang.dev/docs/api/format/write-format) | Writes `format` into `writer`, with each `{}` replaced by the next argument. | | [`Render`](https://rux-lang.dev/docs/api/format/render) | The text `format` becomes with its placeholders filled, as a string of its own. | | [`WriteIntegerDigits`](https://rux-lang.dev/docs/api/format/integer-text#write-integer-digits) | Writes an integer whose digits are already produced, applying sign, prefix, zero-padding and alignment. | | [`WriteIntegerSpec`](https://rux-lang.dev/docs/api/format/integer-text#write-integer-spec) | Writes an integer under the whole of `spec`: base, sign, alternate prefix, zero-padding and alignment. | | [`FormatScalar`](https://rux-lang.dev/docs/api/format/character-text#format-scalar) | Writes one character under `spec`'s width, fill and alignment. | | [`Float64FromBits`](https://rux-lang.dev/docs/api/format/float-bits#float64-from-bits) | The `float64` whose bits are `bits`. | | [`Float32FromBits`](https://rux-lang.dev/docs/api/format/float-bits#float32-from-bits) | The `float32` whose bits are `bits`. | | [`ExactFloat64`](https://rux-lang.dev/docs/api/format/parse-float#exact-float64) | Reads the decimal `digits * 10^exponent` into the nearest `float64`, with ties to even. | | [`ExactFloat32`](https://rux-lang.dev/docs/api/format/parse-float#exact-float32) | Reads the decimal `digits * 10^exponent` into the nearest `float32`, with ties to even. | | [`ScanDecimal`](https://rux-lang.dev/docs/api/format/parse-float#scan-decimal) | Reads the decimal grammar out of `str`, without deciding what float it names. | | [`ParseFloat64`](https://rux-lang.dev/docs/api/format/parse-float#parse-float64) | Reads `str` as the `float64` nearest what it spells, rounding to nearest with ties to even. | | [`ParseFloat32`](https://rux-lang.dev/docs/api/format/parse-float#parse-float32) | Reads `str` as the `float32` nearest what it spells, rounding to nearest with ties to even. | | [`ParseUint8`](https://rux-lang.dev/docs/api/format/parse#parse-uint8) | Parses a `uint8`: an optional `+`, an optional base prefix, and digits. | | [`ParseInt8`](https://rux-lang.dev/docs/api/format/parse#parse-int8) | Parses an `int8`: an optional sign, an optional base prefix, and digits. | | [`ParseUint16`](https://rux-lang.dev/docs/api/format/parse#parse-uint16) | Parses a `uint16`: an optional `+`, an optional base prefix, and digits. | | [`ParseInt16`](https://rux-lang.dev/docs/api/format/parse#parse-int16) | Parses an `int16`: an optional sign, an optional base prefix, and digits. | | [`ParseUint32`](https://rux-lang.dev/docs/api/format/parse#parse-uint32) | Parses a `uint32`: an optional `+`, an optional base prefix, and digits. | | [`ParseInt32`](https://rux-lang.dev/docs/api/format/parse#parse-int32) | Parses an `int32`: an optional sign, an optional base prefix, and digits. | | [`ParseUint64`](https://rux-lang.dev/docs/api/format/parse#parse-uint64) | Parses a `uint64`: an optional `+`, an optional base prefix, and digits. | | [`ParseInt64`](https://rux-lang.dev/docs/api/format/parse#parse-int64) | Parses an `int64`: an optional sign, an optional base prefix, and digits. | | [`ParseUint128`](https://rux-lang.dev/docs/api/format/parse#parse-uint128) | Parses a `uint128`: an optional `+`, an optional base prefix, and digits. | | [`ParseInt128`](https://rux-lang.dev/docs/api/format/parse#parse-int128) | Parses an `int128`: an optional sign, an optional base prefix, and digits. | | [`ParseUint256`](https://rux-lang.dev/docs/api/format/parse#parse-uint256) | Parses a `uint256`: an optional `+`, an optional base prefix, and digits. | | [`ParseInt256`](https://rux-lang.dev/docs/api/format/parse#parse-int256) | Parses an `int256`: an optional sign, an optional base prefix, and digits. | | [`ParseUint512`](https://rux-lang.dev/docs/api/format/parse#parse-uint512) | Parses a `uint512`: an optional `+`, an optional base prefix, and digits. | | [`ParseInt512`](https://rux-lang.dev/docs/api/format/parse#parse-int512) | Parses an `int512`: an optional sign, an optional base prefix, and digits. | | [`ParseBool`](https://rux-lang.dev/docs/api/format/parse#parse-bool) | Parses `true` or `false`, exactly. | | [`ParseChar`](https://rux-lang.dev/docs/api/format/parse#parse-char) | Parses exactly one character. | | [`PrecisionDigits`](https://rux-lang.dev/docs/api/format/float-text#precision-digits) | Writes the digits of `significand * 2^exponent` down to the place `precision` names, rounded to nearest with ties to even. | | [`WritePrecisionFloat`](https://rux-lang.dev/docs/api/format/float-text#write-precision-float) | Writes a finite float in fixed notation with exactly `precision` digits after the decimal point. | | [`WritePrecision`](https://rux-lang.dev/docs/api/format/float-text#write-precision) | Renders `parts` under a specification that carries a precision, and applies the specification's sign, width, fill and alignment to the result. | | [`WriteScientificNotation`](https://rux-lang.dev/docs/api/format/float-text#write-scientific-notation) | Renders a finite float in scientific notation under `spec`, and applies the specification's sign, width, fill and alignment to the result. | | [`ShortestDigits`](https://rux-lang.dev/docs/api/format/float-text#shortest-digits) | Writes the shortest decimal digits of `significand * 2^exponent` that read back to exactly that value. | | [`UnpackWide`](https://rux-lang.dev/docs/api/format/float-layout#unpack-wide) | Takes a bit pattern apart under `layout`. | | [`PackWide`](https://rux-lang.dev/docs/api/format/float-layout#pack-wide) | Puts a finite value back together under `layout`, which must already be within range and precision. | | [`InfinityBits`](https://rux-lang.dev/docs/api/format/float-layout#infinity-bits) | The bits of infinity under `layout`. | | [`NanBits`](https://rux-lang.dev/docs/api/format/float-layout#nan-bits) | The bits of a quiet NaN under `layout`. | | [`ParseWideFloat`](https://rux-lang.dev/docs/api/format/parse-float#parse-wide-float) | Reads `str` as a value under `layout`, rounding to nearest with ties to even, and reports the bits. | | [`ParseFloat80`](https://rux-lang.dev/docs/api/format/parse-float#parse-float80) | Reads `str` as an x87 extended value. | | [`ParseFloat128`](https://rux-lang.dev/docs/api/format/parse-float#parse-float128) | Reads `str` as a binary128 value. | | [`ParseFloat256`](https://rux-lang.dev/docs/api/format/parse-float#parse-float256) | Reads `str` as a binary256 value. | | [`ParseFloat512`](https://rux-lang.dev/docs/api/format/parse-float#parse-float512) | Reads `str` as a binary512 value. | | [`WriteWideFloat`](https://rux-lang.dev/docs/api/format/float-layout#write-wide-float) | Writes `bits`, read under `layout`, as text under `spec`. | ### Constants | Name | Summary | | --------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------- | | [`ReplacementCharacter`](https://rux-lang.dev/docs/api/format/character-text#replacement-character) | The character written in place of anything that is not one. | | [`MaximumScalarValue`](https://rux-lang.dev/docs/api/format/character-text#maximum-scalar-value) | The largest value a Unicode scalar can have, past which nothing is a character. | | [`MaxDecimalDigits`](https://rux-lang.dev/docs/api/format/integer-text#max-decimal-digits) | The most digits a `uint64` ever needs, for 18446744073709551615. | | [`FixedNatLimbs`](https://rux-lang.dev/docs/api/format/fixed-nat#fixed-nat-limbs) | How many sixty-four-bit limbs a [`FixedNat`](https://rux-lang.dev/docs/api/format/fixed-nat) holds. | | [`FixedNatBits`](https://rux-lang.dev/docs/api/format/fixed-nat#fixed-nat-bits) | How many bits a [`FixedNat`](https://rux-lang.dev/docs/api/format/fixed-nat) holds in total. | | [`RetainedDecimalDigits`](https://rux-lang.dev/docs/api/format/parse-float#retained-decimal-digits) | How many significant digits a narrow float reader keeps before the rest becomes a sticky bit. | | [`MaximumPrecision`](https://rux-lang.dev/docs/api/format/float-text#maximum-precision) | The largest precision a narrow float renders at. | | [`MaximumFixedLength`](https://rux-lang.dev/docs/api/format/float-text#maximum-fixed-length) | The longest a fixed rendering can be: sign, integer digits, point and fraction. | | [`MaximumShortestDigits`](https://rux-lang.dev/docs/api/format/float-text#maximum-shortest-digits) | The most digits a shortest rendering can need. | # ByteCursor A fixed buffer being filled from the front. ```rux pub struct ByteCursor { // private fields } ``` ## Constructors ### `ByteCursor` ```rux pub func ByteCursor(room: var char8[..]) -> ByteCursor ``` A cursor over `room`, filling from its start. | Name | Type | Description | | ------ | --------------- | ------------------------------- | | `room` | `var char8[..]` | how many bytes the buffer holds | **Returns**: a cursor over that storage, having written nothing [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Format/Src/Cursor.rux#L30){rel=""nofollow""} ## Methods ### `Push` ```rux pub func Push(self: &var ByteCursor, byte: char8) ``` Appends one byte, or records an overrun when there is no room. | Name | Type | Description | | ------ | ------- | ----------- | | `byte` | `char8` | the byte | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Format/Src/Cursor.rux#L37){rel=""nofollow""} ### `PushBytes` ```rux pub func PushBytes(self: &var ByteCursor, bytes: char8[..]) ``` Appends every byte of `bytes`, or records an overrun when they do not all fit. | Name | Type | Description | | ------- | ----------- | ----------- | | `bytes` | `char8[..]` | the bytes | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Format/Src/Cursor.rux#L49){rel=""nofollow""} ### `Written` ```rux pub func Written(self: &ByteCursor) -> char8[..] ``` What has been written. **Returns**: the bytes written so far, borrowed [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Format/Src/Cursor.rux#L60){rel=""nofollow""} ### `Overran` ```rux pub func Overran(self: &ByteCursor) -> bool ``` Whether a write was refused for want of room. **Returns**: whether more was pushed than the buffer holds, which silently dropped the excess [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Format/Src/Cursor.rux#L67){rel=""nofollow""} ## Implements TextWriter `ByteCursor` conforms to `TextWriter`. ### `Write` ```rux pub func Write( self: &var ByteCursor, bytes: char8[..] ) -> ! FormatError ``` Writes `bytes` into the buffer. Reports `InsufficientCapacity` when the bytes do not all fit. The cursor is a bounded destination, so this is the failure it exists to report; a `WriterFailure` is impossible, since there is no destination beyond the buffer, and the bytes are not revalidated here, so no `TextFailure` arises either. Unlike a builder, a cursor that overruns keeps whatever fitted rather than leaving itself unchanged: the buffer is the caller's, the partial content is visible through [`Written`](https://rux-lang.dev/docs/api/format/byte-cursor#written), and [`Overran`](https://rux-lang.dev/docs/api/format/byte-cursor#overran) says it is partial. | Name | Type | Description | | ------- | ----------- | ---------------------- | | `bytes` | `char8[..]` | the UTF-8 run to write | **Returns**: success when every byte fitted [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Format/Src/Cursor.rux#L82){rel=""nofollow""} # FixedNat An unsigned integer of fixed capacity, holding no storage of its own. ```rux pub struct FixedNat { // private fields } ``` `Copy`, and 520 bytes wide, so it is passed by reference rather than by value everywhere in this package. The limbs are least significant first and `length` counts the ones in use, so zero is `length == 0` and there are never leading zero limbs above it — every operation restores that before it returns. ## Constructors ### `FixedNat` ```rux pub func FixedNat() -> FixedNat ``` Zero. Cannot fail; runs in constant time and allocates nothing. **Returns**: the value zero [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Format/Src/FixedNat.rux#L103){rel=""nofollow""} ## Associated functions ### `FromUint64` ```rux pub func FromUint64(initial: uint64) -> FixedNat ``` The value `initial`. Cannot fail: one limb always fits. Runs in constant time and allocates nothing. | Name | Type | Description | | --------- | -------- | ----------------- | | `initial` | `uint64` | the value to hold | **Returns**: a [`FixedNat`](https://rux-lang.dev/docs/api/format/fixed-nat) equal to `initial` [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Format/Src/FixedNat.rux#L112){rel=""nofollow""} ## Methods ### `IsZero` ```rux pub func IsZero(self: &FixedNat) -> bool ``` Whether this is zero. Borrows the value. Cannot fail; runs in constant time and allocates nothing. **Returns**: true when no limb is in use [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Format/Src/FixedNat.rux#L125){rel=""nofollow""} ### `BitLength` ```rux pub func BitLength(self: &FixedNat) -> uint ``` How many bits the value occupies, counting from its highest set bit. Zero has no bits. Borrows the value; runs in time proportional to one limb and allocates nothing. **Returns**: the position one past the highest set bit [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Format/Src/FixedNat.rux#L133){rel=""nofollow""} ### `Compare` ```rux pub func Compare(self: &FixedNat, other: &FixedNat) -> int32 ``` How this value orders against `other`. Borrows both. Cannot fail; runs in time proportional to the length and allocates nothing. | Name | Type | Description | | ------- | ----------- | ---------------------------- | | `other` | `&FixedNat` | the value to compare against | **Returns**: -1 when this is smaller, 0 when they are equal, and 1 when this is larger [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Format/Src/FixedNat.rux#L150){rel=""nofollow""} ### `Assign` ```rux pub func Assign(self: &var FixedNat, other: &FixedNat) ``` Replaces this value with `other`. Cannot fail: both have the same capacity. Runs in time proportional to the capacity and allocates nothing. | Name | Type | Description | | ------- | ----------- | ----------------- | | `other` | `&FixedNat` | the value to copy | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Format/Src/FixedNat.rux#L166){rel=""nofollow""} ### `MultiplyAddSmall` ```rux pub func MultiplyAddSmall( self: &var FixedNat, factor: uint64, addend: uint64 ) -> bool ``` Multiplies by `factor` and adds `addend`, in one pass over the limbs. The pair is one operation because that is how a digit is absorbed while reading a number, and doing it in two passes would double the work for no gain. Answers false when the product needs more limbs than the capacity holds, leaving the value exactly as it was — a caller that sees this has passed the bound Docs/NarrowFloat.md proves is not reached. | Name | Type | Description | | -------- | -------- | ---------------------- | | `factor` | `uint64` | what to multiply by | | `addend` | `uint64` | what to add afterwards | **Returns**: true when the result fits [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Format/Src/FixedNat.rux#L184){rel=""nofollow""} ### `MultiplySmall` ```rux pub func MultiplySmall( self: &var FixedNat, factor: uint64 ) -> bool ``` Multiplies by `factor`. Answers false when the product does not fit, leaving the value as it was. | Name | Type | Description | | -------- | -------- | ------------------- | | `factor` | `uint64` | what to multiply by | **Returns**: true when the result fits [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Format/Src/FixedNat.rux#L202){rel=""nofollow""} ### `AddSmall` ```rux pub func AddSmall( self: &var FixedNat, addend: uint64 ) -> bool ``` Adds `addend`. Answers false when the sum does not fit, leaving the value as it was. | Name | Type | Description | | -------- | -------- | ----------- | | `addend` | `uint64` | what to add | **Returns**: true when the result fits [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Format/Src/FixedNat.rux#L211){rel=""nofollow""} ### `ShiftLeft` ```rux pub func ShiftLeft(self: &var FixedNat, bits: uint) -> bool ``` Shifts left by `bits`, which multiplies by two to that power. Answers false when the result needs more limbs than the capacity holds, leaving the value as it was: the width a shift needs is known before any of it happens. | Name | Type | Description | | ------ | ------ | ---------------- | | `bits` | `uint` | how far to shift | **Returns**: true when the result fits [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Format/Src/FixedNat.rux#L221){rel=""nofollow""} ### `Add` ```rux pub func Add(self: &var FixedNat, other: &FixedNat) -> bool ``` Adds `other`. Answers false when the sum needs more limbs than the capacity holds, leaving the value as it was. | Name | Type | Description | | ------- | ----------- | ----------- | | `other` | `&FixedNat` | what to add | **Returns**: true when the result fits [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Format/Src/FixedNat.rux#L258){rel=""nofollow""} ### `Subtract` ```rux pub func Subtract(self: &var FixedNat, other: &FixedNat) ``` Subtracts `other`, which must not be larger than this value. The caller establishes `other <= self` first, by [`Compare`](https://rux-lang.dev/docs/api/format/fixed-nat#compare) or by construction. Subtracting a larger value has no answer in an unsigned type, and this borrows past the top rather than reporting it. | Name | Type | Description | | ------- | ----------- | ---------------- | | `other` | `&FixedNat` | what to subtract | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Format/Src/FixedNat.rux#L275){rel=""nofollow""} ### `MultiplyPowerOfTen` ```rux pub func MultiplyPowerOfTen( self: &var FixedNat, power: uint ) -> bool ``` Multiplies by ten to the `power`. Done as one pass per limb-sized chunk of the power rather than one per digit: ten to the nineteenth is the largest power of ten a `uint64` holds, so a power of three hundred and twenty-four costs seventeen passes instead of three hundred and twenty-four. Answers false when the result does not fit. A power applied in chunks stops at the chunk that does not fit, so the value is left part-scaled rather than untouched — the one place in this file where that is so, and it is reached only past a bound that is proved not to be. | Name | Type | Description | | ------- | ------ | --------------------- | | `power` | `uint` | the exponent to apply | **Returns**: true when the result fits [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Format/Src/FixedNat.rux#L305){rel=""nofollow""} ### `SetPowerOfTwo` ```rux pub func SetPowerOfTwo( self: &var FixedNat, bits: uint ) -> bool ``` Replaces this value with two to the `bits`. Answers false when `bits` is past the capacity, leaving the value as it was. | Name | Type | Description | | ------ | ------ | --------------------- | | `bits` | `uint` | the exponent to apply | **Returns**: true when the result fits [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Format/Src/FixedNat.rux#L326){rel=""nofollow""} ### `Low64` ```rux pub func Low64(self: &FixedNat) -> uint64 ``` The value's low sixty-four bits. Useful where a caller has already established the value is small, such as a quotient digit. Borrows the value; cannot fail, runs in constant time and allocates nothing. **Returns**: the least significant limb, or zero [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Format/Src/FixedNat.rux#L343){rel=""nofollow""} ## Related ### `FixedNatLimbs` ```rux pub const FixedNatLimbs: uint = 64; ``` How many sixty-four-bit limbs a [`FixedNat`](https://rux-lang.dev/docs/api/format/fixed-nat) holds. Sixty-four, which is 4,096 bits: the 3,681 the narrow conversion reaches at worst, and 415 bits of headroom over it. See Docs/NarrowFloat.md for where the 3,681 comes from. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Format/Src/FixedNat.rux#L28){rel=""nofollow""} ### `FixedNatBits` ```rux pub const FixedNatBits: uint = 4096; ``` How many bits a [`FixedNat`](https://rux-lang.dev/docs/api/format/fixed-nat) holds in total. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Format/Src/FixedNat.rux#L32){rel=""nofollow""} # FloatLayout The shape of one binary interchange format: where its fields are and what they mean. ```rux pub struct FloatLayout { pub precision: uint; // private fields } ``` ## Fields | Name | Type | Description | | ----------- | ------ | -------------------------------------------------------------------------------- | | `precision` | `uint` | The significand precision, counting the leading bit whether or not it is stored. | ## Associated functions ### `Extended80` ```rux pub func Extended80() -> FloatLayout ``` The x87 extended format: sixty-four significand bits with the integer bit written out, in eighty bits. **Returns**: the layout of x87's 80-bit extended format [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Format/Src/WideFloat.rux#L32){rel=""nofollow""} ### `Binary128` ```rux pub func Binary128() -> FloatLayout ``` IEEE binary128: a hundred and thirteen bits of precision. **Returns**: the layout of IEEE 754 binary128 [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Format/Src/WideFloat.rux#L39){rel=""nofollow""} ### `Binary256` ```rux pub func Binary256() -> FloatLayout ``` IEEE binary256: two hundred and thirty-seven bits of precision. **Returns**: the layout of IEEE 754 binary256 [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Format/Src/WideFloat.rux#L46){rel=""nofollow""} ### `Binary512` ```rux pub func Binary512() -> FloatLayout ``` IEEE binary512: four hundred and eighty-nine bits of precision. **Returns**: the layout of IEEE 754 binary512 [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Format/Src/WideFloat.rux#L53){rel=""nofollow""} ## Methods ### `SignificandFieldBits` ```rux pub func SignificandFieldBits(self: &FloatLayout) -> uint ``` How many bits the stored significand field has: the precision, less the leading bit unless it is written. **Returns**: how many bits the stored significand field occupies [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Format/Src/WideFloat.rux#L60){rel=""nofollow""} ### `MinimumExponent` ```rux pub func MinimumExponent(self: &FloatLayout) -> int ``` The smallest exponent a normal value has, as the power of two its integer significand is scaled by. **Returns**: the smallest exponent a normal value can have [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Format/Src/WideFloat.rux#L67){rel=""nofollow""} ### `MaximumExponent` ```rux pub func MaximumExponent(self: &FloatLayout) -> int ``` The largest exponent a finite value has, on the same scale. **Returns**: the largest exponent a finite value can have [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Format/Src/WideFloat.rux#L74){rel=""nofollow""} ### `DecimalDigits` ```rux pub func DecimalDigits(self: &FloatLayout) -> uint ``` How many decimal digits the shortest exact rendering can need: one more than the precision is worth. **Returns**: how many decimal digits round-trip through this format [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Format/Src/WideFloat.rux#L81){rel=""nofollow""} ## Related ### `WideClass` ```rux pub enum WideClass: int32 { Zero = 0, Subnormal = 1, Normal = 2, Infinity = 3, NaN = 4 } ``` What kind of value a bit pattern holds. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Format/Src/WideFloat.rux#L88){rel=""nofollow""} **Cases** | Name | Value | Description | | ----------- | ----- | --------------------------------------------------------------------------------- | | `Zero` | `0` | Zero of either sign. | | `Subnormal` | `1` | A value below the normal range, with no leading bit. | | `Normal` | `2` | An ordinary finite value. | | `Infinity` | `3` | Infinity of either sign. | | `NaN` | `4` | Not a number, including the unnormal and pseudo encodings of the extended format. | ### `UnpackedWide` ```rux pub struct UnpackedWide { pub class: WideClass; // private fields } ``` A finite value taken apart: `significand` times two to the `exponent`. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Format/Src/WideFloat.rux#L103){rel=""nofollow""} **Fields** | Name | Type | Description | | ------- | ----------- | ----------------------------------- | | `class` | `WideClass` | Which kind of value this came from. | ### `UnpackWide` ```rux pub func UnpackWide( bits: uint512, layout: &FloatLayout ) -> UnpackedWide ``` Takes a bit pattern apart under `layout`. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Format/Src/WideFloat.rux#L119){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | -------------- | ------------------------------------------------ | | `bits` | `uint512` | the value's bit pattern | | `layout` | `&FloatLayout` | which wide floating-point format the bits are in | **Returns**: the sign, significand and exponent those bits hold ### `PackWide` ```rux pub func PackWide( negative: bool, significand: uint512, exponent: int, layout: &FloatLayout ) -> uint512 ``` Puts a finite value back together under `layout`, which must already be within range and precision. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Format/Src/WideFloat.rux#L175){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------------- | -------------- | ------------------------------------------------ | | `negative` | `bool` | whether the value is negative | | `significand` | `uint512` | the significand | | `exponent` | `int` | the binary exponent | | `layout` | `&FloatLayout` | which wide floating-point format the bits are in | **Returns**: the bit pattern for that sign, significand and exponent ### `InfinityBits` ```rux pub func InfinityBits( negative: bool, layout: &FloatLayout ) -> uint512 ``` The bits of infinity under `layout`. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Format/Src/WideFloat.rux#L197){rel=""nofollow""} **Parameters** | Name | Type | Description | | ---------- | -------------- | ------------------------------------------------ | | `negative` | `bool` | whether the value is negative | | `layout` | `&FloatLayout` | which wide floating-point format the bits are in | **Returns**: the bit pattern for an infinity of that sign ### `NanBits` ```rux pub func NanBits(layout: &FloatLayout) -> uint512 ``` The bits of a quiet NaN under `layout`. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Format/Src/WideFloat.rux#L213){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | -------------- | ------------------------------------------------ | | `layout` | `&FloatLayout` | which wide floating-point format the bits are in | **Returns**: the bit pattern for a quiet NaN ### `WriteWideFloat` ```rux pub func WriteWideFloat( allocator: Allocator, writer: &var TextWriter, spec: FormatSpec, bits: uint512, layout: &FloatLayout ) -> ! FormatError ``` Writes `bits`, read under `layout`, as text under `spec`. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Format/Src/WideFloatText.rux#L30){rel=""nofollow""} **Parameters** | Name | Type | Description | | ----------- | ----------------- | ------------------------------------------------ | | `allocator` | `Allocator` | where the working storage comes from | | `writer` | `&var TextWriter` | the destination | | `spec` | `FormatSpec` | what the placeholder asked for | | `bits` | `uint512` | the value's bit pattern | | `layout` | `&FloatLayout` | which wide floating-point format the bits are in | **Returns**: success when the whole rendering was accepted # Float128 An IEEE binary128 value, held as its bits. ```rux pub struct Float128 { // private fields } ``` ## Associated functions ### `FromBits` ```rux pub func FromBits(bits: uint128) -> Float128 ``` The value these bits encode. | Name | Type | Description | | ------ | --------- | ----------------------- | | `bits` | `uint128` | the value's bit pattern | **Returns**: the value that bit pattern stands for [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Format/Src/WideFloatValue.rux#L140){rel=""nofollow""} ### `FromValue` ```rux pub func FromValue(value: float128) -> Float128 ``` The value a `float128` holds, carried as its bits. Reads the primitive's storage through a raw pointer, as [`BitsOfFloat64`](https://rux-lang.dev/docs/api/format/float-bits#bits-of-float64) does: a cast would ask for the number, and what is wanted is its representation. | Name | Type | Description | | ------- | ---------- | --------------------- | | `value` | `float128` | the primitive to read | **Returns**: the value with that primitive's bit pattern [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Format/Src/WideFloatValue.rux#L150){rel=""nofollow""} ### `Layout` ```rux pub func Layout() -> FloatLayout ``` The format these bits are read under. **Returns**: which format the bits are in [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Format/Src/WideFloatValue.rux#L176){rel=""nofollow""} ## Methods ### `Value` ```rux pub func Value(self: &Float128) -> float128 ``` The `float128` these bits encode, for arithmetic on a value that was read or built here. Writes the bits into the primitive's storage through a raw pointer. **Returns**: the primitive with this value's bit pattern [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Format/Src/WideFloatValue.rux#L159){rel=""nofollow""} ### `Bits` ```rux pub func Bits(self: &Float128) -> uint128 ``` The bits. **Returns**: the value's bit pattern [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Format/Src/WideFloatValue.rux#L169){rel=""nofollow""} ### `IsNan` ```rux pub func IsNan(self: &Float128) -> bool ``` Whether this is not a number. **Returns**: whether the value is a NaN [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Format/Src/WideFloatValue.rux#L188){rel=""nofollow""} ### `IsInfinite` ```rux pub func IsInfinite(self: &Float128) -> bool ``` Whether this is an infinity of either sign. **Returns**: whether the value is either infinity [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Format/Src/WideFloatValue.rux#L195){rel=""nofollow""} ### `IsFinite` ```rux pub func IsFinite(self: &Float128) -> bool ``` Whether this is an ordinary value: neither a NaN nor an infinity. **Returns**: whether the value is neither infinite nor a NaN [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Format/Src/WideFloatValue.rux#L202){rel=""nofollow""} ### `IsNegative` ```rux pub func IsNegative(self: &Float128) -> bool ``` Whether the sign bit is set, which a negative zero answers yes to. **Returns**: whether the sign bit is set [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Format/Src/WideFloatValue.rux#L210){rel=""nofollow""} ### `FormatWith` ```rux pub func FormatWith( self: &Float128, allocator: Allocator, writer: &var TextWriter, spec: FormatSpec ) -> ! FormatError ``` Writes this value's text under `spec`, taking the working storage from `allocator`. The shortest decimal that reads back as the same bits, or the digits a precision asks for. This is the only way to render one of these: they implement neither `Display` nor `Debug`, because the exact arithmetic their text needs allocates and those protocols offer nowhere to say from where. Reports whatever the writer reported, `UnsupportedRequest` for any style, and `TextFailure(OutOfMemory)` where `allocator` could not supply the working storage. | Name | Type | Description | | ----------- | ----------------- | ------------------------------------ | | `allocator` | `Allocator` | where the working storage comes from | | `writer` | `&var TextWriter` | the destination | | `spec` | `FormatSpec` | what the placeholder asked for | **Returns**: success when the complete rendering was accepted [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Format/Src/WideFloatValue.rux#L226){rel=""nofollow""} # Float256 An IEEE binary256 value, held as its bits. ```rux pub struct Float256 { // private fields } ``` ## Associated functions ### `FromBits` ```rux pub func FromBits(bits: uint256) -> Float256 ``` The value these bits encode. | Name | Type | Description | | ------ | --------- | ----------------------- | | `bits` | `uint256` | the value's bit pattern | **Returns**: the value that bit pattern stands for [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Format/Src/WideFloatValue.rux#L246){rel=""nofollow""} ### `FromValue` ```rux pub func FromValue(value: float256) -> Float256 ``` The value a `float256` holds, carried as its bits. Reads the primitive's storage through a raw pointer, as [`BitsOfFloat64`](https://rux-lang.dev/docs/api/format/float-bits#bits-of-float64) does: a cast would ask for the number, and what is wanted is its representation. | Name | Type | Description | | ------- | ---------- | --------------------- | | `value` | `float256` | the primitive to read | **Returns**: the value with that primitive's bit pattern [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Format/Src/WideFloatValue.rux#L256){rel=""nofollow""} ### `Layout` ```rux pub func Layout() -> FloatLayout ``` The format these bits are read under. **Returns**: which format the bits are in [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Format/Src/WideFloatValue.rux#L282){rel=""nofollow""} ## Methods ### `Value` ```rux pub func Value(self: &Float256) -> float256 ``` The `float256` these bits encode, for arithmetic on a value that was read or built here. Writes the bits into the primitive's storage through a raw pointer. **Returns**: the primitive with this value's bit pattern [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Format/Src/WideFloatValue.rux#L265){rel=""nofollow""} ### `Bits` ```rux pub func Bits(self: &Float256) -> uint256 ``` The bits. **Returns**: the value's bit pattern [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Format/Src/WideFloatValue.rux#L275){rel=""nofollow""} ### `IsNan` ```rux pub func IsNan(self: &Float256) -> bool ``` Whether this is not a number. **Returns**: whether the value is a NaN [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Format/Src/WideFloatValue.rux#L294){rel=""nofollow""} ### `IsInfinite` ```rux pub func IsInfinite(self: &Float256) -> bool ``` Whether this is an infinity of either sign. **Returns**: whether the value is either infinity [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Format/Src/WideFloatValue.rux#L301){rel=""nofollow""} ### `IsFinite` ```rux pub func IsFinite(self: &Float256) -> bool ``` Whether this is an ordinary value: neither a NaN nor an infinity. **Returns**: whether the value is neither infinite nor a NaN [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Format/Src/WideFloatValue.rux#L308){rel=""nofollow""} ### `IsNegative` ```rux pub func IsNegative(self: &Float256) -> bool ``` Whether the sign bit is set, which a negative zero answers yes to. **Returns**: whether the sign bit is set [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Format/Src/WideFloatValue.rux#L316){rel=""nofollow""} ### `FormatWith` ```rux pub func FormatWith( self: &Float256, allocator: Allocator, writer: &var TextWriter, spec: FormatSpec ) -> ! FormatError ``` Writes this value's text under `spec`, taking the working storage from `allocator`. The shortest decimal that reads back as the same bits, or the digits a precision asks for. This is the only way to render one of these: they implement neither `Display` nor `Debug`, because the exact arithmetic their text needs allocates and those protocols offer nowhere to say from where. Reports whatever the writer reported, `UnsupportedRequest` for any style, and `TextFailure(OutOfMemory)` where `allocator` could not supply the working storage. | Name | Type | Description | | ----------- | ----------------- | ------------------------------------ | | `allocator` | `Allocator` | where the working storage comes from | | `writer` | `&var TextWriter` | the destination | | `spec` | `FormatSpec` | what the placeholder asked for | **Returns**: success when the complete rendering was accepted [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Format/Src/WideFloatValue.rux#L332){rel=""nofollow""} # Float512 An IEEE binary512 value, held as its bits. ```rux pub struct Float512 { // private fields } ``` ## Associated functions ### `FromBits` ```rux pub func FromBits(bits: uint512) -> Float512 ``` The value these bits encode. | Name | Type | Description | | ------ | --------- | ----------------------- | | `bits` | `uint512` | the value's bit pattern | **Returns**: the value that bit pattern stands for [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Format/Src/WideFloatValue.rux#L352){rel=""nofollow""} ### `FromValue` ```rux pub func FromValue(value: float512) -> Float512 ``` The value a `float512` holds, carried as its bits. Reads the primitive's storage through a raw pointer, as [`BitsOfFloat64`](https://rux-lang.dev/docs/api/format/float-bits#bits-of-float64) does: a cast would ask for the number, and what is wanted is its representation. | Name | Type | Description | | ------- | ---------- | --------------------- | | `value` | `float512` | the primitive to read | **Returns**: the value with that primitive's bit pattern [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Format/Src/WideFloatValue.rux#L362){rel=""nofollow""} ### `Layout` ```rux pub func Layout() -> FloatLayout ``` The format these bits are read under. **Returns**: which format the bits are in [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Format/Src/WideFloatValue.rux#L388){rel=""nofollow""} ## Methods ### `Value` ```rux pub func Value(self: &Float512) -> float512 ``` The `float512` these bits encode, for arithmetic on a value that was read or built here. Writes the bits into the primitive's storage through a raw pointer. **Returns**: the primitive with this value's bit pattern [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Format/Src/WideFloatValue.rux#L371){rel=""nofollow""} ### `Bits` ```rux pub func Bits(self: &Float512) -> uint512 ``` The bits. **Returns**: the value's bit pattern [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Format/Src/WideFloatValue.rux#L381){rel=""nofollow""} ### `IsNan` ```rux pub func IsNan(self: &Float512) -> bool ``` Whether this is not a number. **Returns**: whether the value is a NaN [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Format/Src/WideFloatValue.rux#L400){rel=""nofollow""} ### `IsInfinite` ```rux pub func IsInfinite(self: &Float512) -> bool ``` Whether this is an infinity of either sign. **Returns**: whether the value is either infinity [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Format/Src/WideFloatValue.rux#L407){rel=""nofollow""} ### `IsFinite` ```rux pub func IsFinite(self: &Float512) -> bool ``` Whether this is an ordinary value: neither a NaN nor an infinity. **Returns**: whether the value is neither infinite nor a NaN [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Format/Src/WideFloatValue.rux#L414){rel=""nofollow""} ### `IsNegative` ```rux pub func IsNegative(self: &Float512) -> bool ``` Whether the sign bit is set, which a negative zero answers yes to. **Returns**: whether the sign bit is set [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Format/Src/WideFloatValue.rux#L422){rel=""nofollow""} ### `FormatWith` ```rux pub func FormatWith( self: &Float512, allocator: Allocator, writer: &var TextWriter, spec: FormatSpec ) -> ! FormatError ``` Writes this value's text under `spec`, taking the working storage from `allocator`. The shortest decimal that reads back as the same bits, or the digits a precision asks for. This is the only way to render one of these: they implement neither `Display` nor `Debug`, because the exact arithmetic their text needs allocates and those protocols offer nowhere to say from where. Reports whatever the writer reported, `UnsupportedRequest` for any style, and `TextFailure(OutOfMemory)` where `allocator` could not supply the working storage. | Name | Type | Description | | ----------- | ----------------- | ------------------------------------ | | `allocator` | `Allocator` | where the working storage comes from | | `writer` | `&var TextWriter` | the destination | | `spec` | `FormatSpec` | what the placeholder asked for | **Returns**: success when the complete rendering was accepted [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Format/Src/WideFloatValue.rux#L438){rel=""nofollow""} # Float80 An x87 extended-precision value, held as its eighty bits. ```rux pub struct Float80 { // private fields } ``` ## Associated functions ### `FromBits` ```rux pub func FromBits(bits: uint128) -> Float80 ``` The value these bits encode. | Name | Type | Description | | ------ | --------- | ----------------------- | | `bits` | `uint128` | the value's bit pattern | **Returns**: the value that bit pattern stands for [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Format/Src/WideFloatValue.rux#L33){rel=""nofollow""} ### `FromValue` ```rux pub func FromValue(value: float80) -> Float80 ``` The value a `float80` holds, carried as its eighty bits. Reads the primitive's storage through a raw pointer, as [`BitsOfFloat64`](https://rux-lang.dev/docs/api/format/float-bits#bits-of-float64) does, and keeps the low eighty bits: the storage is sixteen bytes, and the six above the value are padding whose contents nothing promises. | Name | Type | Description | | ------- | --------- | --------------------- | | `value` | `float80` | the primitive to read | **Returns**: the value with that primitive's bit pattern [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Format/Src/WideFloatValue.rux#L43){rel=""nofollow""} ### `Layout` ```rux pub func Layout() -> FloatLayout ``` The format these bits are read under. **Returns**: which format the bits are in [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Format/Src/WideFloatValue.rux#L70){rel=""nofollow""} ## Methods ### `Value` ```rux pub func Value(self: &Float80) -> float80 ``` The `float80` these bits encode, for arithmetic on a value that was read or built here. Writes the low eighty bits into the primitive's storage through a raw pointer, with the padding above them zero. **Returns**: the primitive with this value's bit pattern [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Format/Src/WideFloatValue.rux#L53){rel=""nofollow""} ### `Bits` ```rux pub func Bits(self: &Float80) -> uint128 ``` The bits. **Returns**: the value's bit pattern [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Format/Src/WideFloatValue.rux#L63){rel=""nofollow""} ### `IsNan` ```rux pub func IsNan(self: &Float80) -> bool ``` Whether this is not a number. **Returns**: whether the value is a NaN [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Format/Src/WideFloatValue.rux#L82){rel=""nofollow""} ### `IsInfinite` ```rux pub func IsInfinite(self: &Float80) -> bool ``` Whether this is an infinity of either sign. **Returns**: whether the value is either infinity [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Format/Src/WideFloatValue.rux#L89){rel=""nofollow""} ### `IsFinite` ```rux pub func IsFinite(self: &Float80) -> bool ``` Whether this is an ordinary value: neither a NaN nor an infinity. **Returns**: whether the value is neither infinite nor a NaN [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Format/Src/WideFloatValue.rux#L96){rel=""nofollow""} ### `IsNegative` ```rux pub func IsNegative(self: &Float80) -> bool ``` Whether the sign bit is set, which a negative zero answers yes to. **Returns**: whether the sign bit is set [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Format/Src/WideFloatValue.rux#L104){rel=""nofollow""} ### `FormatWith` ```rux pub func FormatWith( self: &Float80, allocator: Allocator, writer: &var TextWriter, spec: FormatSpec ) -> ! FormatError ``` Writes this value's text under `spec`, taking the working storage from `allocator`. The shortest decimal that reads back as the same bits, or the digits a precision asks for. This is the only way to render one of these: they implement neither `Display` nor `Debug`, because the exact arithmetic their text needs allocates and those protocols offer nowhere to say from where. Reports whatever the writer reported, `UnsupportedRequest` for any style, and `TextFailure(OutOfMemory)` where `allocator` could not supply the working storage. | Name | Type | Description | | ----------- | ----------------- | ------------------------------------ | | `allocator` | `Allocator` | where the working storage comes from | | `writer` | `&var TextWriter` | the destination | | `spec` | `FormatSpec` | what the placeholder asked for | **Returns**: success when the complete rendering was accepted [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Format/Src/WideFloatValue.rux#L120){rel=""nofollow""} # ParseError Why text could not be read as a value. ```rux pub variant ParseError { Empty, InvalidCharacter(uint), Overflow(uint), OutOfMemory(uint) } ``` Failure-only: every case is a failure, and each says where in the text it was found. Success is the other channel of the `T ! ParseError` a parser returns rather than a case here. Copy, carrying one offset. ## Cases | Name | Description | | ------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `Empty` | There were no bytes to read. The offset is zero, which is both the start of the text and its length. | | `InvalidCharacter(uint)` | A byte that is not part of the grammar, or a well-formed value with something after it. The offset is that byte, which is the text's length when the value stopped short. | | `Overflow(uint)` | The value is well formed and does not fit the width asked for. The offset is the digit that passed the widest representable magnitude, or the end of the number when the number itself is what does not fit. | | `OutOfMemory(uint)` | The exact arithmetic a wide float needs could not get the storage for it. This is the machine rather than the text: the same input on a less busy machine reads fine, which is what tells it apart from `Overflow`. The offset is where the parser had reached, which is the end of the number. | ## Implements ParseFailure `ParseError` conforms to `ParseFailure`. ### `Offset` ```rux pub func Offset(self: &ParseError) -> uint ``` Where in the input the failure was found. Borrows the error and leaves it untouched. Cannot fail; runs in constant time and allocates nothing. **Returns**: the zero-based UTF-8 byte offset, which is the text's length at end of input [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Format/Src/ParseFloat64.rux#L42){rel=""nofollow""} # Writing characters and booleans How characters, character slices and booleans render, and how a value that is no character is escaped. ## `ReplacementCharacter` ```rux pub const ReplacementCharacter: char32 = 0xFFFDu32 as char32; ``` The character written in place of anything that is not one. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Format/Src/Char8.rux#L12){rel=""nofollow""} ## `MaximumScalarValue` ```rux pub const MaximumScalarValue: uint64 = 0x10FFFF; ``` The largest value a Unicode scalar can have, past which nothing is a character. Named because a `char64` has room for a great deal more than this, and the check that it does not hold one has to happen at the full width: narrowing first would turn `0x100000041` into `A`. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Format/Src/CharacterText.rux#L25){rel=""nofollow""} ## `IsWideScalarValue` ```rux pub func IsWideScalarValue(value: uint64) -> bool ``` Whether `value`, at whatever width it was read from, is a Unicode scalar value. Takes a `uint64` so that a `char64` is checked before it is narrowed rather than after. A value past the last scalar and a value in the surrogate range are both refused, which is the same rule `Text::IsScalarValue` applies at thirty-two bits. Cannot fail; runs in constant time and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Format/Src/CharacterText.rux#L35){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------- | -------- | -------------------------------------------------- | | `value` | `uint64` | the numeric value of a character, at its own width | **Returns**: true when a character of that value exists ## `WriteInvalidEscape` ```rux pub func WriteInvalidEscape( writer: &var TextWriter, value: uint64 ) -> ! FormatError ``` Writes the escape for a value that is not a character, preserving exactly what it was. A value that fits a byte is written `\x{nn}`, because a stray byte is not a scalar and should not be shown as one; anything else is written `\u{...}` with as many digits as its width needs, in fours. No valid character can collide with either: the escapes are only ever written for values that are not characters. Reports whatever the writer reported, stopping at the first refusal. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Format/Src/CharacterText.rux#L60){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | ----------------- | -------------------------- | | `writer` | `&var TextWriter` | the destination | | `value` | `uint64` | the numeric value to spell | **Returns**: success when the whole escape was accepted ## `IsScalarValue512` ```rux pub func IsScalarValue512(value: uint512) -> bool ``` Whether `value`, read from a character wider than sixty-four bits, is a Unicode scalar value. The counterpart of [`IsWideScalarValue`](https://rux-lang.dev/docs/api/format/character-text#is-wide-scalar-value) for `char128`, `char256` and `char512`, which widen into a `uint512` to be checked. Any bit above the sixty-fourth makes the value no character at all, and the check sees it because nothing is narrowed until the value is known to be at most U+10FFFF. Cannot fail; runs in constant time and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Format/Src/CharacterText.rux#L82){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------- | --------- | -------------------------------------------------- | | `value` | `uint512` | the numeric value of a character, at its own width | **Returns**: true when a character of that value exists ## `WriteWideInvalidEscape` ```rux pub func WriteWideInvalidEscape( writer: &var TextWriter, value: uint512 ) -> ! FormatError ``` Writes the escape for a value that is not a character, from a character wider than sixty-four bits. A value that fits sixty-four bits is spelled exactly as [`WriteInvalidEscape`](https://rux-lang.dev/docs/api/format/character-text#write-invalid-escape) spells it, so a `char128` and a `char64` holding the same number render alike. A wider value keeps going in the same doubling steps: 32 hex digits past sixty-four bits, 64 past 128 and 128 past 256, so every bit the value holds is shown. The digits are written one at a time from the value itself, and nothing is allocated. Reports whatever the writer reported, stopping at the first refusal. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Format/Src/CharacterText.rux#L97){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | ----------------- | -------------------------- | | `writer` | `&var TextWriter` | the destination | | `value` | `uint512` | the numeric value to spell | **Returns**: success when the whole escape was accepted ## `WriteWideCharacterDebug` ```rux pub func WriteWideCharacterDebug( writer: &var TextWriter, value: uint512 ) -> ! FormatError ``` Writes the `Debug` form of a character wider than sixty-four bits. A value that fits sixty-four bits is written exactly as a `char64` of the same number would be, quoted, and a wider one as its full escape, so no two values of any character width share a rendering they should not. Reports whatever the writer reported, stopping at the first refusal. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Format/Src/CharacterText.rux#L120){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | ----------------- | ---------------------------------------------------- | | `writer` | `&var TextWriter` | the destination | | `value` | `uint512` | the numeric value of the character, at its own width | **Returns**: success when the whole rendering was accepted ## `WriteCharacterDebug` ```rux pub func WriteCharacterDebug( writer: &var TextWriter, value: uint64, whole: bool ) -> ! FormatError ``` Writes one character's `Debug` form: quoted, and preserved exactly when it is not a character. `whole` is the caller's own answer to whether the value is a whole character, because the widths disagree about it. A `char8` of 0xC3 is a valid scalar value as a number and a piece of a character as a byte, and it is the byte's answer that governs: `Display` writes U+FFFD for it, so `Debug` must preserve the byte rather than write the character that number happens to name. Reports whatever the writer reported, stopping at the first refusal. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Format/Src/CharacterText.rux#L141){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | ----------------- | ----------------------------------------------------------------- | | `writer` | `&var TextWriter` | the destination | | `value` | `uint64` | the numeric value of the character, at its own width | | `whole` | `bool` | whether the width this value came from calls it a whole character | **Returns**: success when the whole rendering was accepted ## `WriteEscapedScalar` ```rux pub func WriteEscapedScalar( writer: &var TextWriter, scalar: uint32 ) -> ! FormatError ``` Writes one scalar as it appears inside a quoted rendering, escaping what would otherwise be ambiguous. The quote, the backslash and the control characters get the escapes `Rux/Text` gives them everywhere else, so a quoted character reads the same here as inside a quoted string. Reports whatever the writer reported, and `TextFailure(InvalidUtf8)` for a value that is not a scalar, which a caller checks before calling. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Format/Src/CharacterText.rux#L161){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | ----------------- | --------------------------------- | | `writer` | `&var TextWriter` | the destination | | `scalar` | `uint32` | the Unicode scalar value to write | **Returns**: success when the whole character was accepted ## `MeasurePadding` ```rux pub func MeasurePadding( spec: FormatSpec, occupied: uint, before: *var uint, after: *var uint ) ``` Reports how much fill a spec asks for on each side of a rendering `occupied` characters wide. A character slice cannot hand its rendering to `WriteAligned`, because the bytes do not exist until they are transcoded and transcoding into a buffer would bound how long a slice may be. So the width is measured in one pass over the units and the fill is written around the transcoding instead. Both counts are zero when the rendering already fills the width, which is the common case and costs nothing. Cannot fail; runs in constant time and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Format/Src/CharacterText.rux#L186){rel=""nofollow""} **Parameters** | Name | Type | Description | | ---------- | ------------ | --------------------------------------------- | | `spec` | `FormatSpec` | what the placeholder asked for | | `occupied` | `uint` | how many characters the rendering will occupy | | `before` | `*var uint` | receives the fill to write first | | `after` | `*var uint` | receives the fill to write last | ## `FormatScalar` ```rux pub func FormatScalar( writer: &var TextWriter, spec: FormatSpec, scalar: char32 ) -> ! FormatError ``` Writes one character under `spec`'s width, fill and alignment. Reports `TextFailure(InvalidUtf8)` when `scalar` is not a Unicode scalar value, and otherwise whatever the writer reported. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Format/Src/IntegerText.rux#L116){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | ----------------- | ---------------------------------- | | `writer` | `&var TextWriter` | the destination | | `spec` | `FormatSpec` | what the placeholder asked for | | `scalar` | `char32` | the Unicode scalar value to render | **Returns**: success when the padded character was accepted # Float classification and bits Whether a float is NaN, infinite or finite, and the bits it is stored as. ## `IsNan` ```rux pub func IsNan(value: float16) -> bool pub func IsNan(value: float32) -> bool pub func IsNan(value: float64) -> bool pub func IsNan(value: float8) -> bool ``` Provides the public `IsNan` operation. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Format/Src/Float16.rux#L28){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------- | -------------------------------------------- | ------------------- | | `value` | `float16` / `float32` / `float64` / `float8` | the value to act on | **Returns**: whether the value is a NaN ## `IsInfinite` ```rux pub func IsInfinite(value: float16) -> bool pub func IsInfinite(value: float32) -> bool pub func IsInfinite(value: float64) -> bool pub func IsInfinite(value: float8) -> bool ``` Provides the public `IsInfinite` operation. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Format/Src/Float16.rux#L37){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------- | -------------------------------------------- | ------------------- | | `value` | `float16` / `float32` / `float64` / `float8` | the value to act on | **Returns**: whether the value is either infinity ## `IsFinite` ```rux pub func IsFinite(value: float16) -> bool pub func IsFinite(value: float32) -> bool pub func IsFinite(value: float64) -> bool pub func IsFinite(value: float8) -> bool ``` Provides the public `IsFinite` operation. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Format/Src/Float16.rux#L47){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------- | -------------------------------------------- | ------------------- | | `value` | `float16` / `float32` / `float64` / `float8` | the value to act on | **Returns**: whether the value is neither infinite nor a NaN ## `BitsOfFloat64` ```rux pub func BitsOfFloat64(value: float64) -> uint64 ``` The bits of `value`, as they are stored. Reads the value's storage as an integer of the same width through a raw pointer. This is the representation rather than the value: there is no conversion that preserves the bits, since a cast asks for the number. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Format/Src/FloatDigits.rux#L34){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------- | --------- | ----------------- | | `value` | `float64` | the float to read | **Returns**: its sixty-four bits ## `BitsOfFloat32` ```rux pub func BitsOfFloat32(value: float32) -> uint32 ``` The bits of `value`, as they are stored. As [`BitsOfFloat64`](https://rux-lang.dev/docs/api/format/float-bits#bits-of-float64), at the narrower width. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Format/Src/FloatDigits.rux#L44){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------- | --------- | ----------------- | | `value` | `float32` | the float to read | **Returns**: its thirty-two bits ## `BitsOfFloat16` ```rux pub func BitsOfFloat16(value: float16) -> uint16 ``` The bits of `value`, as they are stored. As [`BitsOfFloat64`](https://rux-lang.dev/docs/api/format/float-bits#bits-of-float64), at the half-precision width. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Format/Src/FloatDigits.rux#L54){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------- | --------- | ----------------- | | `value` | `float16` | the float to read | **Returns**: its sixteen bits ## `BitsOfFloat8` ```rux pub func BitsOfFloat8(value: float8) -> uint8 ``` The bits of `value`, as they are stored. As [`BitsOfFloat64`](https://rux-lang.dev/docs/api/format/float-bits#bits-of-float64), at the eight-bit width: a sign, four exponent bits and three stored significand bits. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Format/Src/FloatDigits.rux#L64){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------- | -------- | ----------------- | | `value` | `float8` | the float to read | **Returns**: its eight bits ## `Float64FromBits` ```rux pub func Float64FromBits(bits: uint64) -> float64 ``` The `float64` whose bits are `bits`. Writes the value's storage from an integer of the same width through a raw pointer, which is the inverse of [`BitsOfFloat64`](https://rux-lang.dev/docs/api/format/float-bits#bits-of-float64) and unsafe for the same reason: there is no conversion that preserves a representation. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Format/Src/NarrowParse.rux#L251){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------ | -------- | -------------------------------------- | | `bits` | `uint64` | the sixty-four bits to read as a value | **Returns**: the value they spell ## `Float32FromBits` ```rux pub func Float32FromBits(bits: uint32) -> float32 ``` The `float32` whose bits are `bits`. As [`Float64FromBits`](https://rux-lang.dev/docs/api/format/float-bits#float64-from-bits), at the narrower width. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Format/Src/NarrowParse.rux#L261){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------ | -------- | -------------------------------------- | | `bits` | `uint32` | the thirty-two bits to read as a value | **Returns**: the value they spell # Writing floats The shortest, fixed-precision and scientific renderings of a float32 or float64. ## `WriteDecimal` ```rux pub func WriteDecimal( cursor: &var ByteCursor, value: float64, significant: uint ) ``` Provides the public `WriteDecimal` operation. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Format/Src/Decimal.rux#L14){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------------- | ----------------- | -------------------------------------- | | `cursor` | `&var ByteCursor` | the buffer the digits are written into | | `value` | `float64` | the value to act on | | `significant` | `uint` | how many significant digits to write | ## `FloatParts` ```rux pub struct FloatParts { pub significand: uint64; pub exponent: int; pub atBinadeBottom: bool; pub negative: bool; } ``` A finite float taken apart: the value is `significand * 2^exponent`. Copy, carrying no reference to the value it came from. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Format/Src/FloatDigits.rux#L17){rel=""nofollow""} **Fields** | Name | Type | Description | | ---------------- | -------- | --------------------------------------------------------------------------------------------- | | `significand` | `uint64` | The integer significand, including the implicit bit for a normal value. Zero only for a zero. | | `exponent` | `int` | The power of two the significand is scaled by. | | `atBinadeBottom` | `bool` | Whether the lower neighbour is half as far away as the upper one. | | `negative` | `bool` | Whether the value is negative, including the negative zero. | ## `DecomposeFloat64` ```rux pub func DecomposeFloat64(value: float64) -> FloatParts ``` Takes a `float64` apart into the significand and exponent its digits are generated from. A NaN or an infinity has no decimal and is not this function's business; a caller establishes the value is finite first. A zero comes back with a zero significand, which the caller writes as `0` without generating anything. Cannot fail; runs in constant time and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Format/Src/FloatDigits.rux#L77){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------- | --------- | ------------------------------ | | `value` | `float64` | the finite float to take apart | **Returns**: its significand, exponent, binade position and sign ## `DecomposeFloat32` ```rux pub func DecomposeFloat32(value: float32) -> FloatParts ``` Takes a `float32` apart into the significand and exponent its digits are generated from. The same decomposition at the narrower width, so both widths reach one generator. Cannot fail; runs in constant time and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Format/Src/FloatDigits.rux#L103){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------- | --------- | ------------------------------ | | `value` | `float32` | the finite float to take apart | **Returns**: its significand, exponent, binade position and sign ## `DecomposeFloat16` ```rux pub func DecomposeFloat16(value: float16) -> FloatParts ``` Takes a `float16` apart into the significand and exponent its digits are generated from. IEEE 754 binary16: eleven bits of significand and an exponent biased by fifteen. The neighbours the generator measures against are this width's own, so the digits that come back are the shortest that read back as a `float16`, not as the `float32` or `float64` the value would widen to. Cannot fail; runs in constant time and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Format/Src/FloatDigits.rux#L127){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------- | --------- | ------------------------------ | | `value` | `float16` | the finite float to take apart | **Returns**: its significand, exponent, binade position and sign ## `DecomposeFloat8` ```rux pub func DecomposeFloat8(value: float8) -> FloatParts ``` Takes a `float8` apart into the significand and exponent its digits are generated from. The E4M3 layout with IEEE-style specials: four bits of significand, an exponent biased by seven, and the all-ones exponent kept for the infinities and NaNs, so the largest finite value is 240. As with the other widths, the neighbours are this width's own. Cannot fail; runs in constant time and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Format/Src/FloatDigits.rux#L150){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------- | -------- | ------------------------------ | | `value` | `float8` | the finite float to take apart | **Returns**: its significand, exponent, binade position and sign ## `WriteShortestFloat` ```rux pub func WriteShortestFloat( cursor: &var ByteCursor, parts: FloatParts, scientificFrom: int ) -> bool ``` Writes the shortest decimal text of a finite, non-zero float taken apart by [`DecomposeFloat64`](https://rux-lang.dev/docs/api/format/float-text#decompose-float64) or its narrow counterpart, choosing fixed or scientific notation the way the rest of this package does. The sign is written from `parts`, so a negative zero keeps its sign even though its digits are a bare zero. Answers false when the exact arithmetic could not run in the fixed workspace, which Docs/NarrowFloat.md proves the narrow widths do not reach. A caller that sees it has a defect in the bound rather than a value to handle. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Format/Src/FloatDigits.rux#L176){rel=""nofollow""} **Parameters** | Name | Type | Description | | ---------------- | ----------------- | ------------------------------------------------------------------ | | `cursor` | `&var ByteCursor` | the destination | | `parts` | `FloatParts` | the value taken apart | | `scientificFrom` | `int` | the decimal exponent at or above which scientific notation is used | **Returns**: true when the whole rendering was written ## `MaximumPrecision` ```rux pub const MaximumPrecision: uint = 1100; ``` The largest precision a narrow float renders at. Eleven hundred, which is exactly enough rather than round: the smallest `float64` subnormal is `2^-1074` and its exact decimal has 1,074 fractional digits, the largest finite value has 309 integer ones, and no `float64` has anything to say past that. A request beyond this is refused rather than clamped, because a caller asking for five thousand digits has miscalculated something and answering with 3,900 zeros would hide it. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Format/Src/PrecisionDigits.rux#L24){rel=""nofollow""} ## `MaximumFixedLength` ```rux pub const MaximumFixedLength: uint = 1424; ``` The longest a fixed rendering can be: sign, integer digits, point and fraction. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Format/Src/PrecisionDigits.rux#L28){rel=""nofollow""} ## `PrecisionDigits` ```rux pub func PrecisionDigits( significand: uint64, exponent: int, precision: uint, into: var char8[..], count: *var uint, power: *var int ) -> bool ``` Writes the digits of `significand * 2^exponent` down to the place `precision` names, rounded to nearest with ties to even. The digits are the significant ones with no point and no sign, and `power` receives the exponent that places them: the value is `0.d1d2...dn * 10^power`, so the last digit written stands for `10^-precision`. A value small enough that nothing reaches that place produces no digits and a power of zero, which the caller writes as a zero and a tail of zeros. Answers false when `precision` is past [`MaximumPrecision`](https://rux-lang.dev/docs/api/format/float-text#maximum-precision), when `into` is too short for the digits the value needs, or when the exact arithmetic could not run in the fixed workspace — which Docs/NarrowFloat.md proves the narrow widths do not reach. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Format/Src/PrecisionDigits.rux#L98){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------------- | --------------- | -------------------------------------------------- | | `significand` | `uint64` | the integer significand, which must not be zero | | `exponent` | `int` | the power of two it is scaled by | | `precision` | `uint` | how many digits after the decimal point are wanted | | `into` | `var char8[..]` | where the digits go | | `count` | `*var uint` | receives how many digits were written | | `power` | `*var int` | receives the power of ten that places them | **Returns**: true when the digits were produced ## `WritePrecisionFloat` ```rux pub func WritePrecisionFloat( cursor: &var ByteCursor, parts: FloatParts, precision: uint ) -> bool ``` Writes a finite float in fixed notation with exactly `precision` digits after the decimal point. Always fixed notation, because that is the only notation in which "digits after the decimal point" has one meaning. A large value therefore renders with every integer digit it has and then the fraction — which is what was asked for, and why the precision is bounded rather than the output. Answers false when the precision is past [`MaximumPrecision`](https://rux-lang.dev/docs/api/format/float-text#maximum-precision), or when the exact arithmetic could not run in the fixed workspace. There is no fallback to another rendering: a refused request is refused. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Format/Src/PrecisionDigits.rux#L183){rel=""nofollow""} **Parameters** | Name | Type | Description | | ----------- | ----------------- | --------------------------------------- | | `cursor` | `&var ByteCursor` | the destination | | `parts` | `FloatParts` | the value taken apart | | `precision` | `uint` | how many digits after the decimal point | **Returns**: true when the whole rendering was written ## `WritePrecision` ```rux pub func WritePrecision( writer: &var TextWriter, spec: FormatSpec, parts: FloatParts ) -> ! FormatError ``` Renders `parts` under a specification that carries a precision, and applies the specification's sign, width, fill and alignment to the result. The large fixed buffer a precision can need lives in this function rather than in the callers', so a placeholder with no precision never pays for it. Reports `UnsupportedRequest` for a precision past [`MaximumPrecision`](https://rux-lang.dev/docs/api/format/float-text#maximum-precision), and whatever the writer reported otherwise. There is no fallback: a refused precision produces no output. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Format/Src/PrecisionDigits.rux#L250){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | ----------------- | ---------------------------------------------------- | | `writer` | `&var TextWriter` | the destination | | `spec` | `FormatSpec` | what the placeholder asked for, carrying a precision | | `parts` | `FloatParts` | the value taken apart | **Returns**: success when the whole rendering was accepted ## `WriteScientificNotation` ```rux pub func WriteScientificNotation( writer: &var TextWriter, spec: FormatSpec, parts: FloatParts, mark: char8 ) -> ! FormatError ``` Renders a finite float in scientific notation under `spec`, and applies the specification's sign, width, fill and alignment to the result. One digit comes before the point and the rest after it, then `mark` and the decimal exponent with its sign and at least two digits: `1.2345e+05`. Without a precision the digits are the shortest that read back as the same value, with `.0` after a lone digit; with one, the precision counts the digits after the point, rounded to nearest with ties to even, and `.0` writes no point at all. A zero is `0.0e+00`, keeping the sign of a negative zero. Reports `UnsupportedRequest` for a precision past [`MaximumPrecision`](https://rux-lang.dev/docs/api/format/float-text#maximum-precision), and whatever the writer reported otherwise. There is no fallback: a refused precision produces no output. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Format/Src/Scientific.rux#L163){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | ----------------- | ------------------------------ | | `writer` | `&var TextWriter` | the destination | | `spec` | `FormatSpec` | what the placeholder asked for | | `parts` | `FloatParts` | the finite value taken apart | | `mark` | `char8` | the exponent mark, `e` or `E` | **Returns**: success when the whole rendering was accepted ## `MaximumShortestDigits` ```rux pub const MaximumShortestDigits: uint = 17; ``` The most digits a shortest rendering can need. Seventeen for a `float64` and nine for a `float32`: those are the counts at which every value of the width is distinguishable from every other, which is the theoretical bound on how long a shortest form can be. The buffer a caller supplies is checked against this rather than against a guess. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Format/Src/ShortestDigits.rux#L24){rel=""nofollow""} ## `ShortestDigits` ```rux pub func ShortestDigits( significand: uint64, exponent: int, atBinadeBottom: bool, into: var char8[..], count: *var uint, exponent10: *var int ) -> bool ``` Writes the shortest decimal digits of `significand * 2^exponent` that read back to exactly that value. The digits are the significant ones with no point and no sign: `into` receives them most significant first, `count` how many there are, and `exponent10` the power of ten the first of them stands for, so the value is `0.d1d2...dn * 10^(exponent10 + 1)` and the caller places the point. `atBinadeBottom` says the value is the smallest significand of its exponent, whose lower neighbour is half as far away as its upper one. A caller reading a `float64` passes true when the stored mantissa is zero and the biased exponent is above one. Answers false when `into` is shorter than [`MaximumShortestDigits`](https://rux-lang.dev/docs/api/format/float-text#maximum-shortest-digits), or when the workspace could not hold the arithmetic — which Docs/NarrowFloat.md proves the narrow widths do not reach, so a false from that cause is a defect in the bound rather than an input to handle. Nothing partial is reported: `count` is zero on failure. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Format/Src/ShortestDigits.rux#L144){rel=""nofollow""} **Parameters** | Name | Type | Description | | ---------------- | --------------- | ------------------------------------------------------------------------------------------------------------------------------------- | | `significand` | `uint64` | the integer significand, which must not be zero | | `exponent` | `int` | the power of two it is scaled by | | `atBinadeBottom` | `bool` | whether the lower gap is half the upper one | | `into` | `var char8[..]` | where the digits go, at least [`MaximumShortestDigits`](https://rux-lang.dev/docs/api/format/float-text#maximum-shortest-digits) long | | `count` | `*var uint` | receives how many digits were written | | `exponent10` | `*var int` | receives the power of ten the first digit stands for | **Returns**: true when the digits were produced # Writing integers Spelling an integer as text: sign, base prefix, zero padding and digits. ## `MaxDecimalDigits` ```rux pub const MaxDecimalDigits: uint = 20; ``` The most digits a `uint64` ever needs, for 18446744073709551615. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Format/Src/Digits.rux#L9){rel=""nofollow""} ## `WriteUint` ```rux pub func WriteUint(cursor: &var ByteCursor, value: uint64) ``` Writes the decimal digits of an unsigned value. A division loop produces them least significant first, so they land in a small buffer and go back reversed. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Format/Src/Digits.rux#L16){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | ----------------- | -------------------------------------- | | `cursor` | `&var ByteCursor` | the buffer the digits are written into | | `value` | `uint64` | the value to act on | ## `WriteInt` ```rux pub func WriteInt(cursor: &var ByteCursor, value: int64) ``` Writes the sign, then the magnitude. The magnitude is taken in `uint64` rather than by negating within `int64`, because the most negative `int64` has no positive counterpart there: negating it overflows straight back to itself. Two's complement gives the right answer for that value and for every other one. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Format/Src/Digits.rux#L45){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | ----------------- | -------------------------------------- | | `cursor` | `&var ByteCursor` | the buffer the digits are written into | | `value` | `int64` | the value to act on | ## `WriteIntegerDigits` ```rux pub func WriteIntegerDigits( writer: &var TextWriter, spec: FormatSpec, digits: char8[..], count: uint, negative: bool ) -> ! FormatError ``` Writes an integer whose digits are already produced, applying sign, prefix, zero-padding and alignment. `digits` holds the digits least significant first, which is the order a division loop makes them; `count` says how many. Zero-padding puts its zeros between the sign and the digits and wins over alignment when both are asked for. Nothing here allocates or copies the digits: each piece goes to the writer as it is reached. Reports whatever the writer reported, stopping at the first refusal. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Format/Src/IntegerText.rux#L24){rel=""nofollow""} **Parameters** | Name | Type | Description | | ---------- | ----------------- | ---------------------------------------------------- | | `writer` | `&var TextWriter` | the destination | | `spec` | `FormatSpec` | what the placeholder asked for | | `digits` | `char8[..]` | the decimal or based digits, least significant first | | `count` | `uint` | how many entries of `digits` are meaningful | | `negative` | `bool` | whether a minus sign precedes the digits | **Returns**: success when the complete rendering was accepted ## `WriteIntegerSpec` ```rux pub func WriteIntegerSpec( writer: &var TextWriter, spec: FormatSpec, magnitude: uint64, negative: bool ) -> ! FormatError ``` Writes an integer under the whole of `spec`: base, sign, alternate prefix, zero-padding and alignment. `magnitude` is the absolute value and `negative` its sign, kept apart because the most negative value of a signed width has no positive counterpart to negate into. Reports whatever the writer reported. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Format/Src/IntegerText.rux#L79){rel=""nofollow""} **Parameters** | Name | Type | Description | | ----------- | ----------------- | ------------------------------ | | `writer` | `&var TextWriter` | the destination | | `spec` | `FormatSpec` | what the placeholder asked for | | `magnitude` | `uint64` | the absolute value to render | | `negative` | `bool` | whether the value is negative | **Returns**: success when the complete rendering was accepted # Parsing integers, booleans and characters Reading an integer of any width and base, a boolean or one character from text. ## `ParseUint8` ```rux pub func ParseUint8(str: char8[..]) -> uint8 ! ParseError pub func ParseUint8(str: StringView) -> uint8 ! ParseError ``` Parses a `uint8`: an optional `+`, an optional base prefix, and digits. Reports `Overflow` for a value the width cannot hold, `InvalidCharacter` at the first byte that is not part of the grammar — a `-` included, since no unsigned value is negative. | Overload | Summary | | ------------------------------------------------------------ | ----------------------------------------------------------------------- | | `pub func ParseUint8(str: char8[..]) -> uint8 ! ParseError` | Parses a `uint8`: an optional `+`, an optional base prefix, and digits. | | `pub func ParseUint8(str: StringView) -> uint8 ! ParseError` | The same grammar for a view, which is what a caller holding text has. | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Format/Src/ParseInteger.rux#L80){rel=""nofollow""} **Parameters** | Name | Type | Description | | ----- | -------------------------- | ----------------- | | `str` | `char8[..]` / `StringView` | the text to parse | **Returns**: the value, or the failure and the byte offset it was found at ## `ParseInt8` ```rux pub func ParseInt8(str: char8[..]) -> int8 ! ParseError pub func ParseInt8(str: StringView) -> int8 ! ParseError ``` Parses an `int8`: an optional sign, an optional base prefix, and digits. The negative bound is one larger than the positive one, because the most negative value has no positive counterpart: the value one past the largest positive fits only with its sign. | Overload | Summary | | ---------------------------------------------------------- | ------------------------------------------------------------------------ | | `pub func ParseInt8(str: char8[..]) -> int8 ! ParseError` | Parses an `int8`: an optional sign, an optional base prefix, and digits. | | `pub func ParseInt8(str: StringView) -> int8 ! ParseError` | The same grammar for a view, which is what a caller holding text has. | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Format/Src/ParseInteger.rux#L95){rel=""nofollow""} **Parameters** | Name | Type | Description | | ----- | -------------------------- | ----------------- | | `str` | `char8[..]` / `StringView` | the text to parse | **Returns**: the value, or the failure and the byte offset it was found at ## `ParseUint16` ```rux pub func ParseUint16(str: char8[..]) -> uint16 ! ParseError pub func ParseUint16(str: StringView) -> uint16 ! ParseError ``` Parses a `uint16`: an optional `+`, an optional base prefix, and digits. Reports `Overflow` for a value the width cannot hold, `InvalidCharacter` at the first byte that is not part of the grammar — a `-` included, since no unsigned value is negative. | Overload | Summary | | -------------------------------------------------------------- | ------------------------------------------------------------------------ | | `pub func ParseUint16(str: char8[..]) -> uint16 ! ParseError` | Parses a `uint16`: an optional `+`, an optional base prefix, and digits. | | `pub func ParseUint16(str: StringView) -> uint16 ! ParseError` | The same grammar for a view, which is what a caller holding text has. | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Format/Src/ParseInteger.rux#L111){rel=""nofollow""} **Parameters** | Name | Type | Description | | ----- | -------------------------- | ----------------- | | `str` | `char8[..]` / `StringView` | the text to parse | **Returns**: the value, or the failure and the byte offset it was found at ## `ParseInt16` ```rux pub func ParseInt16(str: char8[..]) -> int16 ! ParseError pub func ParseInt16(str: StringView) -> int16 ! ParseError ``` Parses an `int16`: an optional sign, an optional base prefix, and digits. The negative bound is one larger than the positive one, because the most negative value has no positive counterpart: the value one past the largest positive fits only with its sign. | Overload | Summary | | ------------------------------------------------------------ | ------------------------------------------------------------------------- | | `pub func ParseInt16(str: char8[..]) -> int16 ! ParseError` | Parses an `int16`: an optional sign, an optional base prefix, and digits. | | `pub func ParseInt16(str: StringView) -> int16 ! ParseError` | The same grammar for a view, which is what a caller holding text has. | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Format/Src/ParseInteger.rux#L126){rel=""nofollow""} **Parameters** | Name | Type | Description | | ----- | -------------------------- | ----------------- | | `str` | `char8[..]` / `StringView` | the text to parse | **Returns**: the value, or the failure and the byte offset it was found at ## `ParseUint32` ```rux pub func ParseUint32(str: char8[..]) -> uint32 ! ParseError pub func ParseUint32(str: StringView) -> uint32 ! ParseError ``` Parses a `uint32`: an optional `+`, an optional base prefix, and digits. Reports `Overflow` for a value the width cannot hold, `InvalidCharacter` at the first byte that is not part of the grammar — a `-` included, since no unsigned value is negative. | Overload | Summary | | -------------------------------------------------------------- | ------------------------------------------------------------------------ | | `pub func ParseUint32(str: char8[..]) -> uint32 ! ParseError` | Parses a `uint32`: an optional `+`, an optional base prefix, and digits. | | `pub func ParseUint32(str: StringView) -> uint32 ! ParseError` | The same grammar for a view, which is what a caller holding text has. | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Format/Src/ParseInteger.rux#L142){rel=""nofollow""} **Parameters** | Name | Type | Description | | ----- | -------------------------- | ----------------- | | `str` | `char8[..]` / `StringView` | the text to parse | **Returns**: the value, or the failure and the byte offset it was found at ## `ParseInt32` ```rux pub func ParseInt32(str: char8[..]) -> int32 ! ParseError pub func ParseInt32(str: StringView) -> int32 ! ParseError ``` Parses an `int32`: an optional sign, an optional base prefix, and digits. The negative bound is one larger than the positive one, because the most negative value has no positive counterpart: the value one past the largest positive fits only with its sign. | Overload | Summary | | ------------------------------------------------------------ | ------------------------------------------------------------------------- | | `pub func ParseInt32(str: char8[..]) -> int32 ! ParseError` | Parses an `int32`: an optional sign, an optional base prefix, and digits. | | `pub func ParseInt32(str: StringView) -> int32 ! ParseError` | The same grammar for a view, which is what a caller holding text has. | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Format/Src/ParseInteger.rux#L157){rel=""nofollow""} **Parameters** | Name | Type | Description | | ----- | -------------------------- | ----------------- | | `str` | `char8[..]` / `StringView` | the text to parse | **Returns**: the value, or the failure and the byte offset it was found at ## `ParseUint64` ```rux pub func ParseUint64(str: char8[..]) -> uint64 ! ParseError pub func ParseUint64(str: StringView) -> uint64 ! ParseError ``` Parses a `uint64`: an optional `+`, an optional base prefix, and digits. Reports `Overflow` for a value the width cannot hold, `InvalidCharacter` at the first byte that is not part of the grammar — a `-` included, since no unsigned value is negative. | Overload | Summary | | -------------------------------------------------------------- | ------------------------------------------------------------------------ | | `pub func ParseUint64(str: char8[..]) -> uint64 ! ParseError` | Parses a `uint64`: an optional `+`, an optional base prefix, and digits. | | `pub func ParseUint64(str: StringView) -> uint64 ! ParseError` | The same grammar for a view, which is what a caller holding text has. | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Format/Src/ParseInteger.rux#L173){rel=""nofollow""} **Parameters** | Name | Type | Description | | ----- | -------------------------- | ----------------- | | `str` | `char8[..]` / `StringView` | the text to parse | **Returns**: the value, or the failure and the byte offset it was found at ## `ParseInt64` ```rux pub func ParseInt64(str: char8[..]) -> int64 ! ParseError pub func ParseInt64(str: StringView) -> int64 ! ParseError ``` Parses an `int64`: an optional sign, an optional base prefix, and digits. The negative bound is one larger than the positive one, because the most negative value has no positive counterpart: the value one past the largest positive fits only with its sign. | Overload | Summary | | ------------------------------------------------------------ | ------------------------------------------------------------------------- | | `pub func ParseInt64(str: char8[..]) -> int64 ! ParseError` | Parses an `int64`: an optional sign, an optional base prefix, and digits. | | `pub func ParseInt64(str: StringView) -> int64 ! ParseError` | The same grammar for a view, which is what a caller holding text has. | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Format/Src/ParseInteger.rux#L190){rel=""nofollow""} **Parameters** | Name | Type | Description | | ----- | -------------------------- | ----------------- | | `str` | `char8[..]` / `StringView` | the text to parse | **Returns**: the value, or the failure and the byte offset it was found at ## `ParseUint128` ```rux pub func ParseUint128(str: char8[..]) -> uint128 ! ParseError pub func ParseUint128(str: StringView) -> uint128 ! ParseError ``` Parses a `uint128`: an optional `+`, an optional base prefix, and digits. Reports `Overflow` for a value the width cannot hold, `InvalidCharacter` at the first byte that is not part of the grammar — a `-` included, since no unsigned value is negative. | Overload | Summary | | ---------------------------------------------------------------- | ------------------------------------------------------------------------- | | `pub func ParseUint128(str: char8[..]) -> uint128 ! ParseError` | Parses a `uint128`: an optional `+`, an optional base prefix, and digits. | | `pub func ParseUint128(str: StringView) -> uint128 ! ParseError` | The same grammar for a view, which is what a caller holding text has. | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Format/Src/ParseInteger.rux#L206){rel=""nofollow""} **Parameters** | Name | Type | Description | | ----- | -------------------------- | ----------------- | | `str` | `char8[..]` / `StringView` | the text to parse | **Returns**: the value, or the failure and the byte offset it was found at ## `ParseInt128` ```rux pub func ParseInt128(str: char8[..]) -> int128 ! ParseError pub func ParseInt128(str: StringView) -> int128 ! ParseError ``` Parses an `int128`: an optional sign, an optional base prefix, and digits. The negative bound is one larger than the positive one, because the most negative value has no positive counterpart: the value one past the largest positive fits only with its sign. | Overload | Summary | | -------------------------------------------------------------- | -------------------------------------------------------------------------- | | `pub func ParseInt128(str: char8[..]) -> int128 ! ParseError` | Parses an `int128`: an optional sign, an optional base prefix, and digits. | | `pub func ParseInt128(str: StringView) -> int128 ! ParseError` | The same grammar for a view, which is what a caller holding text has. | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Format/Src/ParseInteger.rux#L223){rel=""nofollow""} **Parameters** | Name | Type | Description | | ----- | -------------------------- | ----------------- | | `str` | `char8[..]` / `StringView` | the text to parse | **Returns**: the value, or the failure and the byte offset it was found at ## `ParseUint256` ```rux pub func ParseUint256(str: char8[..]) -> uint256 ! ParseError pub func ParseUint256(str: StringView) -> uint256 ! ParseError ``` Parses a `uint256`: an optional `+`, an optional base prefix, and digits. Reports `Overflow` for a value the width cannot hold, `InvalidCharacter` at the first byte that is not part of the grammar — a `-` included, since no unsigned value is negative. | Overload | Summary | | ---------------------------------------------------------------- | ------------------------------------------------------------------------- | | `pub func ParseUint256(str: char8[..]) -> uint256 ! ParseError` | Parses a `uint256`: an optional `+`, an optional base prefix, and digits. | | `pub func ParseUint256(str: StringView) -> uint256 ! ParseError` | The same grammar for a view, which is what a caller holding text has. | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Format/Src/ParseInteger.rux#L239){rel=""nofollow""} **Parameters** | Name | Type | Description | | ----- | -------------------------- | ----------------- | | `str` | `char8[..]` / `StringView` | the text to parse | **Returns**: the value, or the failure and the byte offset it was found at ## `ParseInt256` ```rux pub func ParseInt256(str: char8[..]) -> int256 ! ParseError pub func ParseInt256(str: StringView) -> int256 ! ParseError ``` Parses an `int256`: an optional sign, an optional base prefix, and digits. The negative bound is one larger than the positive one, because the most negative value has no positive counterpart: the value one past the largest positive fits only with its sign. | Overload | Summary | | -------------------------------------------------------------- | -------------------------------------------------------------------------- | | `pub func ParseInt256(str: char8[..]) -> int256 ! ParseError` | Parses an `int256`: an optional sign, an optional base prefix, and digits. | | `pub func ParseInt256(str: StringView) -> int256 ! ParseError` | The same grammar for a view, which is what a caller holding text has. | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Format/Src/ParseInteger.rux#L256){rel=""nofollow""} **Parameters** | Name | Type | Description | | ----- | -------------------------- | ----------------- | | `str` | `char8[..]` / `StringView` | the text to parse | **Returns**: the value, or the failure and the byte offset it was found at ## `ParseUint512` ```rux pub func ParseUint512(str: char8[..]) -> uint512 ! ParseError pub func ParseUint512(str: StringView) -> uint512 ! ParseError ``` Parses a `uint512`: an optional `+`, an optional base prefix, and digits. Reports `Overflow` for a value the width cannot hold, `InvalidCharacter` at the first byte that is not part of the grammar — a `-` included, since no unsigned value is negative. | Overload | Summary | | ---------------------------------------------------------------- | ------------------------------------------------------------------------- | | `pub func ParseUint512(str: char8[..]) -> uint512 ! ParseError` | Parses a `uint512`: an optional `+`, an optional base prefix, and digits. | | `pub func ParseUint512(str: StringView) -> uint512 ! ParseError` | The same grammar for a view, which is what a caller holding text has. | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Format/Src/ParseInteger.rux#L272){rel=""nofollow""} **Parameters** | Name | Type | Description | | ----- | -------------------------- | ----------------- | | `str` | `char8[..]` / `StringView` | the text to parse | **Returns**: the value, or the failure and the byte offset it was found at ## `ParseInt512` ```rux pub func ParseInt512(str: char8[..]) -> int512 ! ParseError pub func ParseInt512(str: StringView) -> int512 ! ParseError ``` Parses an `int512`: an optional sign, an optional base prefix, and digits. The negative bound is one larger than the positive one, because the most negative value has no positive counterpart: the value one past the largest positive fits only with its sign. | Overload | Summary | | -------------------------------------------------------------- | -------------------------------------------------------------------------- | | `pub func ParseInt512(str: char8[..]) -> int512 ! ParseError` | Parses an `int512`: an optional sign, an optional base prefix, and digits. | | `pub func ParseInt512(str: StringView) -> int512 ! ParseError` | The same grammar for a view, which is what a caller holding text has. | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Format/Src/ParseInteger.rux#L289){rel=""nofollow""} **Parameters** | Name | Type | Description | | ----- | -------------------------- | ----------------- | | `str` | `char8[..]` / `StringView` | the text to parse | **Returns**: the value, or the failure and the byte offset it was found at ## `ParseBool` ```rux pub func ParseBool(str: char8[..]) -> bool ! ParseError pub func ParseBool(str: StringView) -> bool ! ParseError ``` Parses `true` or `false`, exactly. Reports `Empty` for no bytes and `InvalidCharacter` at the start for anything else, including a correct word with trailing bytes. | Overload | Summary | | ---------------------------------------------------------- | ---------------------------------- | | `pub func ParseBool(str: char8[..]) -> bool ! ParseError` | Parses `true` or `false`, exactly. | | `pub func ParseBool(str: StringView) -> bool ! ParseError` | The same words for a view. | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Format/Src/ParseValue.rux#L16){rel=""nofollow""} **Parameters** | Name | Type | Description | | ----- | -------------------------- | ----------------- | | `str` | `char8[..]` / `StringView` | the text to parse | **Returns**: the value, or the failure and the byte offset it was found at ## `ParseChar` ```rux pub func ParseChar(str: char8[..]) -> char32 ! ParseError pub func ParseChar(str: StringView) -> char32 ! ParseError ``` Parses exactly one character. Reports `Empty` for no bytes, and `InvalidCharacter` for bytes that are not one whole scalar value — ill-formed UTF-8 at zero, a second character at its own index. | Overload | Summary | | ------------------------------------------------------------ | ------------------------------------- | | `pub func ParseChar(str: char8[..]) -> char32 ! ParseError` | Parses exactly one character. | | `pub func ParseChar(str: StringView) -> char32 ! ParseError` | The same single character for a view. | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Format/Src/ParseValue.rux#L40){rel=""nofollow""} **Parameters** | Name | Type | Description | | ----- | -------------------------- | ----------------- | | `str` | `char8[..]` / `StringView` | the text to parse | **Returns**: the value, or the failure and the byte offset it was found at # Parsing floats Reading decimal text into the nearest float32, float64 or wide float, exactly. ## `RetainedDecimalDigits` ```rux pub const RetainedDecimalDigits: uint = 768; ``` How many significant digits a narrow float reader keeps before the rest becomes a sticky bit. Seven hundred and sixty-eight, which is the longest exact decimal expansion any midpoint between two adjacent `float64` values has. Keeping that many means a tie is detected exactly, and a nonzero digit beyond them means the value cannot be a tie at all — so the bound is where the two arguments meet rather than a round number. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Format/Src/NarrowParse.rux#L24){rel=""nofollow""} ## `ExactFloat64` ```rux pub func ExactFloat64( digits: &FixedNat, exponent: int, truncated: bool, negative: bool, value: *var float64, overflowed: *var bool ) -> bool ``` Reads the decimal `digits * 10^exponent` into the nearest `float64`, with ties to even. Answers false for a value past the format's range or a workspace failure, with `overflowed` saying which. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Format/Src/NarrowParse.rux#L276){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------------ | -------------- | ----------------------------------------------------------- | | `digits` | `&FixedNat` | the retained significant digits | | `exponent` | `int` | the power of ten they are scaled by | | `truncated` | `bool` | whether a nonzero digit was dropped past the retained bound | | `negative` | `bool` | whether the value is negative | | `value` | `*var float64` | receives the float | | `overflowed` | `*var bool` | receives whether the failure was the value being too large | **Returns**: true when the value was read ## `ExactFloat32` ```rux pub func ExactFloat32( digits: &FixedNat, exponent: int, truncated: bool, negative: bool, value: *var float32, overflowed: *var bool ) -> bool ``` Reads the decimal `digits * 10^exponent` into the nearest `float32`, with ties to even. Read at this width's own precision rather than at a `float64`'s and narrowed: narrowing rounds a second time, and a value that lands on a `float32` boundary can round the wrong way when it has already been rounded to fifty-three bits on the way. Answers false for a value past the format's range or a workspace failure, with `overflowed` saying which. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Format/Src/NarrowParse.rux#L300){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------------ | -------------- | ----------------------------------------------------------- | | `digits` | `&FixedNat` | the retained significant digits | | `exponent` | `int` | the power of ten they are scaled by | | `truncated` | `bool` | whether a nonzero digit was dropped past the retained bound | | `negative` | `bool` | whether the value is negative | | `value` | `*var float32` | receives the float | | `overflowed` | `*var bool` | receives whether the failure was the value being too large | **Returns**: true when the value was read ## `DecimalReading` ```rux pub struct DecimalReading { pub digits: FixedNat; pub exponent: int; pub significant: uint; pub truncated: bool; pub negative: bool; pub special: int; } ``` What a decimal spells, before any format decides what to do with it. Copy, holding the retained digits and the two flags the rounding needs. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Format/Src/ParseFloat64.rux#L55){rel=""nofollow""} **Fields** | Name | Type | Description | | ------------- | ---------- | ------------------------------------------------------------------------------------------------------ | | `digits` | `FixedNat` | The retained significant digits, as an integer. | | `exponent` | `int` | The power of ten they are scaled by, counting the decimal point and any digits dropped past the bound. | | `significant` | `uint` | How many significant digits were retained. | | `truncated` | `bool` | Whether a nonzero digit was dropped past the retained bound. | | `negative` | `bool` | Whether the value is negative, including a negative zero. | | `special` | `int` | Zero for an ordinary number, one for `NaN`, two for an infinity. | ## `ScanDecimal` ```rux pub func ScanDecimal( str: char8[..], reading: *var DecimalReading ) -> ! ParseError ``` Reads the decimal grammar out of `str`, without deciding what float it names. One scanner for both narrow widths, so what one reads the other reads: the grammar is `[+-]?(digits[.digits?]?|.digits)([eE][+-]?digits)?`, plus the two special spellings `NaN` and `Inf` exactly as formatting writes them. The digits are kept exactly up to [`RetainedDecimalDigits`](https://rux-lang.dev/docs/api/format/parse-float#retained-decimal-digits), past which a nonzero one sets `truncated` and moves the exponent instead. Reports `Empty` for no bytes, `InvalidCharacter` at the byte where the shape stopped matching, and `OutOfMemory` where the retained digits would not fit the workspace. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Format/Src/ParseFloat64.rux#L81){rel=""nofollow""} **Parameters** | Name | Type | Description | | --------- | --------------------- | -------------------------------- | | `str` | `char8[..]` | the text to read | | `reading` | `*var DecimalReading` | receives what the decimal spells | **Returns**: success when the whole text was the grammar ## `ParseFloat64` ```rux pub func ParseFloat64(str: char8[..]) -> float64 ! ParseError pub func ParseFloat64(str: StringView) -> float64 ! ParseError ``` Reads `str` as the `float64` nearest what it spells, rounding to nearest with ties to even. Exact: the value is formed as a ratio of integers and the quotient is taken with a sticky bit, so what comes back is the nearest `float64` and never one step off it. `NaN`, `Inf` and `-Inf` are read exactly as formatting writes them. Reports `Empty`, `InvalidCharacter` and `OutOfMemory` as [`ScanDecimal`](https://rux-lang.dev/docs/api/format/parse-float#scan-decimal) does, and `Overflow` at the text's length for a value past the largest finite `float64` — refused rather than rounded to an infinity, since that would turn a number the caller wrote into one they did not. A value below the smallest subnormal is the signed zero it rounds to. | Overload | Summary | | ---------------------------------------------------------------- | ------------------------------------------------------------------------------------------- | | `pub func ParseFloat64(str: char8[..]) -> float64 ! ParseError` | Reads `str` as the `float64` nearest what it spells, rounding to nearest with ties to even. | | `pub func ParseFloat64(str: StringView) -> float64 ! ParseError` | Provides the public `ParseFloat64` operation. | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Format/Src/ParseFloat64.rux#L191){rel=""nofollow""} **Parameters** | Name | Type | Description | | ----- | -------------------------- | ---------------- | | `str` | `char8[..]` / `StringView` | the text to read | **Returns**: the value, or why the text is not one ## `ParseFloat32` ```rux pub func ParseFloat32(str: char8[..]) -> float32 ! ParseError pub func ParseFloat32(str: StringView) -> float32 ! ParseError ``` Reads `str` as the `float32` nearest what it spells, rounding to nearest with ties to even. Read at this width's own precision rather than at a `float64`'s and narrowed. Narrowing rounds a second time, and a value that lands on a `float32` boundary can round the wrong way once it has already been rounded to fifty-three bits on the way there. The failures [`ParseFloat64`](https://rux-lang.dev/docs/api/format/parse-float#parse-float64) reports, at this width's range: `Overflow` for a value past the largest finite `float32`, and the signed zero for one below the smallest subnormal. | Overload | Summary | | ---------------------------------------------------------------- | ------------------------------------------------------------------------------------------- | | `pub func ParseFloat32(str: char8[..]) -> float32 ! ParseError` | Reads `str` as the `float32` nearest what it spells, rounding to nearest with ties to even. | | `pub func ParseFloat32(str: StringView) -> float32 ! ParseError` | The same grammar for a view. | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Format/Src/ParseFloat64.rux#L245){rel=""nofollow""} **Parameters** | Name | Type | Description | | ----- | -------------------------- | ---------------- | | `str` | `char8[..]` / `StringView` | the text to read | **Returns**: the value, or why the text is not one ## `ParseWideFloat` ```rux pub func ParseWideFloat( allocator: Allocator, str: char8[..], layout: &FloatLayout ) -> uint512 ! ParseError ``` Reads `str` as a value under `layout`, rounding to nearest with ties to even, and reports the bits. Overflow is refused rather than rounded to infinity, as [`ParseFloat64`](https://rux-lang.dev/docs/api/format/parse-float#parse-float64) refuses it; a value too small for the format becomes the signed zero. `NaN`, `Inf` and `-Inf` are read exactly as formatting writes them. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Format/Src/WideFloatParse.rux#L18){rel=""nofollow""} **Parameters** | Name | Type | Description | | ----------- | -------------- | ------------------------------------------------ | | `allocator` | `Allocator` | where the working storage comes from | | `str` | `char8[..]` | the text to parse | | `layout` | `&FloatLayout` | which wide floating-point format the bits are in | **Returns**: the bit pattern, or the failure and where it was found ## `ParseFloat80` ```rux pub func ParseFloat80( allocator: Allocator, str: char8[..] ) -> Float80 ! ParseError ``` Reads `str` as an x87 extended value. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Format/Src/WideFloatParse.rux#L208){rel=""nofollow""} **Parameters** | Name | Type | Description | | ----------- | ----------- | ------------------------------------ | | `allocator` | `Allocator` | where the working storage comes from | | `str` | `char8[..]` | the text to parse | **Returns**: the value, or the failure and the byte offset it was found at ## `ParseFloat128` ```rux pub func ParseFloat128( allocator: Allocator, str: char8[..] ) -> Float128 ! ParseError ``` Reads `str` as a binary128 value. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Format/Src/WideFloatParse.rux#L219){rel=""nofollow""} **Parameters** | Name | Type | Description | | ----------- | ----------- | ------------------------------------ | | `allocator` | `Allocator` | where the working storage comes from | | `str` | `char8[..]` | the text to parse | **Returns**: the value, or the failure and the byte offset it was found at ## `ParseFloat256` ```rux pub func ParseFloat256( allocator: Allocator, str: char8[..] ) -> Float256 ! ParseError ``` Reads `str` as a binary256 value. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Format/Src/WideFloatParse.rux#L230){rel=""nofollow""} **Parameters** | Name | Type | Description | | ----------- | ----------- | ------------------------------------ | | `allocator` | `Allocator` | where the working storage comes from | | `str` | `char8[..]` | the text to parse | **Returns**: the value, or the failure and the byte offset it was found at ## `ParseFloat512` ```rux pub func ParseFloat512( allocator: Allocator, str: char8[..] ) -> Float512 ! ParseError ``` Reads `str` as a binary512 value. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Format/Src/WideFloatParse.rux#L241){rel=""nofollow""} **Parameters** | Name | Type | Description | | ----------- | ----------- | ------------------------------------ | | `allocator` | `Allocator` | where the working storage comes from | | `str` | `char8[..]` | the text to parse | **Returns**: the value, or the failure and the byte offset it was found at # Render The text `format` becomes with its placeholders filled, as a string of its own. ```rux pub func Render( allocator: Allocator, #Format() format: char8[..], ... ) -> String ! FormatError ``` This is the allocating entry point, and the only one: every other way of rendering writes into a destination the caller already has. Reserving up front is a guess at the result's size — the literal text plus a little for each argument — so a short call fills in without a reallocation and a long one grows through the builder as usual. It is named for what it does rather than for the package, because `Format(allocator, ...)` read as a noun and a namespace at once and said nothing about producing a value. Reports `TextFailure(OutOfMemory)` when the initial reservation fails, and otherwise whatever [`WriteFormat`](https://rux-lang.dev/docs/api/format/write-format) reported. On failure the partially built string is released rather than returned, so a caller never receives half a rendering that looks whole and the allocator gets its block back either way. ## Parameters | Name | Type | Description | | ------------------ | ----------- | ---------------------------------------------------------------------- | | `allocator` | `Allocator` | what the returned string is built with and will give its block back to | | `#Format() format` | `char8[..]` | | | `...` | | | **Returns**: the rendered string, or why it could not be produced # WriteFormat Writes `format` into `writer`, with each `{}` replaced by the next argument. ```rux pub func WriteFormat( writer: &var TextWriter, #Format() format: char8[..], ... ) -> ! FormatError ``` A placeholder is `{}`, or `{:spec}` carrying fill, alignment, sign, width, precision and style — see `ParseFormatSpec` for the grammar. `{{` and `}}` stand for a literal brace, and are the only way to write one. The pattern is checked before any of it is written, so a pattern that is wrong produces no output rather than a prefix of one. What is checked is the pattern and the argument count, both of which are known at the call site; a value's own rendering can still fail partway, and what it managed to write stays written. `format` is marked `#Format()`, so when it is a string literal the compiler counts its placeholders against the arguments and a mismatch is reported while compiling rather than as `ArgumentCountMismatch`. Reports `InvalidSpecification` with the byte offset into `format` for a specification that does not parse, a brace the grammar does not allow, or a placeholder with no closing brace; `ArgumentCountMismatch` with the placeholders counted and the arguments supplied when the two differ; and otherwise whatever the destination or a value's own renderer reported, stopping at the first refusal. The first two are found before anything is written. ## Parameters | Name | Type | Description | | ------------------ | ----------------- | --------------- | | `writer` | `&var TextWriter` | the destination | | `#Format() format` | `char8[..]` | | | `...` | | | **Returns**: success when the whole pattern and every argument were accepted # Unicode Unicode character properties, case, normalization and segmentation. ## Installation Add `Unicode` to the `[Dependencies]` table of your package's `Rux.toml`: ```toml [Dependencies] Unicode = { Namespace = "Rux", Version = "0.1.0" } ``` Standard packages are declared by hand: the registry does not serve them, so `rux add Rux/Unicode` cannot add them. ## Dependencies - [`Core`](https://rux-lang.dev/docs/api/core) 0.1.0 ## Guide Unicode character properties, case, normalization and segmentation, from tables generated out of the Unicode 17.0.0 Character Database. ### What it provides - **Properties** — the general category, canonical combining class, and the `White_Space`, `Alphabetic` and numeric properties, answered by binary search over compressed ranges. - **Case** — simple per-character mappings, the unconditional full mappings, locale-independent full case folding, and [`NextInCaseOrbit`](https://rux-lang.dev/docs/api/unicode/case#next-in-case-orbit), which walks every value with the same simple folding, such as `k`, `K` and the Kelvin sign. The conditional mappings are deliberately absent: they depend on locale or context, and applying them silently is how `i` stops round-tripping in Turkish. - **Normalization** — canonical and compatibility decomposition (Hangul arithmetically), canonical ordering, and composition: all four normal forms, over scalar-value slices. - **Graphemes** — extended grapheme cluster boundaries by the UAX #29 rules, emoji sequences and regional-indicator pairs included. - **Scripts** — the Script property: [`ScriptOf`](https://rux-lang.dev/docs/api/unicode/scripts#script-of) gives the [`Script`](https://rux-lang.dev/docs/api/unicode/scripts#script) a scalar belongs to, such as Latin, Greek or Common, and [`Script::FromName`](https://rux-lang.dev/docs/api/unicode/scripts#from-name) finds one by its long name, matched loosely. The tables under `Src/Generated*.rux` are committed output of `Tools/UnicodeGen`, which records the SHA-256 of every input it read; regenerate with `Bin/Tools/rux-unicode-gen` after changing the data under `Tools/UnicodeGen/Data`. ### Value model Unicode scalar values, [`GeneralCategory`](https://rux-lang.dev/docs/api/unicode/general-category), and [`GraphemeBreak`](https://rux-lang.dev/docs/api/unicode/grapheme-break) are structural `Copy` values. Text is borrowed through `char32[..]` and results are written into caller-owned `var char32[..]` storage; the package allocates and owns nothing. Length results remain raw writable pointers, so pass an address such as `@written`. It must be non-null and valid for one `uint` throughout the call. The slices carry their bounds but not ownership, and their backing storage must outlive the operation. ### Example ```rux import Unicode::ToUpperFull; var output: char32[3]; var written: uint = 0; ToUpperFull(0xDFu32 as char32, (@output[0])[..3], @written); ``` ## Index ### Types | Name | Summary | | --------------------------------------------------------------------------- | --------------------------------------------------- | | [`GraphemeBreak`](https://rux-lang.dev/docs/api/unicode/grapheme-break) | The grapheme break class of a scalar value. | | [`GeneralCategory`](https://rux-lang.dev/docs/api/unicode/general-category) | The Unicode general category, one per scalar value. | | [`Script`](https://rux-lang.dev/docs/api/unicode/scripts#script) | A script. | ### Functions | Name | Summary | | ------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | [`ToUpperSimple`](https://rux-lang.dev/docs/api/unicode/case#to-upper-simple) | The simple uppercase of `scalar`: one value to one, itself when it has no mapping. | | [`ToLowerSimple`](https://rux-lang.dev/docs/api/unicode/case#to-lower-simple) | The simple lowercase of `scalar`. | | [`ToTitleSimple`](https://rux-lang.dev/docs/api/unicode/case#to-title-simple) | The simple titlecase of `scalar`: the uppercase, except for the few dozen characters whose titlecase differs. | | [`NextInCaseOrbit`](https://rux-lang.dev/docs/api/unicode/case#next-in-case-orbit) | The next scalar value that case-insensitive comparison treats as `scalar`, going round the set of values with the same simple case folding: `k`, `K` and the Kelvin sign, or `σ`, `ς` and `Σ`. | | [`ToUpperFull`](https://rux-lang.dev/docs/api/unicode/case#to-upper-full) | Writes the full uppercase of `scalar` into `into` and reports how many values it took. | | [`ToLowerFull`](https://rux-lang.dev/docs/api/unicode/case#to-lower-full) | Writes the full lowercase of `scalar` into `into`. | | [`Fold`](https://rux-lang.dev/docs/api/unicode/case#fold) | Writes the full, locale-independent case folding of `scalar` into `into`. | | [`GraphemeBreakOf`](https://rux-lang.dev/docs/api/unicode/grapheme-break#grapheme-break-of) | The break class of `scalar`. | | [`IsPictographic`](https://rux-lang.dev/docs/api/unicode/grapheme-break#is-pictographic) | Whether `scalar` is an extended pictograph: the emoji and everything reserved to become one. | | [`IsGraphemeBoundary`](https://rux-lang.dev/docs/api/unicode/graphemes#is-grapheme-boundary) | Whether a cluster boundary falls before `index` in `text`. | | [`CountGraphemes`](https://rux-lang.dev/docs/api/unicode/graphemes#count-graphemes) | How many grapheme clusters `text` holds. | | [`DecomposeCanonical`](https://rux-lang.dev/docs/api/unicode/normalization#decompose-canonical) | Writes the canonical decomposition of `text` into `into`, marks in canonical order: NFD. | | [`DecomposeCompatibility`](https://rux-lang.dev/docs/api/unicode/normalization#decompose-compatibility) | Writes the compatibility decomposition of `text` into `into`, marks in canonical order: NFKD. | | [`NormalizeCanonical`](https://rux-lang.dev/docs/api/unicode/normalization#normalize-canonical) | Writes the NFC of `text` into `into`: canonical decomposition, canonical order, then composition. | | [`NormalizeCompatibility`](https://rux-lang.dev/docs/api/unicode/normalization#normalize-compatibility) | Writes the NFKC of `text` into `into`: compatibility decomposition, canonical order, then composition. | | [`CategoryOf`](https://rux-lang.dev/docs/api/unicode/general-category#category-of) | The general category of `scalar`. | | [`CombiningClassOf`](https://rux-lang.dev/docs/api/unicode/properties#combining-class-of) | The canonical combining class of `scalar`: zero for nearly everything, and the reordering key for marks. | | [`IsWhiteSpace`](https://rux-lang.dev/docs/api/unicode/properties#is-white-space) | Whether `scalar` is whitespace by Unicode's `White_Space` property. | | [`IsAlphabetic`](https://rux-lang.dev/docs/api/unicode/properties#is-alphabetic) | Whether `scalar` is alphabetic by the derived `Alphabetic` property. | | [`IsNumeric`](https://rux-lang.dev/docs/api/unicode/properties#is-numeric) | Whether `scalar` is numeric: a decimal digit, a letterlike number, or another number form. | | [`ScriptOf`](https://rux-lang.dev/docs/api/unicode/scripts#script-of) | The script `scalar` belongs to. | | [`ScriptCount`](https://rux-lang.dev/docs/api/unicode/scripts#script-count) | How many scripts there are, Unknown among them. | ### Constants | Name | Summary | | ------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- | | [`SimpleUpperPairs`](https://rux-lang.dev/docs/api/unicode/tables#simple-upper-pairs) | Simple uppercase pairs: code point, its uppercase. | | [`SimpleLowerPairs`](https://rux-lang.dev/docs/api/unicode/tables#simple-lower-pairs) | Simple lowercase pairs: code point, its lowercase. | | [`SimpleTitlePairs`](https://rux-lang.dev/docs/api/unicode/tables#simple-title-pairs) | Simple titlecase pairs, for the points whose titlecase differs from their uppercase. | | [`CaseOrbitPairs`](https://rux-lang.dev/docs/api/unicode/tables#case-orbit-pairs) | Case orbits the simple mappings do not pair: code point, the next point that folds to the same point, the largest followed by the smallest. | | [`FullFoldIndex`](https://rux-lang.dev/docs/api/unicode/tables#full-fold-index) | Full case folding index: code point, offset, length. | | [`FullFoldElements`](https://rux-lang.dev/docs/api/unicode/tables#full-fold-elements) | Full case folding elements, indexed by FullFoldIndex. | | [`FullUpperIndex`](https://rux-lang.dev/docs/api/unicode/tables#full-upper-index) | Unconditional full uppercase index: code point, offset, length. | | [`FullUpperElements`](https://rux-lang.dev/docs/api/unicode/tables#full-upper-elements) | Unconditional full uppercase elements. | | [`FullLowerIndex`](https://rux-lang.dev/docs/api/unicode/tables#full-lower-index) | Unconditional full lowercase index: code point, offset, length. | | [`FullLowerElements`](https://rux-lang.dev/docs/api/unicode/tables#full-lower-elements) | Unconditional full lowercase elements. | | [`NormalizationVectorIndex`](https://rux-lang.dev/docs/api/unicode/tables#normalization-vector-index) | Normalization vector index: five (offset, length) pairs per row, for the columns c1..c5. | | [`NormalizationVectorElements`](https://rux-lang.dev/docs/api/unicode/tables#normalization-vector-elements) | The scalar values of every conformance vector, run together end to end. | | [`GraphemeVectorIndex`](https://rux-lang.dev/docs/api/unicode/tables#grapheme-vector-index) | Grapheme vector index: offset, length per row. | | [`GraphemeVectorPoints`](https://rux-lang.dev/docs/api/unicode/tables#grapheme-vector-points) | Grapheme vector code points. | | [`GraphemeVectorBreaks`](https://rux-lang.dev/docs/api/unicode/tables#grapheme-vector-breaks) | Grapheme vector break masks: bit N set when a boundary precedes point N, the highest bit for the end of the row. | | [`GraphemeBreakRanges`](https://rux-lang.dev/docs/api/unicode/tables#grapheme-break-ranges) | Grapheme break class ranges: first, last, class ordinal. | | [`PictographicRanges`](https://rux-lang.dev/docs/api/unicode/tables#pictographic-ranges) | Extended\_Pictographic ranges: first, last. | | [`ConjunctConsonantRanges`](https://rux-lang.dev/docs/api/unicode/tables#conjunct-consonant-ranges) | InCB=Consonant ranges: first, last. | | [`ConjunctLinkerRanges`](https://rux-lang.dev/docs/api/unicode/tables#conjunct-linker-ranges) | InCB=Linker ranges: first, last. | | [`ConjunctExtendRanges`](https://rux-lang.dev/docs/api/unicode/tables#conjunct-extend-ranges) | InCB=Extend ranges: first, last. | | [`CanonicalDecompositionIndex`](https://rux-lang.dev/docs/api/unicode/tables#canonical-decomposition-index) | Canonical decomposition index: code point, offset, length. | | [`CanonicalDecompositionElements`](https://rux-lang.dev/docs/api/unicode/tables#canonical-decomposition-elements) | The scalar values every canonical decomposition expands to, run together end to end. | | [`CompatibilityDecompositionIndex`](https://rux-lang.dev/docs/api/unicode/tables#compatibility-decomposition-index) | Compatibility decomposition index: code point, offset, length. | | [`CompatibilityDecompositionElements`](https://rux-lang.dev/docs/api/unicode/tables#compatibility-decomposition-elements) | The scalar values every compatibility decomposition expands to, run together end to end. | | [`CompositionTriples`](https://rux-lang.dev/docs/api/unicode/tables#composition-triples) | Primary composite triples: starter, combining, composed. | | [`CategoryRanges`](https://rux-lang.dev/docs/api/unicode/tables#category-ranges) | General category ranges: first, last, category ordinal. | | [`CombiningClassRanges`](https://rux-lang.dev/docs/api/unicode/tables#combining-class-ranges) | Canonical combining class ranges: first, last, class. | | [`WhiteSpaceRanges`](https://rux-lang.dev/docs/api/unicode/tables#white-space-ranges) | White\_Space ranges: first, last. | | [`AlphabeticRanges`](https://rux-lang.dev/docs/api/unicode/tables#alphabetic-ranges) | Alphabetic ranges: first, last. | | [`NumericRanges`](https://rux-lang.dev/docs/api/unicode/tables#numeric-ranges) | Numeric ranges — the Nd, Nl and No categories: first, last. | | [`ScriptRanges`](https://rux-lang.dev/docs/api/unicode/tables#script-ranges) | Script ranges: first, last, script number. | | [`ScriptNameIndex`](https://rux-lang.dev/docs/api/unicode/tables#script-name-index) | Script names: offset into ScriptNameBytes and length, by script number. | | [`ScriptNameBytes`](https://rux-lang.dev/docs/api/unicode/tables#script-name-bytes) | The bytes of the scripts' long names, such as Latin or Old\_Italic, all ASCII. | | [`UnknownScript`](https://rux-lang.dev/docs/api/unicode/tables#unknown-script) | The script number of Unknown, the script of a point in no range. | | [`HangulBase`](https://rux-lang.dev/docs/api/unicode/normalization#hangul-base) | The first Hangul syllable, LV and LVT composition's base. | # GeneralCategory The Unicode general category, one per scalar value. ```rux pub enum GeneralCategory: int32 { Unassigned = 0, UppercaseLetter = 1, LowercaseLetter = 2, TitlecaseLetter = 3, ModifierLetter = 4, OtherLetter = 5, NonspacingMark = 6, SpacingMark = 7, EnclosingMark = 8, DecimalNumber = 9, LetterNumber = 10, OtherNumber = 11, ConnectorPunctuation = 12, DashPunctuation = 13, OpenPunctuation = 14, ClosePunctuation = 15, InitialPunctuation = 16, FinalPunctuation = 17, OtherPunctuation = 18, MathSymbol = 19, CurrencySymbol = 20, ModifierSymbol = 21, OtherSymbol = 22, SpaceSeparator = 23, LineSeparator = 24, ParagraphSeparator = 25, Control = 26, Format = 27, Surrogate = 28, PrivateUse = 29 } ``` `Copy`. The ordinals match the generated table and must not be reordered: the table stores them as numbers. ## Cases | Name | Value | Description | | ---------------------- | ----- | ----------------------------------------------- | | `Unassigned` | `0` | Unassigned, or outside every range. | | `UppercaseLetter` | `1` | Lu: an uppercase letter. | | `LowercaseLetter` | `2` | Ll: a lowercase letter. | | `TitlecaseLetter` | `3` | Lt: a titlecase letter. | | `ModifierLetter` | `4` | Lm: a modifier letter. | | `OtherLetter` | `5` | Lo: a letter without case. | | `NonspacingMark` | `6` | Mn: a nonspacing mark. | | `SpacingMark` | `7` | Mc: a spacing combining mark. | | `EnclosingMark` | `8` | Me: an enclosing mark. | | `DecimalNumber` | `9` | Nd: a decimal digit. | | `LetterNumber` | `10` | Nl: a letterlike number. | | `OtherNumber` | `11` | No: some other number. | | `ConnectorPunctuation` | `12` | Pc: a connector. | | `DashPunctuation` | `13` | Pd: a dash. | | `OpenPunctuation` | `14` | Ps: an opening bracket. | | `ClosePunctuation` | `15` | Pe: a closing bracket. | | `InitialPunctuation` | `16` | Pi: an initial quote. | | `FinalPunctuation` | `17` | Pf: a final quote. | | `OtherPunctuation` | `18` | Po: other punctuation. | | `MathSymbol` | `19` | Sm: a mathematical symbol. | | `CurrencySymbol` | `20` | Sc: a currency symbol. | | `ModifierSymbol` | `21` | Sk: a modifier symbol. | | `OtherSymbol` | `22` | So: some other symbol. | | `SpaceSeparator` | `23` | Zs: a space separator. | | `LineSeparator` | `24` | Zl: the line separator. | | `ParagraphSeparator` | `25` | Zp: the paragraph separator. | | `Control` | `26` | Cc: a control character. | | `Format` | `27` | Cf: an invisible formatting character. | | `Surrogate` | `28` | Cs: a surrogate half, which no scalar value is. | | `PrivateUse` | `29` | Co: private use. | ## Related ### `CategoryOf` ```rux pub func CategoryOf(scalar: char32) -> GeneralCategory ``` The general category of `scalar`. Runs in a handful of comparisons and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Unicode/Src/Properties.rux#L78){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | -------- | ---------------------------- | | `scalar` | `char32` | the scalar value to classify | **Returns**: its general category # GraphemeBreak The grapheme break class of a scalar value. ```rux pub enum GraphemeBreak: int32 { Any = 0, CarriageReturn = 1, LineFeed = 2, Control = 3, Extend = 4, ZeroWidthJoiner = 5, RegionalIndicator = 6, Prepend = 7, SpacingMark = 8, HangulL = 9, HangulV = 10, HangulT = 11, HangulLV = 12, HangulLVT = 13 } ``` `Copy`. The ordinals match the generated table and must not be reordered. ## Cases | Name | Value | Description | | ------------------- | ----- | ----------------------------------------------------------- | | `Any` | `0` | Everything with no class of its own. | | `CarriageReturn` | `1` | A carriage return, which joins only the line feed after it. | | `LineFeed` | `2` | A line feed. | | `Control` | `3` | A control character, which stands alone. | | `Extend` | `4` | A mark that extends the cluster before it. | | `ZeroWidthJoiner` | `5` | The zero-width joiner, which is what glues emoji sequences. | | `RegionalIndicator` | `6` | A regional indicator, half of a flag. | | `Prepend` | `7` | A prefix that binds to what follows it. | | `SpacingMark` | `8` | A spacing mark, kept with what precedes it. | | `HangulL` | `9` | A Hangul leading consonant. | | `HangulV` | `10` | A Hangul vowel. | | `HangulT` | `11` | A Hangul trailing consonant. | | `HangulLV` | `12` | A Hangul LV syllable. | | `HangulLVT` | `13` | A Hangul LVT syllable. | ## Related ### `GraphemeBreakOf` ```rux pub func GraphemeBreakOf(scalar: char32) -> GraphemeBreak ``` The break class of `scalar`. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Unicode/Src/Graphemes.rux#L49){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | -------- | ---------------------------- | | `scalar` | `char32` | the scalar value to classify | **Returns**: its grapheme cluster break property ### `IsPictographic` ```rux pub func IsPictographic(scalar: char32) -> bool ``` Whether `scalar` is an extended pictograph: the emoji and everything reserved to become one. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Unicode/Src/Graphemes.rux#L57){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | -------- | ------------------------ | | `scalar` | `char32` | the scalar value to test | **Returns**: whether it has the Extended\_Pictographic property # Case mapping Simple and full upper, lower and title case mappings, and case folding. ## `ToUpperSimple` ```rux pub func ToUpperSimple(scalar: char32) -> char32 ``` The simple uppercase of `scalar`: one value to one, itself when it has no mapping. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Unicode/Src/Case.rux#L18){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | -------- | ----------------------- | | `scalar` | `char32` | the scalar value to map | **Returns**: its single-scalar uppercase, or `scalar` itself when there is none ## `ToLowerSimple` ```rux pub func ToLowerSimple(scalar: char32) -> char32 ``` The simple lowercase of `scalar`. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Unicode/Src/Case.rux#L26){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | -------- | ----------------------- | | `scalar` | `char32` | the scalar value to map | **Returns**: its single-scalar lowercase, or `scalar` itself when there is none ## `ToTitleSimple` ```rux pub func ToTitleSimple(scalar: char32) -> char32 ``` The simple titlecase of `scalar`: the uppercase, except for the few dozen characters whose titlecase differs. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Unicode/Src/Case.rux#L34){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | -------- | ----------------------- | | `scalar` | `char32` | the scalar value to map | **Returns**: its single-scalar titlecase, or `scalar` itself when there is none ## `NextInCaseOrbit` ```rux pub func NextInCaseOrbit(scalar: char32) -> char32 ``` The next scalar value that case-insensitive comparison treats as `scalar`, going round the set of values with the same simple case folding: `k`, `K` and the Kelvin sign, or `σ`, `ς` and `Σ`. Calling it again on each answer visits every member of the set and comes back to `scalar`, so a caller asking whether a set of characters holds any form of a letter tests each answer until it returns. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Unicode/Src/Case.rux#L47){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | -------- | ------------------------------ | | `scalar` | `char32` | the scalar value to start from | **Returns**: the next member of its set, or `scalar` itself when no other value folds with it ## `ToUpperFull` ```rux pub func ToUpperFull( scalar: char32, into: var char32[..], written: *var uint ) -> bool ``` Writes the full uppercase of `scalar` into `into` and reports how many values it took. Up to three values, so a buffer of three always suffices; reports `false` without writing when the room is short. Falls back to the simple mapping for the points that need no expansion, which is nearly all of them. `written` must be non-null and writable. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Unicode/Src/Case.rux#L97){rel=""nofollow""} **Parameters** | Name | Type | Description | | --------- | ---------------- | ------------------------------------------------- | | `scalar` | `char32` | the scalar value to map | | `into` | `var char32[..]` | receives the mapping; three values always suffice | | `written` | `*var uint` | receives how many values were written | **Returns**: false without writing when `into` is too short ## `ToLowerFull` ```rux pub func ToLowerFull( scalar: char32, into: var char32[..], written: *var uint ) -> bool ``` Writes the full lowercase of `scalar` into `into`. `written` must be non-null and writable. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Unicode/Src/Case.rux#L108){rel=""nofollow""} **Parameters** | Name | Type | Description | | --------- | ---------------- | ------------------------------------------------- | | `scalar` | `char32` | the scalar value to map | | `into` | `var char32[..]` | receives the mapping; three values always suffice | | `written` | `*var uint` | receives how many values were written | **Returns**: false without writing when `into` is too short ## `Fold` ```rux pub func Fold( scalar: char32, into: var char32[..], written: *var uint ) -> bool ``` Writes the full, locale-independent case folding of `scalar` into `into`. Folding is for comparison rather than display: fold both strings, and equal foldings mean the same text whatever its case. It is built from the C and F entries alone, which is what makes the answer the same in every locale. A point with no entry folds to itself. `written` must be non-null and writable. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Unicode/Src/Case.rux#L122){rel=""nofollow""} **Parameters** | Name | Type | Description | | --------- | ---------------- | ------------------------------------------------- | | `scalar` | `char32` | the scalar value to fold | | `into` | `var char32[..]` | receives the folding; three values always suffice | | `written` | `*var uint` | receives how many values were written | **Returns**: false without writing when `into` is too short # Grapheme clusters Extended grapheme cluster boundaries, and how many user-perceived characters a text holds. ## `IsGraphemeBoundary` ```rux pub func IsGraphemeBoundary( text: char32[..], index: uint ) -> bool ``` Whether a cluster boundary falls before `index` in `text`. The ends count: position zero and the length are always boundaries, which is what makes "the clusters of a text" a partition of it. The rules between are UAX #29's, applied to the pair either side of the position with lookback where a rule reaches further — the emoji join, the flag pairs, and the Indic conjuncts. Runs in time proportional to the lookback, which is the run of marks behind the position; allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Unicode/Src/Graphemes.rux#L83){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------- | ------------ | -------------------------------------- | | `text` | `char32[..]` | the scalar values to examine | | `index` | `uint` | the position to test, in scalar values | **Returns**: whether a grapheme cluster boundary falls before `index` ## `CountGraphemes` ```rux pub func CountGraphemes(text: char32[..]) -> uint ``` How many grapheme clusters `text` holds. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Unicode/Src/Graphemes.rux#L170){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------ | ------------ | -------------------------- | | `text` | `char32[..]` | the scalar values to count | **Returns**: how many grapheme clusters `text` holds # Normalization Canonical and compatibility decomposition, and the NFD, NFC, NFKD and NFKC normal forms. ## `HangulBase` ```rux pub const HangulBase: uint32 = 0xAC00; ``` The first Hangul syllable, LV and LVT composition's base. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Unicode/Src/Normalize.rux#L17){rel=""nofollow""} ## `DecomposeCanonical` ```rux pub func DecomposeCanonical( text: char32[..], into: var char32[..], written: *var uint ) -> bool ``` Writes the canonical decomposition of `text` into `into`, marks in canonical order: NFD. Reports the length through `written`, or `false` without a defined result when the room is short. The decompositions are fully expanded in the tables, so nothing recurses. `written` must be non-null and writable. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Unicode/Src/Normalize.rux#L112){rel=""nofollow""} **Parameters** | Name | Type | Description | | --------- | ---------------- | ------------------------------------- | | `text` | `char32[..]` | the scalar values to decompose | | `into` | `var char32[..]` | receives the decomposition | | `written` | `*var uint` | receives how many values were written | **Returns**: false without writing when `into` is too short ## `DecomposeCompatibility` ```rux pub func DecomposeCompatibility( text: char32[..], into: var char32[..], written: *var uint ) -> bool ``` Writes the compatibility decomposition of `text` into `into`, marks in canonical order: NFKD. `written` must be non-null and writable. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Unicode/Src/Normalize.rux#L123){rel=""nofollow""} **Parameters** | Name | Type | Description | | --------- | ---------------- | ------------------------------------- | | `text` | `char32[..]` | the scalar values to decompose | | `into` | `var char32[..]` | receives the decomposition | | `written` | `*var uint` | receives how many values were written | **Returns**: false without writing when `into` is too short ## `NormalizeCanonical` ```rux pub func NormalizeCanonical( text: char32[..], into: var char32[..], written: *var uint ) -> bool ``` Writes the NFC of `text` into `into`: canonical decomposition, canonical order, then composition. `written` must be non-null and writable. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Unicode/Src/Normalize.rux#L238){rel=""nofollow""} **Parameters** | Name | Type | Description | | --------- | ---------------- | ------------------------------------- | | `text` | `char32[..]` | the scalar values to normalize | | `into` | `var char32[..]` | receives the normalized form | | `written` | `*var uint` | receives how many values were written | **Returns**: false without writing when `into` is too short ## `NormalizeCompatibility` ```rux pub func NormalizeCompatibility( text: char32[..], into: var char32[..], written: *var uint ) -> bool ``` Writes the NFKC of `text` into `into`: compatibility decomposition, canonical order, then composition. `written` must be non-null and writable. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Unicode/Src/Normalize.rux#L252){rel=""nofollow""} **Parameters** | Name | Type | Description | | --------- | ---------------- | ------------------------------------- | | `text` | `char32[..]` | the scalar values to normalize | | `into` | `var char32[..]` | receives the normalized form | | `written` | `*var uint` | receives how many values were written | **Returns**: false without writing when `into` is too short # Character properties The canonical combining class and the White\_Space, Alphabetic and Numeric properties of a scalar value. ## `CombiningClassOf` ```rux pub func CombiningClassOf(scalar: char32) -> uint32 ``` The canonical combining class of `scalar`: zero for nearly everything, and the reordering key for marks. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Unicode/Src/Properties.rux#L86){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | -------- | ---------------------------- | | `scalar` | `char32` | the scalar value to classify | **Returns**: its canonical combining class, zero for a starter ## `IsWhiteSpace` ```rux pub func IsWhiteSpace(scalar: char32) -> bool ``` Whether `scalar` is whitespace by Unicode's `White_Space` property. A superset of ASCII's six: the no-break spaces, the typographic spaces and the line and paragraph separators are all here, which is what separates this from `Text`'s deliberately ASCII-only trimming. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Unicode/Src/Properties.rux#L96){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | -------- | ------------------------ | | `scalar` | `char32` | the scalar value to test | **Returns**: whether it has the White\_Space property ## `IsAlphabetic` ```rux pub func IsAlphabetic(scalar: char32) -> bool ``` Whether `scalar` is alphabetic by the derived `Alphabetic` property. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Unicode/Src/Properties.rux#L104){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | -------- | ------------------------ | | `scalar` | `char32` | the scalar value to test | **Returns**: whether it has the Alphabetic property ## `IsNumeric` ```rux pub func IsNumeric(scalar: char32) -> bool ``` Whether `scalar` is numeric: a decimal digit, a letterlike number, or another number form. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Unicode/Src/Properties.rux#L112){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | -------- | ------------------------ | | `scalar` | `char32` | the scalar value to test | **Returns**: whether it has the Numeric\_Type property # Scripts The script each code point belongs to. ## `Script` ```rux pub struct Script { // private fields } ``` A script. `Copy`. Scripts are named by their long names in the database, such as `Latin` or `Old_Italic`, and found by name loosely: case, spaces, hyphens and underscores are ignored, so `old italic` names `Old_Italic`. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Unicode/Src/Scripts.rux#L10){rel=""nofollow""} **Associated functions** ### `FromName` ```rux pub func FromName(name: char8[..]) -> Script? ``` The script whose long name is `name`, matched loosely. | Name | Type | Description | | ------ | ----------- | ----------------------------------------- | | `name` | `char8[..]` | the name, such as `Greek` or `old_italic` | **Returns**: the script, or `none` when no script has that name [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Unicode/Src/Scripts.rux#L48){rel=""nofollow""} ### `Unknown` ```rux pub func Unknown() -> Script ``` The script of points the database assigns to none. **Returns**: the Unknown script [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Unicode/Src/Scripts.rux#L61){rel=""nofollow""} **Methods** ### `Equals` ```rux pub func Equals(self: &Script, other: Script) -> bool ``` Whether `other` is the same script. | Name | Type | Description | | ------- | -------- | ---------------- | | `other` | `Script` | the other script | **Returns**: whether they are one script [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Unicode/Src/Scripts.rux#L69){rel=""nofollow""} ### `Number` ```rux pub func Number(self: &Script) -> uint32 ``` The script's number: a stable small integer, less than [`ScriptCount()`](https://rux-lang.dev/docs/api/unicode/scripts#script-count), in the order of the scripts' names. **Returns**: the number [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Unicode/Src/Scripts.rux#L76){rel=""nofollow""} ### `WriteName` ```rux pub func WriteName( self: &Script, into: var char8[..] ) -> uint ``` Writes the script's long name, such as `Old_Italic`, into `into`. | Name | Type | Description | | ------ | --------------- | ------------------------------------------------ | | `into` | `var char8[..]` | room for the name; the longest is under 32 bytes | **Returns**: how many bytes were written, which is fewer than the name's length when `into` is too short [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Unicode/Src/Scripts.rux#L84){rel=""nofollow""} ## `ScriptOf` ```rux pub func ScriptOf(scalar: char32) -> Script ``` The script `scalar` belongs to. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Unicode/Src/Scripts.rux#L99){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | -------- | ---------------------------- | | `scalar` | `char32` | the scalar value to classify | **Returns**: its script, Unknown for a point the database assigns to none ## `ScriptCount` ```rux pub func ScriptCount() -> uint ``` How many scripts there are, Unknown among them. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Unicode/Src/Scripts.rux#L106){rel=""nofollow""} **Returns**: the count # Generated tables The Unicode 17.0.0 Character Database tables the lookups search. ## `SimpleUpperPairs` ```rux pub const SimpleUpperPairs: uint32[N] = …; ``` Simple uppercase pairs: code point, its uppercase. Sorted; absence means the point maps to itself. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Unicode/Src/GeneratedCase.rux#L14){rel=""nofollow""} ## `SimpleLowerPairs` ```rux pub const SimpleLowerPairs: uint32[N] = …; ``` Simple lowercase pairs: code point, its lowercase. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Unicode/Src/GeneratedCase.rux#L270){rel=""nofollow""} ## `SimpleTitlePairs` ```rux pub const SimpleTitlePairs: uint32[N] = …; ``` Simple titlecase pairs, for the points whose titlecase differs from their uppercase. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Unicode/Src/GeneratedCase.rux#L523){rel=""nofollow""} ## `CaseOrbitPairs` ```rux pub const CaseOrbitPairs: uint32[N] = …; ``` Case orbits the simple mappings do not pair: code point, the next point that folds to the same point, the largest followed by the smallest. Sorted. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Unicode/Src/GeneratedCase.rux#L773){rel=""nofollow""} ## `FullFoldIndex` ```rux pub const FullFoldIndex: uint32[N] = …; ``` Full case folding index: code point, offset, length. C and F entries only, so the folding is the same in every locale. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Unicode/Src/GeneratedCase.rux#L795){rel=""nofollow""} ## `FullFoldElements` ```rux pub const FullFoldElements: uint32[N] = …; ``` Full case folding elements, indexed by FullFoldIndex. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Unicode/Src/GeneratedCase.rux#L1197){rel=""nofollow""} ## `FullUpperIndex` ```rux pub const FullUpperIndex: uint32[N] = …; ``` Unconditional full uppercase index: code point, offset, length. The conditional mappings are deliberately absent — they depend on locale or context. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Unicode/Src/GeneratedCase.rux#L1346){rel=""nofollow""} ## `FullUpperElements` ```rux pub const FullUpperElements: uint32[N] = …; ``` Unconditional full uppercase elements. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Unicode/Src/GeneratedCase.rux#L1377){rel=""nofollow""} ## `FullLowerIndex` ```rux pub const FullLowerIndex: uint32[N] = …; ``` Unconditional full lowercase index: code point, offset, length. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Unicode/Src/GeneratedCase.rux#L1401){rel=""nofollow""} ## `FullLowerElements` ```rux pub const FullLowerElements: uint32[N] = …; ``` Unconditional full lowercase elements. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Unicode/Src/GeneratedCase.rux#L1432){rel=""nofollow""} ## `NormalizationVectorIndex` ```rux pub const NormalizationVectorIndex: uint32[N] = …; ``` Normalization vector index: five (offset, length) pairs per row, for the columns c1..c5. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Unicode/Src/GeneratedConformance.rux#L12){rel=""nofollow""} ## `NormalizationVectorElements` ```rux pub const NormalizationVectorElements: uint32[N] = …; ``` The scalar values of every conformance vector, run together end to end. [`NormalizationVectorIndex`](https://rux-lang.dev/docs/api/unicode/tables#normalization-vector-index) says where each vector's five forms start. These come from the Unicode Consortium's own NormalizationTest file, so a passing run means agreement with the standard's own expected output rather than with this implementation's idea of it. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Unicode/Src/GeneratedConformance.rux#L1295){rel=""nofollow""} ## `GraphemeVectorIndex` ```rux pub const GraphemeVectorIndex: uint32[N] = …; ``` Grapheme vector index: offset, length per row. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Unicode/Src/GeneratedConformance.rux#L2563){rel=""nofollow""} ## `GraphemeVectorPoints` ```rux pub const GraphemeVectorPoints: uint32[N] = …; ``` Grapheme vector code points. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Unicode/Src/GeneratedConformance.rux#L2696){rel=""nofollow""} ## `GraphemeVectorBreaks` ```rux pub const GraphemeVectorBreaks: uint32[N] = …; ``` Grapheme vector break masks: bit N set when a boundary precedes point N, the highest bit for the end of the row. No row is longer than thirty-one points. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Unicode/Src/GeneratedConformance.rux#L2868){rel=""nofollow""} ## `GraphemeBreakRanges` ```rux pub const GraphemeBreakRanges: uint32[N] = …; ``` Grapheme break class ranges: first, last, class ordinal. The ordinals mirror [`GraphemeBreak`](https://rux-lang.dev/docs/api/unicode/grapheme-break) in Graphemes.rux, and a code point in no range is `Any`. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Unicode/Src/GeneratedGraphemes.rux#L15){rel=""nofollow""} ## `PictographicRanges` ```rux pub const PictographicRanges: uint32[N] = …; ``` Extended\_Pictographic ranges: first, last. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Unicode/Src/GeneratedGraphemes.rux#L367){rel=""nofollow""} ## `ConjunctConsonantRanges` ```rux pub const ConjunctConsonantRanges: uint32[N] = …; ``` InCB=Consonant ranges: first, last. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Unicode/Src/GeneratedGraphemes.rux#L398){rel=""nofollow""} ## `ConjunctLinkerRanges` ```rux pub const ConjunctLinkerRanges: uint32[N] = …; ``` InCB=Linker ranges: first, last. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Unicode/Src/GeneratedGraphemes.rux#L416){rel=""nofollow""} ## `ConjunctExtendRanges` ```rux pub const ConjunctExtendRanges: uint32[N] = …; ``` InCB=Extend ranges: first, last. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Unicode/Src/GeneratedGraphemes.rux#L425){rel=""nofollow""} ## `CanonicalDecompositionIndex` ```rux pub const CanonicalDecompositionIndex: uint32[N] = …; ``` Canonical decomposition index: code point, offset, length. Fully expanded, so lookup never recurses. Hangul is absent: its decomposition is arithmetic and computed instead. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Unicode/Src/GeneratedNormalization.rux#L13){rel=""nofollow""} ## `CanonicalDecompositionElements` ```rux pub const CanonicalDecompositionElements: uint32[N] = …; ``` The scalar values every canonical decomposition expands to, run together end to end. [`CanonicalDecompositionIndex`](https://rux-lang.dev/docs/api/unicode/tables#canonical-decomposition-index) says where each point's run starts and how long it is; this holds the runs themselves, so a decomposition is a slice of it rather than a table lookup per value. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Unicode/Src/GeneratedNormalization.rux#L541){rel=""nofollow""} ## `CompatibilityDecompositionIndex` ```rux pub const CompatibilityDecompositionIndex: uint32[N] = …; ``` Compatibility decomposition index: code point, offset, length. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Unicode/Src/GeneratedNormalization.rux#L834){rel=""nofollow""} ## `CompatibilityDecompositionElements` ```rux pub const CompatibilityDecompositionElements: uint32[N] = …; ``` The scalar values every compatibility decomposition expands to, run together end to end. [`CompatibilityDecompositionIndex`](https://rux-lang.dev/docs/api/unicode/tables#compatibility-decomposition-index) says where each point's run starts and how long it is. These are the decompositions that change appearance rather than preserving it, which is what separates NFKD from NFD. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Unicode/Src/GeneratedNormalization.rux#L2320){rel=""nofollow""} ## `CompositionTriples` ```rux pub const CompositionTriples: uint32[N] = …; ``` Primary composite triples: starter, combining, composed. Sorted by starter then combining, for binary search. The exclusions and non-starter decompositions are already left out. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Unicode/Src/GeneratedNormalization.rux#L3093){rel=""nofollow""} ## `CategoryRanges` ```rux pub const CategoryRanges: uint32[N] = …; ``` General category ranges: first, last, category ordinal. Sorted by first; a code point in no range is unassigned. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Unicode/Src/GeneratedProperties.rux#L14){rel=""nofollow""} ## `CombiningClassRanges` ```rux pub const CombiningClassRanges: uint32[N] = …; ``` Canonical combining class ranges: first, last, class. A code point in no range has class zero, which is nearly all of them. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Unicode/Src/GeneratedProperties.rux#L873){rel=""nofollow""} ## `WhiteSpaceRanges` ```rux pub const WhiteSpaceRanges: uint32[N] = …; ``` White\_Space ranges: first, last. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Unicode/Src/GeneratedProperties.rux#L979){rel=""nofollow""} ## `AlphabeticRanges` ```rux pub const AlphabeticRanges: uint32[N] = …; ``` Alphabetic ranges: first, last. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Unicode/Src/GeneratedProperties.rux#L986){rel=""nofollow""} ## `NumericRanges` ```rux pub const NumericRanges: uint32[N] = …; ``` Numeric ranges — the Nd, Nl and No categories: first, last. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Unicode/Src/GeneratedProperties.rux#L1118){rel=""nofollow""} ## `ScriptRanges` ```rux pub const ScriptRanges: uint32[N] = …; ``` Script ranges: first, last, script number. Sorted by first; a point in no range is in the Unknown script. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Unicode/Src/GeneratedScripts.rux#L10){rel=""nofollow""} ## `ScriptNameIndex` ```rux pub const ScriptNameIndex: uint32[N] = …; ``` Script names: offset into ScriptNameBytes and length, by script number. The scripts are numbered in the order of their names. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Unicode/Src/GeneratedScripts.rux#L262){rel=""nofollow""} ## `ScriptNameBytes` ```rux pub const ScriptNameBytes: uint32[N] = …; ``` The bytes of the scripts' long names, such as Latin or Old\_Italic, all ASCII. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Unicode/Src/GeneratedScripts.rux#L297){rel=""nofollow""} ## `UnknownScript` ```rux pub const UnknownScript: uint32[N] = …; ``` The script number of Unknown, the script of a point in no range. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Unicode/Src/GeneratedScripts.rux#L426){rel=""nofollow""} # Collections Generic data structures. ## Installation Add `Collections` to the `[Dependencies]` table of your package's `Rux.toml`: ```toml [Dependencies] Collections = { Namespace = "Rux", Version = "0.1.0" } ``` Standard packages are declared by hand: the registry does not serve them, so `rux add Rux/Collections` cannot add them. ## Dependencies - [`Algorithms`](https://rux-lang.dev/docs/api/algorithms) 0.1.0 - [`Allocator`](https://rux-lang.dev/docs/api/allocator) 0.1.0 - [`Core`](https://rux-lang.dev/docs/api/core) 0.1.0 - [`Entropy`](https://rux-lang.dev/docs/api/entropy) 0.1.0 - [`Hash`](https://rux-lang.dev/docs/api/hash) 0.1.0 - [`Memory`](https://rux-lang.dev/docs/api/memory) 0.1.0 - [`Text`](https://rux-lang.dev/docs/api/text) 0.1.0 ## Guide ### What it provides | Type | Role | Also known as | | ------------------------------------------------------------------------------ | -------------------------------------------- | ------------- | | [`Array<T>`](https://rux-lang.dev/docs/api/collections/array) | Fixed-length owned heap storage | | | [`Vector<T>`](https://rux-lang.dev/docs/api/collections/vector) | Growable contiguous sequence | the stack | | [`Deque<T>`](https://rux-lang.dev/docs/api/collections/deque) | Double-ended queue over a circular buffer | the queue | | [`HashMap<K, V>`](https://rux-lang.dev/docs/api/collections/hash-map) | Open-addressed associative table | | | [`HashSet<T>`](https://rux-lang.dev/docs/api/collections/hash-set) | Open-addressed set of distinct values | | | [`TreeMap<K, V>`](https://rux-lang.dev/docs/api/collections/tree-map) | Ordered red-black-tree map | | | [`TreeSet<T>`](https://rux-lang.dev/docs/api/collections/tree-set) | Ordered red-black-tree set | | | [`PriorityQueue<T>`](https://rux-lang.dev/docs/api/collections/priority-queue) | Max-heap that hands out the largest first | the heap | | [`BitSet`](https://rux-lang.dev/docs/api/collections/bit-set) | Growable set of small integers, a bit each | | | [`SmallVector<T>`](https://rux-lang.dev/docs/api/collections/small-vector) | Vector holding 64 bytes of elements inline | | | [`LruCache<K, V>`](https://rux-lang.dev/docs/api/collections/lru-cache) | Bounded map evicting the least recently used | | There is no `Stack` or `Queue` type. [`Vector`](https://rux-lang.dev/docs/api/collections/vector) already is the stack — `Push` and `TryPop` work at the end that costs nothing to reach — and [`Deque`](https://rux-lang.dev/docs/api/collections/deque) already is the queue, with [`PushBack`](https://rux-lang.dev/docs/api/collections/deque#push-back) and `TryPopFront`. Wrapper types would duplicate them to add no safety Rux can enforce. There is no `Dictionary` either: [`HashMap`](https://rux-lang.dev/docs/api/collections/hash-map) is the one associative name. There are no linked lists. They cost a pointer chase per element and an allocation per node, and nothing in this repository wants that. ### Four ways to name a run of elements [`Array`](https://rux-lang.dev/docs/api/collections/array) is the one that owns heap storage whose length is decided at run time. The others are not interchangeable with it: | Spelling | Storage | Length | Owns it | | --------------------------------------------------------------- | -------- | --------------------- | ------- | | `T[N]` | inline | fixed at compile time | — | | `T[..]` | borrowed | run time | no | | `var T[..]` | borrowed | run time | no | | [`Array<T>`](https://rux-lang.dev/docs/api/collections/array) | heap | run time, then fixed | yes | | [`Vector<T>`](https://rux-lang.dev/docs/api/collections/vector) | heap | run time, growable | yes | `AsSlice` and `AsMutableSlice` hand out a borrowed view of a container's elements without copying them, which is how a container reaches [`Rux/Algorithms`](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/../Algorithms){rel=""nofollow""}. A [`Vector`](https://rux-lang.dev/docs/api/collections/vector) view covers its initialized elements only, never its spare capacity. Both read-only and writable slices support `values[i]` and `values[1..3]` directly. Containers use bounds-checked `Get`, `Set`, and `Reference` methods and provide iterator values for `for` loops. ### Failure model Two return shapes, and which one an operation uses says what can go wrong. An operation that has to **allocate** returns a native fallible, `T ! CollectionError` or `! CollectionError`, whose failure channel is: ```rux enum CollectionError: uint8 { OutOfMemory = 1, CapacityOverflow = 2, IndexOutOfRange = 3, Unsupported = 4 } ``` The five are not interchangeable. `OutOfMemory` is the only one worth retrying — [`IsTransient`](https://rux-lang.dev/docs/api/collections/collection-error#is-transient) says so — because the allocator having nothing to give is a state that changes. A capacity that cannot be represented will not start being representable, an index the collection does not have will not appear, and a layout the allocator refuses will be refused the same way next time. [`FromAllocError`](https://rux-lang.dev/docs/api/collections/collection-error#from-alloc-error) is what maps an allocator's own answer onto these. An operation that **cannot** allocate reports an ordinary miss with an optional — `Get`, `Remove`, and [`PopFront`](https://rux-lang.dev/docs/api/collections/deque#pop-front) return `T?` — or with a `bool`, through the `Try*` prefix and an out-parameter. So an exhausted allocator is never confused with an empty container, a missing key, or a rejected index — the distinction is in the type, not in the documentation. An operation that both allocates and can find nothing, such as a map's `Replace`, returns `V? ! CollectionError`. ```rux import Allocator::{ Allocator, SystemAllocator }; import Collections::Vector; var system = SystemAllocator(); let allocator: Allocator = system; var numbers = Vector<int32>(allocator); numbers.Push(1) catch { else => return 1 }; var last: int32 = 0; if numbers.TryPop(@last) { // ... } ``` **A failed operation changes nothing.** Capacity arithmetic is checked before anything is allocated, and a reallocated block lands in a local before it replaces the owned pointer — so a failure leaves the original allocation valid and owned, rather than leaking it and nulling the container. Every count is checked for overflow. `count * sizeof(T)` is the most dangerous expression a container writes: a product that wraps asks for a small block and then writes far past it. Containers talk to the allocator in elements rather than bytes, through three helpers in `ContainerStorage.rux` that compute the layout from `sizeof(T)` and `alignof(T)` once. Those helpers are package-private, and there is nothing to import: they are how a container is built, not something a caller composes with. What they promise is visible through any container — an element occupying no bytes still gets a run with a real address rather than the shared empty one, a growth the allocator refuses leaves the container exactly as it was, and everything held is destroyed exactly once. ### Ownership Every owning container prohibits copying. Hand one to a consuming function with `<-`; the compiler rejects later reads of the source. Canonical destructors destroy initialized elements before releasing their storage. The same capability is derived through generic fields, so a map or consuming iterator containing an owning kernel is also move-only. Canonical empty construction is `Vector<T>(allocator)`, `Deque<T>(allocator)`, `HashMap<K, V>(...)`, `HashSet<T>(...)`, `TreeMap<K, V>(...)`, and `TreeSet<T>(...)`. Descriptive or fallible factories such as `FromSlice`, `WithCapacity`, and [`Filled`](https://rux-lang.dev/docs/api/collections/array#filled) retain their names. The allocator is injected at construction and kept, so an array built from an arena disappears with the arena and one built from a pool comes back to the pool. Every constructor *copies* its elements into the storage, which means an array of a move-only element type cannot be built this way: copying such an element would give two owners to a value that promises one. [`Vector<T>`](https://rux-lang.dev/docs/api/collections/vector) and its `Push` is the shape that works, since each element is moved in exactly once. A container destroys an element it does not know is droppable by relocating it from raw backing storage into a local and letting the local's life end. This raw-storage boundary is deliberate: safe references cannot transfer ownership through borrowed storage. It costs nothing for an element type that owns nothing and is what [`~Array`](https://rux-lang.dev/docs/api/collections/array#destructor) does. ### Elements that own something [`Vector::Push`](https://rux-lang.dev/docs/api/collections/vector#push), deque pushes, and map/set insertion move their arguments into raw backing storage. Pass a named move-only element explicitly, for example `values.Push(<-value)`. Each element is destroyed exactly once, when it is removed without being returned or when its container dies. `TryPop`, removals, and consuming iterators move elements back out. [`Array`](https://rux-lang.dev/docs/api/collections/array)'s constructors copy, so an array of owning elements has to be built through a vector first. Whether handing a value to a generic container consumes it depends on what its element type turns out to be, which the container's own body cannot know — the answer is settled at each instantiation. The tests count destructions rather than assuming them: pushing seven elements destroys none, destroying the vector destroys exactly those seven, and truncating destroys exactly the ones it drops. ### Iterating [`ValueIterator`](https://rux-lang.dev/docs/api/collections/iterators#value-iterator) yields elements by copy, [`ReferenceIterator`](https://rux-lang.dev/docs/api/collections/iterators#reference-iterator) yields read-only pointers, and [`MutableReferenceIterator`](https://rux-lang.dev/docs/api/collections/iterators#mutable-reference-iterator) yields writable pointers. The compiler's `for` loop drives all three. Use pointer iteration for move-only elements: it leaves each element in its storage and copies no element. All three borrow their storage. The storage must outlive the iterator and every pointer it yields. Array and Vector provide `References()` and `MutableReferences()`; the writable form borrows the container mutably when the cursor is created and visits only initialized elements. `IntoIterator` is the owning alternative for vectors, maps, and sets. Invoke it on a named owner as `(<-values).IntoIterator()`; whatever is not yielded is destroyed with the consuming iterator. Borrowed iterators retain raw storage addresses because references cannot be stored in fields or returned. A `for` loop over an iterator *value* walks a copy of it, so the iterator the caller holds is left where it was. A loop is not a way to advance an iterator someone else is also reading. For example, `for element in numbers.MutableReferences() { *element = *element * 2; }` doubles the stored numbers. Construct `MutableReferenceIterator<T>(items)` directly to walk a `var T[..]`. Repeated `Next()` calls return `(*var T)?` and keep returning `none` after exhaustion. These cursors store raw pointers: callers must coordinate aliases and avoid moving or destroying the owner, or growing, shrinking, or reallocating its storage while an iterator or yielded pointer is in use. Iteration itself does not allocate or destroy elements. ### Hashing [`HashMap`](https://rux-lang.dev/docs/api/collections/hash-map) and [`HashSet`](https://rux-lang.dev/docs/api/collections/hash-set) are one kernel — Robin Hood open addressing over a power-of-two table — with the set storing nothing alongside its keys. A fix to the probing or the deletion is a fix to both. Each slot also keeps the top byte of its key's hash, so a lookup passing other keys compares one byte for each and calls the equality function only on a likely match: for text keys that saves reading each passed key's bytes from wherever they live, at one byte per slot. Every entry records how far it sits from the slot its hash names. An insertion that meets an entry closer to home than itself takes the slot and carries that entry onward, so the distances along a chain never decrease and the worst one stays near the average. That also makes a miss cheap: a search reaching a slot whose occupant is closer to home than the search has travelled can stop, because the key would have taken that slot on the way past. Removal shifts the following entries back one slot each, stopping at an empty slot or one already at home. That leaves the table exactly as if the removed entry had never been inserted — **there are no tombstones**, so a table that is churned rather than grown does not slowly fill with them and rehash for no reason. The tests churn five hundred insert-remove pairs at a steady size and assert the capacity never moves. #### The hash is seeded, and the seed is a secret Without one, an adversary who chooses keys can compute a few thousand that collide and turn every lookup into a linear scan — a denial of service against anything keyed on input it did not write. The seed comes from `Rux/Entropy`, and the ready-made hashers use `SipHash`, which is what makes guessing the seed the only way in. [`TableSeed::Random`](https://rux-lang.dev/docs/api/collections/table-seed#random) draws one; each draw is a system call, so a program making many tables should draw once and pass it to `WithSeed`. [`TableSeed::Of`](https://rux-lang.dev/docs/api/collections/table-seed#of) takes the words directly, for a test that needs the same table twice. A table's iteration order is its seed's, so it differs between two tables in one program and between two runs of it. Nothing may rely on that order. #### Reading and writing in one operation There is no `Entry` type. An entry API is closure-shaped, and Rux has no closures — so the operation it exists for is offered directly instead: ```rux var count: *var int32 = null; var inserted = false; counts.GetOrInsert(word, 0, @count, @inserted); *count = *count + 1; ``` One probe when the key is present, and the key named once. `Replace` is the other half: it stores a value and hands back the one that was there, where `Insert` throws it away. `RemoveEntry` hands back both halves, so a key that owns something leaves intact too — and it hands back the *stored* key rather than the one looked up. The two compare equal, but a key type carrying anything the equality ignores makes them different values, and the map's is the one it kept. #### Supplying the pair The hash and equality are supplied as functions rather than taken from the key type, because Rux has no closures and an interface value would be stored and dispatched through on every lookup. `Hashing` has ready-made pairs for the usual key types. A caller keying on its own type writes them, and the one rule is that keys comparing equal must hash the same. ### Ordered maps [`HashMap`](https://rux-lang.dev/docs/api/collections/hash-map) is the one to reach for by default: constant expected time against a pointer chase per level. [`TreeMap`](https://rux-lang.dev/docs/api/collections/tree-map) earns its keep when order is part of the question. It walks smallest key first, answers `Floor` and `Ceiling` — the nearest key at or below, at or above — and hands back everything between two bounds through `Range`, none of which a hash table can do at all, since a hash scatters keys deliberately and moves them between slots as it grows. The ordering is the caller's, given once as a function. `Comparing` has ready-made ones for the key types `Hashing` covers. The rules are the ordinary ones: consistent, the same every call, and agreeing with equality — two keys that compare `Equal` are one key, and the second to arrive replaces the first's value. `Range(start, end)` is half-open, so `Range(a, b)` and `Range(b, c)` together give exactly `Range(a, c)` with nothing repeated and nothing missed. Starting a range costs a descent rather than a walk from the smallest key. A borrow from a [`TreeMap`](https://rux-lang.dev/docs/api/collections/tree-map) outlives more than a [`HashMap`](https://rux-lang.dev/docs/api/collections/hash-map)'s: each entry is its own allocation and removal relinks the successor rather than copying into the removed node, so a pointer to an entry stays good across insertions and removals of every other key. ### Ordered sets [`TreeSet`](https://rux-lang.dev/docs/api/collections/tree-set) is to [`HashSet`](https://rux-lang.dev/docs/api/collections/hash-set) what [`TreeMap`](https://rux-lang.dev/docs/api/collections/tree-map) is to [`HashMap`](https://rux-lang.dev/docs/api/collections/hash-map): order, at the price of a pointer chase per level. It walks smallest first, answers `Floor` and `Ceiling`, and hands back what lies between two bounds through `Range`. Its elements are the keys of a tree whose values are the unit `()`, which occupies no bytes — a set is a map with the values compiled away rather than a second copy of the same balancing. An element must be copyable, exactly as a [`HashSet`](https://rux-lang.dev/docs/api/collections/hash-set)'s must: the comparison takes its two elements by value and every descent compares against elements the set holds, so an element that owned something would be destroyed by the first comparison it took part in. Owning values belong in a [`TreeMap`](https://rux-lang.dev/docs/api/collections/tree-map) under copyable keys. `IntersectWith` and `Subtract` allocate nothing, and ask for the next element by key rather than by following a pointer: removal relinks the nodes around what was removed, including the very node a pointer walk would visit next. `UnionWith` and `SymmetricDifferenceWith` can grow and report a [`CollectionError`](https://rux-lang.dev/docs/api/collections/collection-error); unlike the hash set's, they are not all-or-nothing, because a tree has no capacity to reserve in advance — a partial union is still a set with every invariant intact, and running the call again finishes it. ### Set algebra The predicates — `IsSubsetOf`, `IsSupersetOf`, `IsDisjointFrom`, `Equals` — allocate nothing and cannot fail. So do `IntersectWith` and `Subtract`, which only ever make a set smaller. `UnionWith` and `SymmetricDifferenceWith` can grow, so they report a [`CollectionError`](https://rux-lang.dev/docs/api/collections/collection-error). Both take room for the worst case first, which makes them all-or-nothing: a failure part-way would leave a set that is neither what it was nor the answer, and there is nothing useful a caller could do with that. Reserving more than needed is the price, and `ShrinkToFit` gives it back. `IntersectWith` and `Subtract` sweep the slots until a whole sweep removes nothing. Removing shifts the entries that follow a slot back into it, and a chain running past the end of the table shifts them past the end too, so no single sweep in either direction can be sure it looked at everything — and which entries move at all depends on where the table's random seed happened to put them, which is what makes getting this wrong show up in one run out of several rather than every time. That is the one place the absence of tombstones costs something. ### Complexity | Operation | Time | | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------- | | [`Array`](https://rux-lang.dev/docs/api/collections/array) construction, `Clone`, `FromSlice` | O(n) | | [`Array`](https://rux-lang.dev/docs/api/collections/array) / [`Vector`](https://rux-lang.dev/docs/api/collections/vector) `At`, `Set`, `TryGet`, `TrySet` | O(1) | | [`Vector::Push`](https://rux-lang.dev/docs/api/collections/vector#push), `TryPop`, [`SwapRemoveAt`](https://rux-lang.dev/docs/api/collections/vector#swap-remove-at), `Truncate` | O(1) amortized | | [`Vector::Insert`](https://rux-lang.dev/docs/api/collections/vector#insert), [`RemoveAt`](https://rux-lang.dev/docs/api/collections/vector#remove-at) | O(n) | | [`Deque`](https://rux-lang.dev/docs/api/collections/deque) push, pop, peek, `At` at either end | O(1) amortized | | [`Deque::MakeContiguous`](https://rux-lang.dev/docs/api/collections/deque#make-contiguous), `AsSlice` | O(capacity) | | [`HashMap`](https://rux-lang.dev/docs/api/collections/hash-map) / [`HashSet`](https://rux-lang.dev/docs/api/collections/hash-set) lookup, insert, remove | O(1) expected, O(capacity) worst | | `Reserve`, `ShrinkToFit`, `Clone`, one full traversal | O(capacity) | Growth doubles from a floor of four slots, so a run of additions costs an amortized constant. [`Deque`](https://rux-lang.dev/docs/api/collections/deque) and both tables round to powers of two, which is what lets a wrap be a mask rather than a division. ### Working with `Rux/Algorithms` Algorithms takes a pointer and a length, so a container passes the fields of a view straight in. The compacting functions return a surviving length without resizing anything, and [`Vector::Truncate`](https://rux-lang.dev/docs/api/collections/vector#truncate) is what accepts it: ```rux import Algorithms::Unique; let view = numbers.AsMutableSlice(); let kept = Unique<int32>(view); numbers.Truncate(kept); ``` ### Showing what a container holds [`WriteVectorDebug`](https://rux-lang.dev/docs/api/collections/vector#write-vector-debug), [`WriteArrayDebug`](https://rux-lang.dev/docs/api/collections/array#write-array-debug) and [`WriteDequeDebug`](https://rux-lang.dev/docs/api/collections/deque#write-deque-debug) write a sequential container as `[first, second, third]` into any [`Rux/Text`](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/../Text){rel=""nofollow""} `TextWriter`, given an element type that implements `Debug`: ```rux import Allocator::{ Allocator, SystemAllocator }; import Collections::{ Vector, WriteVectorDebug }; import Io::{ ConsoleWriter, IoError }; import Text::{ FormatError, FormatSpec, TextWriter }; // `Rux/Format` is imported for its `Debug` implementations, not for a name: `WriteVectorDebug` is bound on // `T: Debug`, and the implementation for `int32` lives there. Without this the bound is unsatisfied. import Format::*; func Show() -> ! FormatError { var system = SystemAllocator(); let allocator: Allocator = system; var numbers = Vector<int32>(allocator); numbers.Push(1) catch { else => {} }; numbers.Push(2) catch { else => {} }; var failure: IoError? = none; var console = ConsoleWriter(@failure); let sink: &var TextWriter = console; return WriteVectorDebug<int32>(sink, numbers, FormatSpec::Plain()); } ``` They are functions carrying the bound rather than `Debug` implementations, because what a [`Vector<T>`](https://rux-lang.dev/docs/api/collections/vector) looks like is entirely a question about `T` and an implementation has nowhere to say "when the element can be shown". Each instantiation resolves the element's [`WriteDebug`](https://rux-lang.dev/docs/api/collections/collection-error#write-debug) at compile time. Everything is borrowed. A container owns its elements and hands out no copy of a move-only one, so a diagnostic that took an element out to print it would be taking ownership of it; these show every element through a borrow, and a vector of move-only elements can be written as often as wanted and still holds all of them. Capacity is not shown, since the spare room past the length holds nothing. A deque is written front to back whether or not its ring has wrapped, and nothing is rearranged to do it — [`MakeContiguous`](https://rux-lang.dev/docs/api/collections/deque#make-contiguous) is a caller's decision, not a side effect of printing. The specification reaches the elements unchanged, so `{:x}` over a vector of integers writes each one in hexadecimal. [`WriteHashMapDebug`](https://rux-lang.dev/docs/api/collections/hash-map#write-hash-map-debug), [`WriteHashSetDebug`](https://rux-lang.dev/docs/api/collections/hash-set#write-hash-set-debug), [`WriteTreeMapDebug`](https://rux-lang.dev/docs/api/collections/tree-map#write-tree-map-debug) and [`WriteTreeSetDebug`](https://rux-lang.dev/docs/api/collections/tree-set#write-tree-set-debug) write a map as `{key: value, key: value}` and a set as `{element, element}` — braces rather than brackets, because what they hold is not a run of things. An ordered map or set is written in key order, so its rendering is a fact about its contents: two maps holding the same entries agree, and one map renders the same way every time. A hash map or set is written in the order of its table, which follows from the seed drawn when it was made and from the displacement every insertion caused, so it is not the insertion order, it does not hold between two maps with the same entries, and it changes between runs. Nothing sorts, since that would need an ordering on the key a hash container does not have and was built not to need; [`TreeMap`](https://rux-lang.dev/docs/api/collections/tree-map) is the container whose rendering is stable. [`CollectionError`](https://rux-lang.dev/docs/api/collections/collection-error) implements `Display` and `Debug` itself. `Display` is the stable description a reader is shown — `out of memory`, `size that cannot be represented` — and the five cases stay as distinguishable in words as they are in the type, since which one it is decides whether retrying makes sense. `Debug` names the case: `CollectionError::OutOfMemory`. Neither accepts a style or a precision, because a description has one form and truncating it produces a sentence that says something else. ### Guarantees and limitations - **Owners are move-only.** Their copy operation is prohibited and their canonical destructor releases elements and storage. `Clone` is explicit and copies elements, so it is available only when the instantiated element operations permit it. - **Raw storage remains deliberate.** Allocator blocks, tree links, stored iterator addresses, pointer-returning element borrows, and scalar output slots cannot be references. They never transfer ownership merely by being passed. - **Views borrow, never own.** Growth, rehashing, destruction, and [`Deque::MakeContiguous`](https://rux-lang.dev/docs/api/collections/deque#make-contiguous) invalidate relevant views and raw element pointers. The compiler tracks reference loans, but deliberately raw addresses remain the caller's responsibility. - **Relocation uses the raw-storage compatibility boundary.** Explicit moves are used for named owners and elements; internal relocation through allocator memory remains an intentional raw operation until ownership-aware raw places are expressible. - **Indexing is checked.** `Get`, `Set`, and `Reference` report a miss or `IndexOutOfRange` rather than indexing past the allocation. ## Index ### Types | Name | Summary | | --------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | [`Array<T>`](https://rux-lang.dev/docs/api/collections/array) | A fixed-length run of elements on storage this array owns. | | [`BitSet`](https://rux-lang.dev/docs/api/collections/bit-set) | A growable set of bits. | | [`CollectionError`](https://rux-lang.dev/docs/api/collections/collection-error) | Why a collection operation could not be completed. | | [`Deque<T>`](https://rux-lang.dev/docs/api/collections/deque) | A double-ended queue over a circular buffer. | | [`HashMap<K, V>`](https://rux-lang.dev/docs/api/collections/hash-map) | A hash table from keys to values. | | [`KeyValue<K, V>`](https://rux-lang.dev/docs/api/collections/key-value) | One entry of a map, as a value a caller can hold. | | [`HashMapIterator<K, V>`](https://rux-lang.dev/docs/api/collections/hash-map#hash-map-iterator) | An iterator over the entries of a map, by copy. | | [`HashMapIntoIterator<K, V>`](https://rux-lang.dev/docs/api/collections/hash-map#hash-map-into-iterator) | An iterator that takes a map apart, yielding each entry by value. | | [`HashSet<T>`](https://rux-lang.dev/docs/api/collections/hash-set) | A hash table of distinct values. | | [`HashSetIterator<T>`](https://rux-lang.dev/docs/api/collections/hash-set#hash-set-iterator) | An iterator over the elements of a set, by copy. | | [`HashSetIntoIterator<T>`](https://rux-lang.dev/docs/api/collections/hash-set#hash-set-into-iterator) | An iterator that takes a set apart, yielding each element by value. | | [`ValueIterator<T>`](https://rux-lang.dev/docs/api/collections/iterators#value-iterator) | An iterator that yields each element of a run by copy. | | [`ReferenceIterator<T>`](https://rux-lang.dev/docs/api/collections/iterators#reference-iterator) | An iterator that yields a pointer to each element of a run. | | [`MutableReferenceIterator<T>`](https://rux-lang.dev/docs/api/collections/iterators#mutable-reference-iterator) | An iterator that yields a writable pointer to each element of a run. | | [`LruCache<K, V>`](https://rux-lang.dev/docs/api/collections/lru-cache) | A map that holds at most `capacity` entries and evicts the least recently used. | | [`PriorityQueue<T>`](https://rux-lang.dev/docs/api/collections/priority-queue) | A max-priority queue over a binary heap. | | [`SmallVector<T>`](https://rux-lang.dev/docs/api/collections/small-vector) | A growable sequence that holds up to 64 bytes of elements without allocating. | | [`TableSeed`](https://rux-lang.dev/docs/api/collections/table-seed) | A hash seed, drawn once and shared by every table that wants one. | | [`Table<K, V>`](https://rux-lang.dev/docs/api/collections/table) | The open-addressing table [`HashMap`](https://rux-lang.dev/docs/api/collections/hash-map) and [`HashSet`](https://rux-lang.dev/docs/api/collections/hash-set) are both built on. | | [`TreeNode<K, V>`](https://rux-lang.dev/docs/api/collections/tree#tree-node) | One node of a red-black tree. | | [`Tree<K, V>`](https://rux-lang.dev/docs/api/collections/tree) | An ordered collection of entries, kept balanced by colouring. | | [`TreeMap<K, V>`](https://rux-lang.dev/docs/api/collections/tree-map) | An ordered map from keys to values. | | [`TreeMapIterator<K, V>`](https://rux-lang.dev/docs/api/collections/tree-map#tree-map-iterator) | A walk over a borrowed map, smallest key first. | | [`TreeMapRangeIterator<K, V>`](https://rux-lang.dev/docs/api/collections/tree-map#tree-map-range-iterator) | A walk over a borrowed map that stops at a bound. | | [`TreeMapIntoIterator<K, V>`](https://rux-lang.dev/docs/api/collections/tree-map#tree-map-into-iterator) | A walk that consumes the map, smallest key first. | | [`TreeSet<T>`](https://rux-lang.dev/docs/api/collections/tree-set) | An ordered set of unique elements. | | [`TreeSetIterator<T>`](https://rux-lang.dev/docs/api/collections/tree-set#tree-set-iterator) | A walk over a borrowed set, smallest element first. | | [`TreeSetRangeIterator<T>`](https://rux-lang.dev/docs/api/collections/tree-set#tree-set-range-iterator) | A walk over a borrowed set that stops at a bound. | | [`TreeSetIntoIterator<T>`](https://rux-lang.dev/docs/api/collections/tree-set#tree-set-into-iterator) | A walk that consumes the set, smallest element first. | | [`Vector<T>`](https://rux-lang.dev/docs/api/collections/vector) | A growable contiguous run of elements on storage this vector owns. | | [`VectorIntoIterator<T>`](https://rux-lang.dev/docs/api/collections/vector#vector-into-iterator) | An iterator that takes a vector apart, yielding each element by value. | ### Functions | Name | Summary | | ---------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------ | | [`FromAllocError`](https://rux-lang.dev/docs/api/collections/collection-error#from-alloc-error) | The collection error that corresponds to an allocator's. | | [`CompareUint`](https://rux-lang.dev/docs/api/collections/comparing#compare-uint) | The ordering of two `uint` values. | | [`CompareUint64`](https://rux-lang.dev/docs/api/collections/comparing#compare-uint64) | The ordering of two `uint64` values. | | [`CompareUint32`](https://rux-lang.dev/docs/api/collections/comparing#compare-uint32) | The ordering of two `uint32` values. | | [`CompareInt64`](https://rux-lang.dev/docs/api/collections/comparing#compare-int64) | The ordering of two `int64` values. | | [`CompareInt32`](https://rux-lang.dev/docs/api/collections/comparing#compare-int32) | The ordering of two `int32` values. | | [`CompareChar8`](https://rux-lang.dev/docs/api/collections/comparing#compare-char8) | The ordering of two `char8` code units. | | [`CompareSlice`](https://rux-lang.dev/docs/api/collections/comparing#compare-slice) | The ordering of two runs of characters, shortest-first where one is a prefix of the other. | | [`HashUint`](https://rux-lang.dev/docs/api/collections/hashing#hash-uint) | The seeded hash of a `uint`. | | [`HashUint64`](https://rux-lang.dev/docs/api/collections/hashing#hash-uint64) | The seeded hash of a `uint64`. | | [`HashUint32`](https://rux-lang.dev/docs/api/collections/hashing#hash-uint32) | The seeded hash of a `uint32`. | | [`HashInt64`](https://rux-lang.dev/docs/api/collections/hashing#hash-int64) | The seeded hash of an `int64`. | | [`HashInt32`](https://rux-lang.dev/docs/api/collections/hashing#hash-int32) | The seeded hash of an `int32`. | | [`HashChar8`](https://rux-lang.dev/docs/api/collections/hashing#hash-char8) | The seeded hash of a `char8`. | | [`HashSlice`](https://rux-lang.dev/docs/api/collections/hashing#hash-slice) | The seeded hash of a run of characters, which is what a string key comes to. | | [`EqualsUint`](https://rux-lang.dev/docs/api/collections/hashing#equals-uint) | Whether two `uint` keys are the same. | | [`EqualsUint64`](https://rux-lang.dev/docs/api/collections/hashing#equals-uint64) | Whether two `uint64` keys are the same. | | [`EqualsUint32`](https://rux-lang.dev/docs/api/collections/hashing#equals-uint32) | Whether two `uint32` keys are the same. | | [`EqualsInt64`](https://rux-lang.dev/docs/api/collections/hashing#equals-int64) | Whether two `int64` keys are the same. | | [`EqualsInt32`](https://rux-lang.dev/docs/api/collections/hashing#equals-int32) | Whether two `int32` keys are the same. | | [`EqualsChar8`](https://rux-lang.dev/docs/api/collections/hashing#equals-char8) | Whether two `char8` keys are the same. | | [`EqualsSlice`](https://rux-lang.dev/docs/api/collections/hashing#equals-slice) | Whether two runs of characters hold the same characters. | | [`WriteVectorDebug<T>`](https://rux-lang.dev/docs/api/collections/vector#write-vector-debug) | Writes a borrowed vector as `[first, second, third]`. | | [`WriteArrayDebug<T>`](https://rux-lang.dev/docs/api/collections/array#write-array-debug) | Writes a borrowed array as `[first, second, third]`. | | [`WriteDequeDebug<T>`](https://rux-lang.dev/docs/api/collections/deque#write-deque-debug) | Writes a borrowed deque as `[front, ..., back]`, front element first. | | [`WriteHashMapDebug<K, V>`](https://rux-lang.dev/docs/api/collections/hash-map#write-hash-map-debug) | Writes a borrowed hash map as `{key: value, key: value}`. | | [`WriteHashSetDebug<T>`](https://rux-lang.dev/docs/api/collections/hash-set#write-hash-set-debug) | Writes a borrowed hash set as `{first, second, third}`. | | [`WriteTreeMapDebug<K, V>`](https://rux-lang.dev/docs/api/collections/tree-map#write-tree-map-debug) | Writes a borrowed ordered map as `{key: value, key: value}`, in key order. | | [`WriteTreeSetDebug<T>`](https://rux-lang.dev/docs/api/collections/tree-set#write-tree-set-debug) | Writes a borrowed ordered set as `{first, second, third}`, in order. | ### Constants | Name | Summary | | --------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------- | | [`MinimumDequeCapacity`](https://rux-lang.dev/docs/api/collections/deque#minimum-deque-capacity) | The capacity a deque takes when it first has to allocate. | | [`SlotEmpty`](https://rux-lang.dev/docs/api/collections/table#slot-empty) | The state byte of a slot that has never held an entry, and does not now. | | [`MaximumProbeDistance`](https://rux-lang.dev/docs/api/collections/table#maximum-probe-distance) | The furthest an entry may sit from home before the table gives up and grows. | | [`MinimumTableCapacity`](https://rux-lang.dev/docs/api/collections/table#minimum-table-capacity) | Eight slots is where a table starts. | | [`MinimumVectorCapacity`](https://rux-lang.dev/docs/api/collections/vector#minimum-vector-capacity) | The capacity a vector takes when it first has to allocate. | # Array\<T> A fixed-length run of elements on storage this array owns. ```rux pub struct Array<T> { // private fields } ``` Move-only: it owns its elements and storage, prohibits copying, and destroys both with [`~Array`](https://rux-lang.dev/docs/api/collections/array#destructor). ## Type parameters | Name | Description | | ---- | ---------------- | | `T` | the element type | ## Associated functions ### `Filled` ```rux pub func Filled( allocator: Allocator, length: uint, value: T ) -> Array<T> ! CollectionError ``` An array of `length` elements, every one a copy of `value`. `allocator` is borrowed for the call and kept; `value` is read by value and copied into every position. A length of zero gives an empty array that owns a zero-sized block and is released like any other. A failure hands back no array at all, so there is nothing half-built to destroy. Runs in time proportional to `length`. | Name | Type | Description | | ----------- | ----------- | ---------------------------- | | `allocator` | `Allocator` | where the storage comes from | | `length` | `uint` | how many elements | | `value` | `T` | the value to act on | **Returns**: an array of `length` copies of `value` [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/Array.rux#L45){rel=""nofollow""} ### `FromSlice` ```rux pub func FromSlice( allocator: Allocator, items: T[..] ) -> Array<T> ! CollectionError ``` An array holding a copy of every element of `items`, in order. `allocator` is borrowed for the call and kept; `items` is borrowed and read. An empty slice gives an empty array. Runs in time proportional to the slice's length. | Name | Type | Description | | ----------- | ----------- | ---------------------------- | | `allocator` | `Allocator` | where the storage comes from | | `items` | `T[..]` | the elements to take | **Returns**: an array holding a copy of those elements [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/Array.rux#L64){rel=""nofollow""} ## Methods ### `Clone` ```rux pub func Clone(self: &Array<T>) -> Array<T> ! CollectionError ``` An independent array holding a copy of every element of this one. `self` is borrowed and left alone. The copy has its own storage from the same allocator, so both are released independently. Copying elements is what this does, so an element that owns something ends up owned twice — which is why this is only usable where copying an element means what it says. Runs in time proportional to the length. **Returns**: an independent copy [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/Array.rux#L83){rel=""nofollow""} ### `Length` ```rux pub func Length(self: &Array<T>) -> uint ``` How many elements the array holds. `self` is borrowed. Fixed for the array's whole life. **Returns**: how many elements it holds [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/Array.rux#L91){rel=""nofollow""} ### `IsEmpty` ```rux pub func IsEmpty(self: &Array<T>) -> bool ``` Whether the array holds no elements. `self` is borrowed. **Returns**: whether it holds nothing [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/Array.rux#L99){rel=""nofollow""} ### `Get` ```rux pub func Get(self: &Array<T>, index: uint) -> T? ``` The element at `index`, or `none` when there is no such index. `self` is borrowed; the element is returned by copy. Bounds-checked, which is what separates this from indexing the slice directly. | Name | Type | Description | | ------- | ------ | ----------------------------- | | `index` | `uint` | which one, counting from zero | **Returns**: a copy of the element, or `none` when the index is out of range [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/Array.rux#L109){rel=""nofollow""} ### `Reference` ```rux pub func Reference(self: &Array<T>, index: uint) -> (*T)? ``` A pointer to the element at `index`, or `none` when there is no such index. `self` is borrowed; the pointer borrows the element where it sits. This is how an element that owns something is read without being copied. The pointer is valid until the array is destroyed or moved. | Name | Type | Description | | ------- | ------ | ----------------------------- | | `index` | `uint` | which one, counting from zero | **Returns**: the address of the element, or `none` when the index is out of range [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/Array.rux#L121){rel=""nofollow""} ### `Set` ```rux pub func Set( self: &var Array<T>, index: uint, value: T ) -> ! CollectionError ``` Replaces the element at `index` with `value`. `self` is borrowed mutably; `value` is read by value. Reports `IndexOutOfRange` and changes nothing when there is no such index. The old element is overwritten rather than destroyed. For an element that owns something, take it out first. | Name | Type | Description | | ------- | ------ | ----------------------------- | | `index` | `uint` | which one, counting from zero | | `value` | `T` | the value to act on | **Returns**: nothing when the element was written, or `IndexOutOfRange` [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/Array.rux#L134){rel=""nofollow""} ### `AsSlice` ```rux pub func AsSlice(self: &Array<T>) -> T[..] ``` The whole array as a borrowed read-only view. `self` is borrowed. The view is what every `Rux/Algorithms` query takes. The view is valid until the array is destroyed or moved. **Returns**: the elements, borrowed [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/Array.rux#L145){rel=""nofollow""} ### `AsMutableSlice` ```rux pub func AsMutableSlice(self: &var Array<T>) -> var T[..] ``` The whole array as a borrowed writable view. `self` is borrowed mutably. The view is what every `Rux/Algorithms` mutation takes, so sorting an array is `Sort<T>(array.AsMutableSlice())`. The view is valid until the array is destroyed or moved. **Returns**: the elements, borrowed for writing [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/Array.rux#L155){rel=""nofollow""} ### `Iterate` ```rux pub func Iterate(self: &Array<T>) -> ValueIterator<T> ``` An iterator over the elements, by copy. `self` is borrowed and must outlive the iterator. This is the method a `for` loop finds. **Returns**: a cursor yielding copies of the elements [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/Array.rux#L163){rel=""nofollow""} ### `References` ```rux pub func References(self: &Array<T>) -> ReferenceIterator<T> ``` An iterator over pointers to the elements. `self` is borrowed and must outlive the iterator. This is how elements that own something are walked. **Returns**: a cursor yielding the elements' addresses [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/Array.rux#L171){rel=""nofollow""} ### `MutableReferences` ```rux pub func MutableReferences(self: &var Array<T>) -> MutableReferenceIterator<T> ``` An iterator over writable pointers to the elements, without copying them. The array's storage must outlive the iterator and every yielded pointer. Do not destroy or move the array while any of them is in use, and coordinate aliases that access the same elements. **Returns**: a cursor yielding writable element addresses [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/Array.rux#L180){rel=""nofollow""} ## Destructor ```rux func ~Array(self: &var Array<T>) ``` Destroys every element and releases the storage. Runs when the array's life ends. Elements go first and the block second, which is the only order that works: an element destroyed after its storage was released would be read from freed memory. An array that was moved away is not destroyed where it used to live, so this happens exactly once. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/Array.rux#L189){rel=""nofollow""} ## Related ### `WriteArrayDebug<T>` ```rux pub func WriteArrayDebug<T: Debug>( writer: &var TextWriter, value: &Array<T>, spec: FormatSpec ) -> ! FormatError ``` Writes a borrowed array as `[first, second, third]`. An empty array is `[]`. The array and every element are borrowed, so an array of a move-only element type is shown without disturbing one of them. `spec` describes the elements, exactly as for a vector. Reports whatever the writer or an element's implementation reported, stopping at the first refusal. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/Presentation.rux#L79){rel=""nofollow""} **Type parameters** | Name | Description | | ---------- | ---------------------------------------------------- | | `T: Debug` | the element type, which must know how to show itself | **Parameters** | Name | Type | Description | | -------- | ----------------- | ---------------------------------------- | | `writer` | `&var TextWriter` | the destination | | `value` | `&Array<T>` | the array to show, borrowed for the call | | `spec` | `FormatSpec` | what to show each element under | **Returns**: success when the whole rendering was accepted # BitSet A growable set of bits. ```rux pub struct BitSet { // private fields } ``` Move-only: it owns its words. ## Constructors ### `BitSet` ```rux pub func BitSet(allocator: Allocator) -> BitSet ``` An empty set that spans no bits and has allocated nothing. | Name | Type | Description | | ----------- | ----------- | ---------------------------- | | `allocator` | `Allocator` | where the storage comes from | **Returns**: the set [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/BitSet.rux#L25){rel=""nofollow""} ## Methods ### `Length` ```rux pub func Length(self: &BitSet) -> uint ``` How many bits the set spans, set or not. **Returns**: the length in bits [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/BitSet.rux#L32){rel=""nofollow""} ### `Resize` ```rux pub func Resize( self: &var BitSet, length: uint ) -> ! CollectionError ``` Spans `length` bits: new bits are unset, and bits past a shorter length are dropped. | Name | Type | Description | | -------- | ------ | ------------------ | | `length` | `uint` | the length in bits | **Returns**: nothing, or why there was no room [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/BitSet.rux#L40){rel=""nofollow""} ### `Get` ```rux pub func Get(self: &BitSet, index: uint) -> bool ``` Whether bit `index` is set; false for one past the length. | Name | Type | Description | | ------- | ------ | ----------- | | `index` | `uint` | the bit | **Returns**: whether it is set [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/BitSet.rux#L56){rel=""nofollow""} ### `Set` ```rux pub func Set( self: &var BitSet, index: uint ) -> ! CollectionError ``` Sets bit `index`, growing the set to span it. | Name | Type | Description | | ------- | ------ | ----------- | | `index` | `uint` | the bit | **Returns**: nothing, or why there was no room to grow [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/BitSet.rux#L65){rel=""nofollow""} ### `Reset` ```rux pub func Reset(self: &var BitSet, index: uint) ``` Unsets bit `index`. A bit past the length is already unset. | Name | Type | Description | | ------- | ------ | ----------- | | `index` | `uint` | the bit | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/BitSet.rux#L74){rel=""nofollow""} ### `Toggle` ```rux pub func Toggle( self: &var BitSet, index: uint ) -> ! CollectionError ``` Flips bit `index`, growing the set to span it. | Name | Type | Description | | ------- | ------ | ----------- | | `index` | `uint` | the bit | **Returns**: nothing, or why there was no room to grow [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/BitSet.rux#L84){rel=""nofollow""} ### `Count` ```rux pub func Count(self: &BitSet) -> uint ``` How many bits are set. **Returns**: the count [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/BitSet.rux#L93){rel=""nofollow""} ### `IsEmpty` ```rux pub func IsEmpty(self: &BitSet) -> bool ``` Whether no bit is set. **Returns**: whether the set is empty [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/BitSet.rux#L102){rel=""nofollow""} ### `Clear` ```rux pub func Clear(self: &var BitSet) ``` Unsets every bit, keeping the length. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/BitSet.rux#L111){rel=""nofollow""} ### `NextSet` ```rux pub func NextSet(self: &BitSet, from: uint) -> uint? ``` The lowest set bit at or after `from`, which walks the set in order. | Name | Type | Description | | ------ | ------ | ---------------------- | | `from` | `uint` | where to start looking | **Returns**: the bit, or `none` when no bit there or after is set [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/BitSet.rux#L124){rel=""nofollow""} ### `UnionWith` ```rux pub func UnionWith( self: &var BitSet, other: &BitSet ) -> ! CollectionError ``` Sets every bit that is set in `other`, growing to span it. | Name | Type | Description | | ------- | --------- | ------------- | | `other` | `&BitSet` | the other set | **Returns**: nothing, or why there was no room to grow [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/BitSet.rux#L146){rel=""nofollow""} ### `IntersectWith` ```rux pub func IntersectWith(self: &var BitSet, other: &BitSet) ``` Unsets every bit that is not set in `other`. | Name | Type | Description | | ------- | --------- | ------------- | | `other` | `&BitSet` | the other set | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/BitSet.rux#L160){rel=""nofollow""} ### `DifferenceWith` ```rux pub func DifferenceWith(self: &var BitSet, other: &BitSet) ``` Unsets every bit that is set in `other`. | Name | Type | Description | | ------- | --------- | ------------- | | `other` | `&BitSet` | the other set | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/BitSet.rux#L173){rel=""nofollow""} ### `Equals` ```rux pub func Equals(self: &BitSet, other: &BitSet) -> bool ``` Whether the same bits are set in both, whatever their lengths. | Name | Type | Description | | ------- | --------- | ------------- | | `other` | `&BitSet` | the other set | **Returns**: whether they hold the same members [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/BitSet.rux#L187){rel=""nofollow""} # CollectionError Why a collection operation could not be completed. ```rux pub enum CollectionError: uint8 { OutOfMemory = 1, CapacityOverflow = 2, IndexOutOfRange = 3, Unsupported = 4 } ``` Every case means the operation did not happen and the collection is as it was. ## Cases | Name | Value | Description | | ------------------ | ----- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `OutOfMemory` | `1` | The allocator had no storage to give. Transient in principle: the same request may succeed later, and a caller with something to release may make it so. | | `CapacityOverflow` | `2` | The size the operation needed could not be represented. A count times an element size that does not fit in a `uint`, or a length plus a growth that wraps. Not a shortage of memory but of arithmetic: no allocator could have served the request, because the number naming it does not exist. | | `IndexOutOfRange` | `3` | The index was not one the collection has. | | `Unsupported` | `4` | The allocator refused the layout itself rather than running short. An alignment stricter than the allocator serves, or a block it did not hand out. Retrying is pointless: the same request will be refused the same way. | ## Methods ### `IsTransient` ```rux pub func IsTransient(self: CollectionError) -> bool ``` Whether the same operation might succeed later. `self` is borrowed. True only for `OutOfMemory`, which says the allocator had nothing to give rather than that the request was impossible. A capacity that cannot be represented will not start being representable, an index the collection does not have will not appear, and a layout the allocator refuses will be refused again. Cannot fail. Runs in constant time and allocates nothing. **Returns**: whether trying again could succeed [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/CollectionError.rux#L43){rel=""nofollow""} ## Implements Display `CollectionError` conforms to `Display`. ### `WriteDisplay` ```rux pub func WriteDisplay( self: &CollectionError, writer: &var TextWriter, spec: FormatSpec ) -> ! FormatError ``` Writes the description of why an operation did not happen, or `no error` for success. The five cases stay distinguishable in words as they are in the type: a shortage of memory is not a size that cannot be named, and neither is a layout the allocator refuses outright. Those distinctions decide whether a caller retries, so a description that blurred them would send somebody to fix the wrong thing. The descriptions are stable. They are not a parsing contract: a program branches on the case. Reports whatever the writer reported, and `UnsupportedRequest` for any style or precision. | Name | Type | Description | | -------- | ----------------- | ------------------------------ | | `writer` | `&var TextWriter` | the destination | | `spec` | `FormatSpec` | what the placeholder asked for | **Returns**: success when the whole description was accepted [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/CollectionError.rux#L255){rel=""nofollow""} ## Implements Debug `CollectionError` conforms to `Debug`. ### `WriteDebug` ```rux pub func WriteDebug( self: &CollectionError, writer: &var TextWriter, spec: FormatSpec ) -> ! FormatError ``` Names the case, qualified by its type: `CollectionError::OutOfMemory`. Reports whatever the writer reported, and `UnsupportedRequest` for any style or precision. | Name | Type | Description | | -------- | ----------------- | ------------------------------ | | `writer` | `&var TextWriter` | the destination | | `spec` | `FormatSpec` | what the placeholder asked for | **Returns**: success when the whole name was accepted [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/CollectionError.rux#L274){rel=""nofollow""} ## Related ### `FromAllocError` ```rux pub func FromAllocError(error: AllocError) -> CollectionError ``` The collection error that corresponds to an allocator's. `error` is read by value. `OutOfMemory` stays itself, and `Unsupported` and `InvalidBlock` both become `Unsupported`, because from a collection's side they are the same thing — the allocator will not serve this, and asking again will not change that. Cannot fail. Runs in constant time and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/CollectionError.rux#L56){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------- | ------------ | ------------------------- | | `error` | `AllocError` | why the allocator refused | **Returns**: the same failure as a collection error # Deque\<T> A double-ended queue over a circular buffer. ```rux pub struct Deque<T> { // private fields } ``` Move-only: it owns its elements and storage, prohibits copying, and destroys both with [`~Deque`](https://rux-lang.dev/docs/api/collections/deque#destructor). ## Type parameters | Name | Description | | ---- | ---------------- | | `T` | the element type | ## Constructors ### `Deque` ```rux pub func Deque(allocator: Allocator) -> Deque<T> ``` An empty deque that has not allocated anything. `allocator` is borrowed for the call and kept. Costs nothing: a deque that is never pushed to never allocates. Cannot fail. Runs in constant time. | Name | Type | Description | | ----------- | ----------- | ---------------------------- | | `allocator` | `Allocator` | where the storage comes from | **Returns**: an empty collection that has taken no storage yet [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/Deque.rux#L51){rel=""nofollow""} ## Associated functions ### `WithCapacity` ```rux pub func WithCapacity( allocator: Allocator, capacity: uint ) -> Deque<T> ! CollectionError ``` An empty deque with room for `capacity` elements already taken. `allocator` is borrowed for the call and kept. The capacity actually taken is rounded up to a power of two, since that is what the ring's masking needs. | Name | Type | Description | | ----------- | ----------- | ---------------------------------- | | `allocator` | `Allocator` | where the storage comes from | | `capacity` | `uint` | how many elements to make room for | **Returns**: an empty deque with room for that many elements already taken [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/Deque.rux#L62){rel=""nofollow""} ### `FromSlice` ```rux pub func FromSlice( allocator: Allocator, items: T[..] ) -> Deque<T> ! CollectionError ``` A deque holding a copy of every element of `items`, front to back. `allocator` is borrowed for the call and kept; `items` is borrowed and read. Copies its elements, so a move-only element type is built with [`PushBack`](https://rux-lang.dev/docs/api/collections/deque#push-back) instead. | Name | Type | Description | | ----------- | ----------- | ---------------------------- | | `allocator` | `Allocator` | where the storage comes from | | `items` | `T[..]` | the elements to take | **Returns**: a deque holding a copy of those elements [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/Deque.rux#L78){rel=""nofollow""} ## Methods ### `Clone` ```rux pub func Clone(self: &Deque<T>) -> Deque<T> ! CollectionError ``` An independent deque holding a copy of every element of this one, in order. `self` is borrowed and left alone. The copy starts contiguous whatever this one's elements were doing. **Returns**: an independent copy [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/Deque.rux#L98){rel=""nofollow""} ### `Length` ```rux pub func Length(self: &Deque<T>) -> uint ``` How many elements the deque holds. `self` is borrowed. **Returns**: how many elements it holds [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/Deque.rux#L113){rel=""nofollow""} ### `Capacity` ```rux pub func Capacity(self: &Deque<T>) -> uint ``` How many elements the ring could hold without growing. `self` is borrowed. A power of two, or zero. **Returns**: how many elements fit before the next growth [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/Deque.rux#L121){rel=""nofollow""} ### `IsEmpty` ```rux pub func IsEmpty(self: &Deque<T>) -> bool ``` Whether the deque holds no elements. `self` is borrowed. **Returns**: whether it holds nothing [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/Deque.rux#L129){rel=""nofollow""} ### `Reserve` ```rux pub func Reserve( self: &var Deque<T>, additional: uint ) -> ! CollectionError ``` Makes room for `additional` more elements on top of those already present. `self` is borrowed mutably; the length does not change. A failure leaves the deque exactly as it was. | Name | Type | Description | | ------------ | ------ | --------------------------------------- | | `additional` | `uint` | how many more elements to make room for | **Returns**: nothing when the operation succeeded, or why it did not [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/Deque.rux#L184){rel=""nofollow""} ### `ShrinkToFit` ```rux pub func ShrinkToFit(self: &var Deque<T>) -> ! CollectionError ``` Releases the capacity the length does not need. `self` is borrowed mutably. The capacity stays a power of two, so this gives back what rounding leaves spare rather than everything above the length. An empty deque gives up its storage entirely. A failure leaves the deque usable at its current capacity: failing to hand memory back is never a reason to stop working. **Returns**: nothing when the operation succeeded, or why it did not [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/Deque.rux#L196){rel=""nofollow""} ### `Clear` ```rux pub func Clear(self: &var Deque<T>) ``` Destroys every element, keeping the storage. `self` is borrowed mutably. The front returns to physical zero, so the next run of additions does not wrap. Runs in time proportional to the length. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/Deque.rux#L224){rel=""nofollow""} ### `PushFront` ```rux pub func PushFront( self: &var Deque<T>, value: T ) -> ! CollectionError ``` Adds an element at the front, growing the ring when it is full. `self` is borrowed mutably; `value` is moved in. A failure leaves the deque exactly as it was and the value with the caller. Amortized constant time. | Name | Type | Description | | ------- | ---- | ------------------- | | `value` | `T` | the value to act on | **Returns**: nothing when the operation succeeded, or why it did not [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/Deque.rux#L256){rel=""nofollow""} ### `PushBack` ```rux pub func PushBack( self: &var Deque<T>, value: T ) -> ! CollectionError ``` Adds an element at the back, growing the ring when it is full. `self` is borrowed mutably; `value` is moved in. A failure leaves the deque exactly as it was. Amortized constant time. | Name | Type | Description | | ------- | ---- | ------------------- | | `value` | `T` | the value to act on | **Returns**: nothing when the operation succeeded, or why it did not [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/Deque.rux#L273){rel=""nofollow""} ### `PopFront` ```rux pub func PopFront(self: &var Deque<T>) -> T? ``` Takes the front element out. `self` is borrowed mutably. The element is moved out and handed to the caller rather than destroyed, so one that owns something leaves intact. Reports `none` for an empty deque. The storage is kept, so a deque emptied this way costs nothing to refill. **Returns**: the element taken from the front, or `none` when empty [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/Deque.rux#L288){rel=""nofollow""} ### `PopBack` ```rux pub func PopBack(self: &var Deque<T>) -> T? ``` Takes the back element out. `self` is borrowed mutably. The element is moved out and handed to the caller. Reports `none` for an empty deque. **Returns**: the element taken from the back, or `none` when empty [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/Deque.rux#L301){rel=""nofollow""} ### `Front` ```rux pub func Front(self: &Deque<T>) -> (*T)? ``` A pointer to the front element, or `none` for an empty deque. `self` is borrowed; the pointer borrows the element where it sits. The pointer is valid until the deque grows, shrinks, or is made contiguous. **Returns**: the address of the first element, or `none` when empty [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/Deque.rux#L312){rel=""nofollow""} ### `Back` ```rux pub func Back(self: &Deque<T>) -> (*T)? ``` A pointer to the back element, or `none` for an empty deque. `self` is borrowed; the pointer borrows the element where it sits. **Returns**: the address of the last element, or `none` when empty [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/Deque.rux#L320){rel=""nofollow""} ### `Get` ```rux pub func Get(self: &Deque<T>, index: uint) -> T? ``` The element at `index`, counting from the front, or `none` when there is no such index. `self` is borrowed; the element is returned by copy. The index is logical: element zero is the front wherever it happens to sit physically. | Name | Type | Description | | ------- | ------ | ----------------------------- | | `index` | `uint` | which one, counting from zero | **Returns**: a copy of the element, or `none` when the index is out of range [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/Deque.rux#L331){rel=""nofollow""} ### `Reference` ```rux pub func Reference(self: &Deque<T>, index: uint) -> (*T)? ``` A pointer to the element at `index`, or `none` when there is no such index. `self` is borrowed; the pointer borrows the element where it sits. The pointer is valid until the deque grows, shrinks, or is made contiguous. | Name | Type | Description | | ------- | ------ | ----------------------------- | | `index` | `uint` | which one, counting from zero | **Returns**: the address of the element, or `none` when the index is out of range [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/Deque.rux#L342){rel=""nofollow""} ### `Set` ```rux pub func Set( self: &var Deque<T>, index: uint, value: T ) -> ! CollectionError ``` Replaces the element at `index` with `value`. `self` is borrowed mutably. Reports `IndexOutOfRange` and changes nothing when there is no such index. The old element is overwritten rather than destroyed. For an element that owns something, take it out first. | Name | Type | Description | | ------- | ------ | ----------------------------- | | `index` | `uint` | which one, counting from zero | | `value` | `T` | the value to act on | **Returns**: nothing when the element was written, or `IndexOutOfRange` [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/Deque.rux#L354){rel=""nofollow""} ### `IsContiguous` ```rux pub func IsContiguous(self: &Deque<T>) -> bool ``` Whether the elements occupy one unbroken run. `self` is borrowed. True for an empty deque and for one whose elements have not wrapped past the end of the ring. This is what says whether [`AsSlice`](https://rux-lang.dev/docs/api/collections/deque#as-slice) will move anything. **Returns**: whether the elements sit in one run, which is what [`AsSlice`](https://rux-lang.dev/docs/api/collections/deque#as-slice) needs [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/Deque.rux#L365){rel=""nofollow""} ### `AsSlices` ```rux pub func AsSlices( self: &Deque<T>, front: *var T[..], back: *var T[..] ) ``` The elements as at most two runs, front run first, without moving anything. `self` is borrowed; `front` and `back` receive the two runs and either may be null. The second run is empty whenever the storage is already contiguous, so joining the two always gives the elements in order. This is the view that costs nothing. [`AsSlice`](https://rux-lang.dev/docs/api/collections/deque#as-slice) gives one run instead, and pays a rotation for it. Both views are valid until the deque grows, shrinks, or is made contiguous. | Name | Type | Description | | ------- | ------------ | ------------------------------------------------------------------ | | `front` | `*var T[..]` | receives the first run of elements | | `back` | `*var T[..]` | receives the second, which is empty when the storage is contiguous | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/Deque.rux#L378){rel=""nofollow""} ### `MakeContiguous` ```rux pub func MakeContiguous(self: &var Deque<T>) ``` Moves the elements so they occupy one unbroken run starting at physical zero. `self` is borrowed mutably. Allocates nothing: rotating the whole ring left by the head brings the front element to zero and preserves cyclic order for every slot at once, so no element has to be tracked individually. Every pointer and view into the deque is invalidated, and so is any physical index a caller recorded. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/Deque.rux#L413){rel=""nofollow""} ### `AsSlice` ```rux pub func AsSlice(self: &var Deque<T>) -> T[..] ``` Every element as one borrowed read-only view, moving them together first. `self` is borrowed mutably — unlike a vector's, producing a single view can move the elements, which is why this asks for a writable receiver rather than a read-only one. The view is valid until the deque grows, shrinks, or is made contiguous again. **Returns**: the elements, borrowed; empty unless the storage is contiguous [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/Deque.rux#L425){rel=""nofollow""} ### `AsMutableSlice` ```rux pub func AsMutableSlice(self: &var Deque<T>) -> var T[..] ``` Every element as one borrowed writable view, moving them together first. `self` is borrowed mutably. The view is valid until the deque grows, shrinks, or is made contiguous again. **Returns**: the elements borrowed for writing; empty unless the storage is contiguous [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/Deque.rux#L435){rel=""nofollow""} ### `Iterate` ```rux pub func Iterate(self: &var Deque<T>) -> ValueIterator<T> ``` An iterator over the elements, front to back, by copy. `self` is borrowed mutably and must outlive the iterator, and the elements are moved together first so one run can be walked. This is the method a `for` loop finds. The deque must not grow or shrink while the iterator is alive. **Returns**: a cursor yielding copies of the elements, front to back [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/Deque.rux#L446){rel=""nofollow""} ### `References` ```rux pub func References(self: &var Deque<T>) -> ReferenceIterator<T> ``` An iterator over pointers to the elements, front to back. `self` is borrowed mutably and must outlive the iterator, and the elements are moved together first. **Returns**: a cursor yielding the elements' addresses, front to back [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/Deque.rux#L454){rel=""nofollow""} ## Destructor ```rux func ~Deque(self: &var Deque<T>) ``` Destroys every element and releases the storage. Runs when the deque's life ends. The elements go first and the block second, since an element destroyed after its storage was released would be read from freed memory. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/Deque.rux#L240){rel=""nofollow""} ## Related ### `MinimumDequeCapacity` ```rux pub const MinimumDequeCapacity: uint = 4; ``` The capacity a deque takes when it first has to allocate. Four slots, and a power of two like every capacity after it. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/Deque.rux#L22){rel=""nofollow""} ### `WriteDequeDebug<T>` ```rux pub func WriteDequeDebug<T: Debug>( writer: &var TextWriter, value: &Deque<T>, spec: FormatSpec ) -> ! FormatError ``` Writes a borrowed deque as `[front, ..., back]`, front element first. The order is the deque's own — what [`PopFront`](https://rux-lang.dev/docs/api/collections/deque#pop-front) would yield, in the order it would yield it — whether or not the ring has wrapped. A wrapped deque holds its elements in two runs, and both are walked inside one pair of brackets, so where the ring happens to be split is not visible in the output and does not need to be. Nothing is rearranged to write it: this is the reason the deque is borrowed rather than borrowed mutably, since making the elements contiguous first would be a diagnostic quietly moving a caller's data around. `spec` describes the elements, exactly as for a vector. Reports whatever the writer or an element's implementation reported, stopping at the first refusal. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/Presentation.rux#L98){rel=""nofollow""} **Type parameters** | Name | Description | | ---------- | ---------------------------------------------------- | | `T: Debug` | the element type, which must know how to show itself | **Parameters** | Name | Type | Description | | -------- | ----------------- | ---------------------------------------- | | `writer` | `&var TextWriter` | the destination | | `value` | `&Deque<T>` | the deque to show, borrowed for the call | | `spec` | `FormatSpec` | what to show each element under | **Returns**: success when the whole rendering was accepted # HashMap\<K, V> A hash table from keys to values. ```rux pub struct HashMap<K, V> { // private fields } ``` Move-only: it owns its entries and storage and prohibits copying. ## Type parameters | Name | Description | | ---- | -------------- | | `K` | the key type | | `V` | the value type | ## Constructors ### `HashMap` ```rux pub func HashMap( allocator: Allocator, hash: func(K, uint64, uint64) -> uint64, equals: func(K, K) -> bool ) -> HashMap<K, V> ``` An empty map that has not allocated anything, with a seed drawn from the operating system. `allocator` is borrowed for the call and kept. A program making many maps should draw one seed with [`TableSeed::Random`](https://rux-lang.dev/docs/api/collections/table-seed#random) and use [`WithSeed`](https://rux-lang.dev/docs/api/collections/hash-map#with-seed), since each draw here is a system call. | Name | Type | Description | | ----------- | ----------------------------------- | ---------------------------------------------------------- | | `allocator` | `Allocator` | where the storage comes from | | `hash` | `func(K, uint64, uint64) -> uint64` | how a key is hashed, taking the key and the two seed words | | `equals` | `func(K, K) -> bool` | whether two keys are the same | **Returns**: an empty collection that has taken no storage yet [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/HashMap.rux#L44){rel=""nofollow""} ## Associated functions ### `WithSeed` ```rux pub func WithSeed( allocator: Allocator, seed: TableSeed, hash: func(K, uint64, uint64) -> uint64, equals: func(K, K) -> bool ) -> HashMap<K, V> ``` An empty map that has not allocated anything, hashing with `seed`. `allocator` is borrowed for the call and kept; `seed` is read by value. Two maps sharing a seed hash alike, which is what a caller drawing one seed for many maps wants and what a test needing the same table twice needs. | Name | Type | Description | | ----------- | ----------------------------------- | ----------------------------------------------------------------- | | `allocator` | `Allocator` | where the storage comes from | | `seed` | `TableSeed` | the two words that key the hash, which decide the iteration order | | `hash` | `func(K, uint64, uint64) -> uint64` | how a key is hashed, taking the key and the two seed words | | `equals` | `func(K, K) -> bool` | whether two keys are the same | **Returns**: an empty map keyed with that seed [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/HashMap.rux#L59){rel=""nofollow""} ### `WithCapacity` ```rux pub func WithCapacity( allocator: Allocator, capacity: uint, hash: func(K, uint64, uint64) -> uint64, equals: func(K, K) -> bool ) -> HashMap<K, V> ! CollectionError ``` An empty map with room for `capacity` entries already taken. The capacity actually taken is rounded up to a power of two above the load factor, so it is larger than asked for. | Name | Type | Description | | ----------- | ----------------------------------- | ---------------------------------------------------------- | | `allocator` | `Allocator` | where the storage comes from | | `capacity` | `uint` | how many elements to make room for | | `hash` | `func(K, uint64, uint64) -> uint64` | how a key is hashed, taking the key and the two seed words | | `equals` | `func(K, K) -> bool` | whether two keys are the same | **Returns**: an empty map with room for that many entries already taken [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/HashMap.rux#L73){rel=""nofollow""} ## Methods ### `Length` ```rux pub func Length(self: &HashMap<K, V>) -> uint ``` How many entries the map holds. **Returns**: how many entries it holds [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/HashMap.rux#L83){rel=""nofollow""} ### `Capacity` ```rux pub func Capacity(self: &HashMap<K, V>) -> uint ``` How many slots the table has. Not how many entries fit: a quarter of the slots are kept free, because a table run fuller spends its time displacing entries rather than storing them. **Returns**: how many entries fit before the next growth [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/HashMap.rux#L92){rel=""nofollow""} ### `IsEmpty` ```rux pub func IsEmpty(self: &HashMap<K, V>) -> bool ``` Whether the map holds no entries. **Returns**: whether it holds nothing [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/HashMap.rux#L99){rel=""nofollow""} ### `ContainsKey` ```rux pub func ContainsKey(self: &HashMap<K, V>, key: K) -> bool ``` Whether the map has an entry for `key`. `self` is borrowed; `key` is read by value. Runs in constant expected time and allocates nothing. | Name | Type | Description | | ----- | ---- | ------------------ | | `key` | `K` | the key to look up | **Returns**: whether an entry with that key is present [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/HashMap.rux#L109){rel=""nofollow""} ### `Get` ```rux pub func Get(self: &HashMap<K, V>, key: K) -> V? ``` The value stored under `key`, or `none` when there is no such entry. `self` is borrowed; the value is returned by copy. | Name | Type | Description | | ----- | ---- | ------------------ | | `key` | `K` | the key to look up | **Returns**: a copy of the value, or `none` when the key is absent [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/HashMap.rux#L118){rel=""nofollow""} ### `Reference` ```rux pub func Reference(self: &HashMap<K, V>, key: K) -> (*V)? ``` A pointer to the value stored under `key`, or `none` when there is no such entry. `self` is borrowed; the pointer borrows the value where it sits, which is how one that owns something is read without being taken. The pointer is valid until the map grows, shrinks, or has anything inserted or removed. | Name | Type | Description | | ----- | ---- | ------------------ | | `key` | `K` | the key to look up | **Returns**: the address of the value, or `none` when the key is absent [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/HashMap.rux#L130){rel=""nofollow""} ### `TryReferenceMutable` ```rux pub func TryReferenceMutable( self: &var HashMap<K, V>, key: K, value: *var *var V ) -> bool ``` Points `value` at the stored value for `key`, so it can be changed in place. `self` is borrowed mutably; `value` receives the pointer and is left alone when there is no such entry. Reports whether there was one. An out-parameter rather than an `(*var V)?`, which does not survive lowering inside a generic today. The pointer is valid until the map grows, shrinks, or has anything inserted or removed. Overwriting through it replaces the value without destroying what was there. | Name | Type | Description | | ------- | ------------- | ---------------------------------------- | | `key` | `K` | the key to look up | | `value` | `*var *var V` | receives the address of the stored value | **Returns**: whether the key was present [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/HashMap.rux#L145){rel=""nofollow""} ### `Insert` ```rux pub func Insert( self: &var HashMap<K, V>, key: K, value: V ) -> ! CollectionError ``` Stores `value` under `key`, replacing whatever was there. `self` is borrowed mutably; both are moved in. A key already present keeps its stored key and takes the new value, and the value it had is destroyed — use [`Remove`](https://rux-lang.dev/docs/api/collections/hash-map#remove) first where the old one is wanted. A failure leaves the map exactly as it was and both arguments with the caller. Runs in constant expected time. | Name | Type | Description | | ------- | ---- | ------------------- | | `key` | `K` | the key to look up | | `value` | `V` | the value to act on | **Returns**: nothing when the operation succeeded, or why it did not [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/HashMap.rux#L160){rel=""nofollow""} ### `Remove` ```rux pub func Remove(self: &var HashMap<K, V>, key: K) -> V? ``` Takes the entry for `key` out and hands back its value. `self` is borrowed mutably. The value is moved out rather than destroyed, so one that owns something leaves intact; the key is destroyed, having no other owner. Reports `none` when there is no such entry. The gap closes behind the entry, so the table is left exactly as if it had never been inserted. Runs in constant expected time. | Name | Type | Description | | ----- | ---- | ------------------ | | `key` | `K` | the key to look up | **Returns**: the value that was stored, or `none` when the key was absent [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/HashMap.rux#L190){rel=""nofollow""} ### `Reserve` ```rux pub func Reserve( self: &var HashMap<K, V>, additional: uint ) -> ! CollectionError ``` Makes room for `additional` more entries on top of those already present. `self` is borrowed mutably; the length does not change. A failure leaves the map exactly as it was. | Name | Type | Description | | ------------ | ------ | --------------------------------------- | | `additional` | `uint` | how many more elements to make room for | **Returns**: nothing when the operation succeeded, or why it did not [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/HashMap.rux#L203){rel=""nofollow""} ### `ShrinkToFit` ```rux pub func ShrinkToFit(self: &var HashMap<K, V>) -> ! CollectionError ``` Releases the capacity the entry count does not need. `self` is borrowed mutably. An empty map gives up its storage entirely. **Returns**: nothing when the operation succeeded, or why it did not [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/HashMap.rux#L211){rel=""nofollow""} ### `Clear` ```rux pub func Clear(self: &var HashMap<K, V>) ``` Destroys every entry, keeping the storage. `self` is borrowed mutably. Runs in time proportional to the capacity. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/HashMap.rux#L218){rel=""nofollow""} ### `TryNextEntry` ```rux pub func TryNextEntry( self: &HashMap<K, V>, cursor: *var uint, key: *var K, value: *var V ) -> bool ``` Walks to the next occupied slot at or after `cursor`, reporting the entry it holds. `self` is borrowed; `cursor` is read and advanced past whatever is reported, so a caller starts it at zero and keeps calling. `key` and `value` receive copies and are left alone when this reports false. The order is the table's, which is the seed's and not the insertion's. Nothing may be inserted or removed while a walk is in progress: either moves entries between slots, and a cursor is a slot. | Name | Type | Description | | -------- | ----------- | -------------------------------------------------------- | | `cursor` | `*var uint` | the position to resume from, advanced past what was read | | `key` | `*var K` | receives the key | | `value` | `*var V` | receives the value | **Returns**: whether an entry was read; false at the end [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/HashMap.rux#L232){rel=""nofollow""} ### `GetOrInsert` ```rux pub func GetOrInsert( self: &var HashMap<K, V>, key: K, value: V, existing: *var *var V, inserted: *var bool ) -> ! CollectionError ``` Points `existing` at the value stored under `key`, inserting `value` first when there is none. `self` is borrowed mutably; `key` and `value` are moved in only when there was no entry, and destroyed otherwise — the map keeps what it already had. `existing` receives a pointer to the stored value either way, and `inserted` receives whether the map grew; both may be null. This is what an entry API is for, without pretending Rux has closures: a caller that wants to read a value or put one there gets one operation instead of a lookup followed by an insertion, and does not have to name the key twice. A failure leaves the map exactly as it was. The pointer is valid until the map grows, shrinks, or has anything inserted or removed. | Name | Type | Description | | ---------- | ------------- | --------------------------------------------------- | | `key` | `K` | the key to look up | | `value` | `V` | the value to act on | | `existing` | `*var *var V` | receives the value already stored under that key | | `inserted` | `*var bool` | receives whether the value given was the one stored | **Returns**: nothing when the operation succeeded, or why it did not [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/HashMap.rux#L266){rel=""nofollow""} ### `Replace` ```rux pub func Replace( self: &var HashMap<K, V>, key: K, value: V ) -> V? ! CollectionError ``` Stores `value` under `key` and hands back the value that was there. `self` is borrowed mutably; both are moved in. The old value is moved out rather than destroyed, which is the difference between this and [`Insert`](https://rux-lang.dev/docs/api/collections/hash-map#insert): one hands the previous value back and the other throws it away. Reports `none` when there was no entry, having inserted this one. A failure leaves the map exactly as it was, and is reported apart from the absence. | Name | Type | Description | | ------- | ---- | ------------------- | | `key` | `K` | the key to look up | | `value` | `V` | the value to act on | **Returns**: the value that was there, or `none` when the key was absent [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/HashMap.rux#L302){rel=""nofollow""} ### `RemoveEntry` ```rux pub func RemoveEntry( self: &var HashMap<K, V>, key: K ) -> KeyValue<K, V>? ``` Takes the entry for `key` out and hands back both halves of it. `self` is borrowed mutably. Both the stored key and the value are moved out, so a key that owns something leaves intact too — which [`Remove`](https://rux-lang.dev/docs/api/collections/hash-map#remove) does not offer, since it destroys the key. Reports `none` when there is no such entry. The stored key is handed back rather than the one that was looked up: the two compare equal, but a key type carrying anything the equality ignores makes them different values, and the map's is the one that was kept. | Name | Type | Description | | ----- | ---- | ------------------ | | `key` | `K` | the key to look up | **Returns**: the whole entry, or `none` when the key was absent [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/HashMap.rux#L329){rel=""nofollow""} ### `Iterate` ```rux pub func Iterate(self: &HashMap<K, V>) -> HashMapIterator<K, V> ``` An iterator over the entries, by copy. `self` is borrowed and must outlive the iterator. This is the method a `for` loop finds. The order is the table's, which is the seed's and not the insertion's. Nothing may be inserted or removed while the iterator is alive. **Returns**: a cursor over the entries, in an order the seed decides [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/HashMap.rux#L343){rel=""nofollow""} ### `IntoIterator` ```rux pub func IntoIterator(self: HashMap<K, V>) -> HashMapIntoIterator<K, V> ``` Takes the map apart into an iterator over its entries. Consumes the map: it is moved into the iterator, and the storage goes with it, so nothing is copied and nothing is reallocated. Each entry comes out by value, which is how one whose key or value owns something leaves. Whatever is not taken is destroyed when the iterator's life ends. **Returns**: a cursor that consumes the map as it goes [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/HashMap.rux#L360){rel=""nofollow""} ## Related ### `HashMapIterator<K, V>` ```rux pub struct HashMapIterator<K, V> { // private fields } ``` An iterator over the entries of a map, by copy. Borrows the map, so the map must outlive it and must not be inserted into or removed from while it is alive: either moves entries between slots, and this walks slots. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/HashMap.rux#L407){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | -------------- | | `K` | the key type | | `V` | the value type | **Implements Iterator** `HashMapIterator<K, V>` conforms to `Iterator`. #### `Next` ```rux pub func Next(self: &var HashMapIterator<K, V>) -> KeyValue<K, V>? ``` The next entry, or `none` once every slot has been looked at. `self` is borrowed mutably and advanced. The key and value are copies; a map of things that own something is walked with [`TryNextEntry`](https://rux-lang.dev/docs/api/collections/hash-map#try-next-entry) and a pointer instead. **Returns**: the next entry, or `none` at the end [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/HashMap.rux#L423){rel=""nofollow""} ### `HashMapIntoIterator<K, V>` ```rux pub struct HashMapIntoIterator<K, V> { // private fields } ``` An iterator that takes a map apart, yielding each entry by value. Move-only: it owns the storage the map owned. Whatever is left when its life ends is destroyed with it, which is what makes stopping part-way safe. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/HashMap.rux#L444){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | -------------- | | `K` | the key type | | `V` | the value type | **Implements Iterator** `HashMapIntoIterator<K, V>` conforms to `Iterator`. #### `Next` ```rux pub func Next(self: &var HashMapIntoIterator<K, V>) -> KeyValue<K, V>? ``` The next entry, moved out, or `none` once every slot has been looked at. `self` is borrowed mutably and advanced. The slot is emptied as the entry leaves, so what remains for the destructor is exactly what nobody took. **Returns**: the next entry, or `none` at the end [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/HashMap.rux#L462){rel=""nofollow""} ### `WriteHashMapDebug<K, V>` ```rux pub func WriteHashMapDebug<K: Debug, V: Debug>( writer: &var TextWriter, value: &HashMap<K, V>, spec: FormatSpec ) -> ! FormatError ``` Writes a borrowed hash map as `{key: value, key: value}`. An empty map is `{}`. Braces rather than brackets, because a map is not a run of elements and reading its rendering as one would be reading it wrongly. The order is the table's, which follows from the seed the map was made with and from every insertion and removal since — so it is not the insertion order, it does not hold between two maps with the same entries, and it changes between runs of the same program. Nothing here sorts, since that would need an ordering on the key that a hash map does not have. [`TreeMap`](https://rux-lang.dev/docs/api/collections/tree-map) is the container whose rendering is stable. Every key and value is shown through a borrow of it, so a map of move-only entries is shown without taking one out. `spec` is handed to each of them unchanged. Reports whatever the writer or an entry's implementation reported, stopping at the first refusal. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/Presentation.rux#L127){rel=""nofollow""} **Type parameters** | Name | Description | | ---------- | -------------------------------------------------- | | `K: Debug` | the key type, which must know how to show itself | | `V: Debug` | the value type, which must know how to show itself | **Parameters** | Name | Type | Description | | -------- | ----------------- | -------------------------------------- | | `writer` | `&var TextWriter` | the destination | | `value` | `&HashMap<K, V>` | the map to show, borrowed for the call | | `spec` | `FormatSpec` | what to show each key and value under | **Returns**: success when the whole rendering was accepted # HashSet\<T> A hash table of distinct values. ```rux pub struct HashSet<T> { // private fields } ``` Move-only: it owns its elements and its storage. ## Type parameters | Name | Description | | ---- | ---------------- | | `T` | the element type | ## Constructors ### `HashSet` ```rux pub func HashSet( allocator: Allocator, hash: func(T, uint64, uint64) -> uint64, equals: func(T, T) -> bool ) -> HashSet<T> ``` An empty set that has not allocated anything, with a seed drawn from the operating system. | Name | Type | Description | | ----------- | ----------------------------------- | ---------------------------------------------------------- | | `allocator` | `Allocator` | where the storage comes from | | `hash` | `func(T, uint64, uint64) -> uint64` | how a key is hashed, taking the key and the two seed words | | `equals` | `func(T, T) -> bool` | whether two elements are the same | **Returns**: an empty collection that has taken no storage yet [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/HashSet.rux#L34){rel=""nofollow""} ## Associated functions ### `WithSeed` ```rux pub func WithSeed( allocator: Allocator, seed: TableSeed, hash: func(T, uint64, uint64) -> uint64, equals: func(T, T) -> bool ) -> HashSet<T> ``` An empty set that has not allocated anything, hashing with `seed`. | Name | Type | Description | | ----------- | ----------------------------------- | ----------------------------------------------------------------- | | `allocator` | `Allocator` | where the storage comes from | | `seed` | `TableSeed` | the two words that key the hash, which decide the iteration order | | `hash` | `func(T, uint64, uint64) -> uint64` | how a key is hashed, taking the key and the two seed words | | `equals` | `func(T, T) -> bool` | whether two elements are the same | **Returns**: an empty set keyed with that seed [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/HashSet.rux#L46){rel=""nofollow""} ### `WithCapacity` ```rux pub func WithCapacity( allocator: Allocator, capacity: uint, hash: func(T, uint64, uint64) -> uint64, equals: func(T, T) -> bool ) -> HashSet<T> ! CollectionError ``` An empty set with room for `capacity` elements already taken. | Name | Type | Description | | ----------- | ----------------------------------- | ---------------------------------------------------------- | | `allocator` | `Allocator` | where the storage comes from | | `capacity` | `uint` | how many elements to make room for | | `hash` | `func(T, uint64, uint64) -> uint64` | how a key is hashed, taking the key and the two seed words | | `equals` | `func(T, T) -> bool` | whether two elements are the same | **Returns**: an empty set with room for that many elements already taken [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/HashSet.rux#L58){rel=""nofollow""} ## Methods ### `Length` ```rux pub func Length(self: &HashSet<T>) -> uint ``` How many elements the set holds. **Returns**: how many elements it holds [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/HashSet.rux#L68){rel=""nofollow""} ### `Capacity` ```rux pub func Capacity(self: &HashSet<T>) -> uint ``` How many slots the table has. **Returns**: how many elements fit before the next growth [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/HashSet.rux#L75){rel=""nofollow""} ### `IsEmpty` ```rux pub func IsEmpty(self: &HashSet<T>) -> bool ``` Whether the set holds no elements. **Returns**: whether it holds nothing [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/HashSet.rux#L82){rel=""nofollow""} ### `Contains` ```rux pub func Contains(self: &HashSet<T>, value: T) -> bool ``` Whether `value` is in the set. `self` is borrowed; `value` is read by value. Runs in constant expected time and allocates nothing. | Name | Type | Description | | ------- | ---- | ------------------- | | `value` | `T` | the value to act on | **Returns**: whether the value is present [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/HashSet.rux#L92){rel=""nofollow""} ### `Insert` ```rux pub func Insert( self: &var HashSet<T>, value: T ) -> bool ! CollectionError ``` Adds `value` to the set, reporting whether it was not already there. `self` is borrowed mutably; `value` is moved in when it is added and destroyed when it was already present -- a set holds one of each, and the one it already had is the one it keeps. A failure leaves the set exactly as it was. | Name | Type | Description | | ------- | ---- | ------------------- | | `value` | `T` | the value to act on | **Returns**: whether the value was new rather than already present [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/HashSet.rux#L103){rel=""nofollow""} ### `Remove` ```rux pub func Remove(self: &var HashSet<T>, value: T) -> T? ``` Takes `value` out of the set and hands it back. `self` is borrowed mutably. The element is moved out rather than destroyed, so one that owns something leaves intact. Reports `none` when the set did not have it. | Name | Type | Description | | ------- | ---- | ------------------- | | `value` | `T` | the value to act on | **Returns**: the value that was stored, or `none` when it was absent [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/HashSet.rux#L118){rel=""nofollow""} ### `Reserve` ```rux pub func Reserve( self: &var HashSet<T>, additional: uint ) -> ! CollectionError ``` Makes room for `additional` more elements on top of those already present. | Name | Type | Description | | ------------ | ------ | --------------------------------------- | | `additional` | `uint` | how many more elements to make room for | **Returns**: nothing when the operation succeeded, or why it did not [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/HashSet.rux#L129){rel=""nofollow""} ### `ShrinkToFit` ```rux pub func ShrinkToFit(self: &var HashSet<T>) -> ! CollectionError ``` Releases the capacity the element count does not need. **Returns**: nothing when the operation succeeded, or why it did not [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/HashSet.rux#L136){rel=""nofollow""} ### `Clear` ```rux pub func Clear(self: &var HashSet<T>) ``` Destroys every element, keeping the storage. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/HashSet.rux#L142){rel=""nofollow""} ### `TryNext` ```rux pub func TryNext( self: &HashSet<T>, cursor: *var uint, value: *var T ) -> bool ``` Walks to the next occupied slot at or after `cursor`, reporting the element it holds. `self` is borrowed; `cursor` is read and advanced past whatever is reported. The order is the table's, which is the seed's and not the insertion's, and nothing may be inserted or removed while a walk is in progress. | Name | Type | Description | | -------- | ----------- | -------------------------------------------------------- | | `cursor` | `*var uint` | the position to resume from, advanced past what was read | | `value` | `*var T` | receives the element | **Returns**: whether an element was read; false at the end [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/HashSet.rux#L153){rel=""nofollow""} ### `Iterate` ```rux pub func Iterate(self: &HashSet<T>) -> HashSetIterator<T> ``` An iterator over the elements, by copy. `self` is borrowed and must outlive the iterator. This is the method a `for` loop finds. The order is the table's, which is the seed's. Nothing may be inserted or removed while the iterator is alive. **Returns**: a cursor over the elements, in an order the seed decides [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/HashSet.rux#L175){rel=""nofollow""} ### `IntoIterator` ```rux pub func IntoIterator(self: HashSet<T>) -> HashSetIntoIterator<T> ``` Takes the set apart into an iterator over its elements. Consumes the set: it is moved into the iterator, and the storage goes with it. Whatever is not taken is destroyed when the iterator's life ends. **Returns**: a cursor that consumes the set as it goes [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/HashSet.rux#L189){rel=""nofollow""} ### `IsSubsetOf` ```rux pub func IsSubsetOf( self: &HashSet<T>, other: &HashSet<T> ) -> bool ``` Whether every element of this set is also in `other`. Both are borrowed. A set is a subset of itself, and the empty set is a subset of everything — there is no element of it to be missing. `other` is asked about each of this set's elements, so it decides identity: two sets with different hashes for the same values would disagree, which is a caller error rather than something checkable here. Allocates nothing. Runs in time proportional to this set's size. | Name | Type | Description | | ------- | ------------- | ----------------------------------------- | | `other` | `&HashSet<T>` | the collection to compare or combine with | **Returns**: whether every element of this set is in `other` [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/HashSet.rux#L222){rel=""nofollow""} ### `IsSupersetOf` ```rux pub func IsSupersetOf( self: &HashSet<T>, other: &HashSet<T> ) -> bool ``` Whether every element of `other` is also in this set. Both are borrowed. The mirror of [`IsSubsetOf`](https://rux-lang.dev/docs/api/collections/hash-set#is-subset-of), which is what it calls. | Name | Type | Description | | ------- | ------------- | ----------------------------------------- | | `other` | `&HashSet<T>` | the collection to compare or combine with | **Returns**: whether every element of `other` is in this set [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/HashSet.rux#L244){rel=""nofollow""} ### `IsDisjointFrom` ```rux pub func IsDisjointFrom( self: &HashSet<T>, other: &HashSet<T> ) -> bool ``` Whether the two sets have no element in common. Both are borrowed. Two empty sets are disjoint, and so is any set with an empty one. Walks the smaller of the two, since an element of either that is in both would be found from whichever side it is looked for. Allocates nothing. | Name | Type | Description | | ------- | ------------- | ----------------------------------------- | | `other` | `&HashSet<T>` | the collection to compare or combine with | **Returns**: whether the two share no element [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/HashSet.rux#L256){rel=""nofollow""} ### `Equals` ```rux pub func Equals( self: &HashSet<T>, other: &HashSet<T> ) -> bool ``` Whether the two sets hold exactly the same elements. Both are borrowed. Equal sizes and one containment, which together are containment both ways. | Name | Type | Description | | ------- | ------------- | ----------------------------------------- | | `other` | `&HashSet<T>` | the collection to compare or combine with | **Returns**: whether both hold exactly the same elements [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/HashSet.rux#L279){rel=""nofollow""} ### `UnionWith` ```rux pub func UnionWith( self: &var HashSet<T>, other: &HashSet<T> ) -> ! CollectionError ``` Adds every element of `other` that this set does not already have. `self` is borrowed mutably; `other` is borrowed and left alone. Elements are copied out of `other`, which is what makes this usable only where copying an element means what it says. Room for the worst case is taken first, so this either adds every element or none: a failure part-way would leave a set that is neither what it was nor the union, and there is nothing useful a caller could do with that. Reserving more than it needs is the price, and it is given back by [`ShrinkToFit`](https://rux-lang.dev/docs/api/collections/hash-set#shrink-to-fit). Runs in time proportional to `other`. | Name | Type | Description | | ------- | ------------- | ----------------------------------------- | | `other` | `&HashSet<T>` | the collection to compare or combine with | **Returns**: nothing when the operation succeeded, or why it did not [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/HashSet.rux#L293){rel=""nofollow""} ### `IntersectWith` ```rux pub func IntersectWith( self: &var HashSet<T>, other: &HashSet<T> ) ``` Removes every element this set has that `other` does not. `self` is borrowed mutably; `other` is borrowed and left alone. Whatever leaves is destroyed, since nobody asked for it back. Allocates nothing, so it cannot fail: a set only ever gets smaller here. | Name | Type | Description | | ------- | ------------- | ----------------------------------------- | | `other` | `&HashSet<T>` | the collection to compare or combine with | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/HashSet.rux#L318){rel=""nofollow""} ### `Subtract` ```rux pub func Subtract(self: &var HashSet<T>, other: &HashSet<T>) ``` Removes every element this set has that `other` also has. `self` is borrowed mutably; `other` is borrowed and left alone. Whatever leaves is destroyed. Allocates nothing, so it cannot fail. | Name | Type | Description | | ------- | ------------- | ----------------------------------------- | | `other` | `&HashSet<T>` | the collection to compare or combine with | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/HashSet.rux#L347){rel=""nofollow""} ### `SymmetricDifferenceWith` ```rux pub func SymmetricDifferenceWith( self: &var HashSet<T>, other: &HashSet<T> ) -> ! CollectionError ``` Keeps the elements that are in exactly one of the two sets. `self` is borrowed mutably; `other` is borrowed and left alone. Elements shared by both leave and are destroyed; elements only `other` has are copied in. Room for the worst case is taken first, for the same reason [`UnionWith`](https://rux-lang.dev/docs/api/collections/hash-set#union-with) takes it: a failure part-way would leave a set that is neither operand nor the answer. | Name | Type | Description | | ------- | ------------- | ----------------------------------------- | | `other` | `&HashSet<T>` | the collection to compare or combine with | **Returns**: nothing when the operation succeeded, or why it did not [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/HashSet.rux#L375){rel=""nofollow""} ### `Clone` ```rux pub func Clone(self: &HashSet<T>) -> HashSet<T> ! CollectionError ``` An independent set holding a copy of every element of this one. `self` is borrowed and left alone. The copy has its own storage from the same allocator and the same seed, so the two lay their elements out alike. **Returns**: an independent copy [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/HashSet.rux#L408){rel=""nofollow""} ## Related ### `HashSetIterator<T>` ```rux pub struct HashSetIterator<T> { // private fields } ``` An iterator over the elements of a set, by copy. Borrows the set, so the set must outlive it and must not be inserted into or removed from while it is alive. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/HashSet.rux#L431){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | ---------------- | | `T` | the element type | **Implements Iterator** `HashSetIterator<T>` conforms to `Iterator`. #### `Next` ```rux pub func Next(self: &var HashSetIterator<T>) -> T? ``` The next element, or `none` once every slot has been looked at. `self` is borrowed mutably and advanced. The element is a copy; a set of things that own something is walked with [`TryNext`](https://rux-lang.dev/docs/api/collections/hash-set#try-next) instead. **Returns**: the next element, or `none` at the end [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/HashSet.rux#L446){rel=""nofollow""} ### `HashSetIntoIterator<T>` ```rux pub struct HashSetIntoIterator<T> { // private fields } ``` An iterator that takes a set apart, yielding each element by value. Move-only: it owns the storage the set owned. Whatever is left when its life ends is destroyed with it. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/HashSet.rux#L464){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | ---------------- | | `T` | the element type | **Implements Iterator** `HashSetIntoIterator<T>` conforms to `Iterator`. #### `Next` ```rux pub func Next(self: &var HashSetIntoIterator<T>) -> T? ``` The next element, moved out, or `none` once every slot has been looked at. `self` is borrowed mutably and advanced. The slot is emptied as the element leaves, so what remains for the destructor is exactly what nobody took. **Returns**: the next element, or `none` at the end [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/HashSet.rux#L482){rel=""nofollow""} ### `WriteHashSetDebug<T>` ```rux pub func WriteHashSetDebug<T: Debug>( writer: &var TextWriter, value: &HashSet<T>, spec: FormatSpec ) -> ! FormatError ``` Writes a borrowed hash set as `{first, second, third}`. An empty set is `{}`. The order is the table's and carries the same warning as a hash map's: it follows from the seed and from what the set has been through, so it is not the insertion order and does not hold between runs. [`TreeSet`](https://rux-lang.dev/docs/api/collections/tree-set) is the ordered one. Every element is shown through a borrow of it, and `spec` is handed to each unchanged. Reports whatever the writer or an element's implementation reported, stopping at the first refusal. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/Presentation.rux#L159){rel=""nofollow""} **Type parameters** | Name | Description | | ---------- | ---------------------------------------------------- | | `T: Debug` | the element type, which must know how to show itself | **Parameters** | Name | Type | Description | | -------- | ----------------- | -------------------------------------- | | `writer` | `&var TextWriter` | the destination | | `value` | `&HashSet<T>` | the set to show, borrowed for the call | | `spec` | `FormatSpec` | what to show each element under | **Returns**: success when the whole rendering was accepted # Slice iterators The iterators an array, vector or deque hands out to walk its elements by copy or by pointer. ## `ValueIterator<T>` ```rux pub struct ValueIterator<T> { // private fields } ``` An iterator that yields each element of a run by copy. The element type must be copyable: a move-only element yielded by value would leave the container holding something it no longer owns. Use [`ReferenceIterator`](https://rux-lang.dev/docs/api/collections/iterators#reference-iterator) for those. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/Iteration.rux#L23){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | ---------------- | | `T` | the element type | **Constructors** ### `ValueIterator` ```rux pub func ValueIterator(items: T[..]) -> ValueIterator<T> ``` An iterator over `items`, positioned before the first element. `items` is borrowed and must outlive the iterator. Cannot fail. Runs in constant time and allocates nothing. The storage must not be grown, freed or otherwise moved while this is alive. | Name | Type | Description | | ------- | ------- | -------------------- | | `items` | `T[..]` | the elements to take | **Returns**: a cursor yielding copies of those elements [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/Iteration.rux#L40){rel=""nofollow""} **Implements Iterator** `ValueIterator<T>` conforms to `Iterator`. ### `Next` ```rux pub func Next(self: &var ValueIterator<T>) -> T? ``` The next element, or `none` once the run is exhausted. `self` is borrowed mutably and advanced. An exhausted iterator keeps reporting `none`. Cannot fail. Runs in constant time and allocates nothing. **Returns**: the next element, or `none` at the end [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/Iteration.rux#L51){rel=""nofollow""} ## `ReferenceIterator<T>` ```rux pub struct ReferenceIterator<T> { // private fields } ``` An iterator that yields a pointer to each element of a run. Works for any element type, including one that owns something and may not be copied: the pointer borrows the element where it sits rather than taking it. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/Iteration.rux#L64){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | ---------------- | | `T` | the element type | **Constructors** ### `ReferenceIterator` ```rux pub func ReferenceIterator(items: T[..]) -> ReferenceIterator<T> ``` An iterator over `items`, positioned before the first element. `items` is borrowed and must outlive the iterator. Cannot fail. Runs in constant time and allocates nothing. Every pointer this yields points into the storage, so the storage must not be grown, freed or moved while this or any pointer it yielded is still in use. | Name | Type | Description | | ------- | ------- | -------------------- | | `items` | `T[..]` | the elements to take | **Returns**: a cursor yielding those elements' addresses [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/Iteration.rux#L82){rel=""nofollow""} **Implements Iterator** `ReferenceIterator<T>` conforms to `Iterator`. ### `Next` ```rux pub func Next(self: &var ReferenceIterator<T>) -> (*T)? ``` A pointer to the next element, or `none` once the run is exhausted. `self` is borrowed mutably and advanced. The pointer borrows the element and takes ownership of nothing. Cannot fail. Runs in constant time and allocates nothing. **Returns**: the next element, or `none` at the end [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/Iteration.rux#L93){rel=""nofollow""} ## `MutableReferenceIterator<T>` ```rux pub struct MutableReferenceIterator<T> { // private fields } ``` An iterator that yields a writable pointer to each element of a run. Elements remain in their storage, so move-only elements can be modified without copying or moving them. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/Iteration.rux#L105){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | ---------------- | | `T` | the element type | **Constructors** ### `MutableReferenceIterator` ```rux pub func MutableReferenceIterator(items: var T[..]) -> MutableReferenceIterator<T> ``` An iterator over `items`, positioned before the first element. Cannot fail. Runs in constant time and allocates nothing. The storage must outlive the iterator and every pointer it yields. Do not grow, shrink, free, or move the storage while any of them is in use. Coordinate access through aliases to the same elements. | Name | Type | Description | | ------- | ----------- | ---------------------------------- | | `items` | `var T[..]` | the elements to borrow for writing | **Returns**: a cursor yielding writable addresses [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/Iteration.rux#L122){rel=""nofollow""} **Implements Iterator** `MutableReferenceIterator<T>` conforms to `Iterator`. ### `Next` ```rux pub func Next(self: &var MutableReferenceIterator<T>) -> (*var T)? ``` The next writable element pointer, or `none` once exhausted. Advances the cursor without copying, moving, or destroying an element. An exhausted cursor stays exhausted. Cannot fail. Runs in constant time and allocates nothing. **Returns**: the next element's address, or `none` at the end [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/Iteration.rux#L133){rel=""nofollow""} # KeyValue\<K, V> One entry of a map, as a value a caller can hold. ```rux pub struct KeyValue<K, V> { pub key: K; pub value: V; } ``` What a walk yields and what a consuming iteration hands back. Two fields rather than a pair, because `entry.key` says which is which and `entry.0` does not. ## Type parameters | Name | Description | | ---- | -------------- | | `K` | the key type | | `V` | the value type | ## Fields | Name | Type | Description | | ------- | ---- | ----------------------------------- | | `key` | `K` | The key the entry was stored under. | | `value` | `V` | The value stored under it. | # LruCache\<K, V> A map that holds at most `capacity` entries and evicts the least recently used. ```rux pub struct LruCache<K, V> { // private fields } ``` Move-only. ## Type parameters | Name | Description | | ---- | -------------------------------------------------------- | | `K` | the key type, which the hash and equality functions take | | `V` | the value type | ## Constructors ### `LruCache` ```rux pub func LruCache( allocator: Allocator, capacity: uint, hash: func(K, uint64, uint64) -> uint64, equals: func(K, K) -> bool ) -> LruCache<K, V> ``` An empty cache that holds at most `capacity` entries, at least one. | Name | Type | Description | | ----------- | ----------------------------------- | ------------------------------------------------------ | | `allocator` | `Allocator` | where the storage comes from | | `capacity` | `uint` | how many entries it keeps | | `hash` | `func(K, uint64, uint64) -> uint64` | how a key is hashed, taking the key and two seed words | | `equals` | `func(K, K) -> bool` | whether two keys are the same | **Returns**: the cache [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/LruCache.rux#L42){rel=""nofollow""} ## Methods ### `Length` ```rux pub func Length(self: &LruCache<K, V>) -> uint ``` How many entries it holds. **Returns**: the count [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/LruCache.rux#L56){rel=""nofollow""} ### `Capacity` ```rux pub func Capacity(self: &LruCache<K, V>) -> uint ``` How many entries it keeps before evicting. **Returns**: the capacity [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/LruCache.rux#L63){rel=""nofollow""} ### `Contains` ```rux pub func Contains(self: &LruCache<K, V>, key: K) -> bool ``` Whether `key` has an entry, without counting as a use. | Name | Type | Description | | ----- | ---- | ----------- | | `key` | `K` | the key | **Returns**: whether it is cached [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/LruCache.rux#L71){rel=""nofollow""} ### `Get` ```rux pub func Get(self: &var LruCache<K, V>, key: K) -> V? ``` A copy of the value for `key`, which becomes the most recently used. | Name | Type | Description | | ----- | ---- | ----------- | | `key` | `K` | the key | **Returns**: the value, or `none` when it is not cached [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/LruCache.rux#L98){rel=""nofollow""} ### `Peek` ```rux pub func Peek(self: &LruCache<K, V>, key: K) -> V? ``` A copy of the value for `key`, without counting as a use. | Name | Type | Description | | ----- | ---- | ----------- | | `key` | `K` | the key | **Returns**: the value, or `none` when it is not cached [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/LruCache.rux#L111){rel=""nofollow""} ### `Put` ```rux pub func Put( self: &var LruCache<K, V>, key: K, value: V ) -> K? ! CollectionError ``` Caches `value` for `key` as the most recently used, replacing its value if it has one, and evicting the least recently used entry when the cache is full. | Name | Type | Description | | ------- | ---- | ----------- | | `key` | `K` | the key | | `value` | `V` | the value | **Returns**: the key that was evicted, if one was, or why there was no room [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/LruCache.rux#L122){rel=""nofollow""} ### `Remove` ```rux pub func Remove(self: &var LruCache<K, V>, key: K) -> V? ``` Takes the entry for `key` out of the cache. | Name | Type | Description | | ----- | ---- | ----------- | | `key` | `K` | the key | **Returns**: its value, or `none` when it was not cached [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/LruCache.rux#L162){rel=""nofollow""} ### `Clear` ```rux pub func Clear(self: &var LruCache<K, V>) ``` Forgets every entry, keeping the storage. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/LruCache.rux#L183){rel=""nofollow""} ### `KeysByRecency` ```rux pub func KeysByRecency( self: &LruCache<K, V>, into: var K[..] ) -> uint ``` The keys from the most to the least recently used. | Name | Type | Description | | ------ | ----------- | ----------------------------------------------- | | `into` | `var K[..]` | receives the keys in that order, as many as fit | **Returns**: how many were written [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/LruCache.rux#L194){rel=""nofollow""} # PriorityQueue\<T> A max-priority queue over a binary heap. ```rux pub struct PriorityQueue<T> { // private fields } ``` Move-only: it owns its elements. ## Type parameters | Name | Description | | ---- | --------------------------------- | | `T` | the element type, which needs `<` | ## Constructors ### `PriorityQueue` ```rux pub func PriorityQueue(allocator: Allocator) -> PriorityQueue<T> ``` An empty queue that has not allocated anything. | Name | Type | Description | | ----------- | ----------- | ---------------------------- | | `allocator` | `Allocator` | where the storage comes from | **Returns**: the queue [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/PriorityQueue.rux#L25){rel=""nofollow""} ## Methods ### `Length` ```rux pub func Length(self: &PriorityQueue<T>) -> uint ``` How many elements it holds. **Returns**: the count [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/PriorityQueue.rux#L32){rel=""nofollow""} ### `IsEmpty` ```rux pub func IsEmpty(self: &PriorityQueue<T>) -> bool ``` Whether it holds nothing. **Returns**: whether it is empty [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/PriorityQueue.rux#L39){rel=""nofollow""} ### `Push` ```rux pub func Push( self: &var PriorityQueue<T>, value: T ) -> ! CollectionError ``` Adds `value`, moving it in. Logarithmic time, amortized over the vector's growth. | Name | Type | Description | | ------- | ---- | ----------- | | `value` | `T` | the element | **Returns**: nothing, or why there was no room; the queue is unchanged on failure [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/PriorityQueue.rux#L47){rel=""nofollow""} ### `Peek` ```rux pub func Peek(self: &PriorityQueue<T>) -> (*T)? ``` The largest element, without taking it out. **Returns**: a pointer to it, valid until the queue next changes, or `none` when the queue is empty [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/PriorityQueue.rux#L62){rel=""nofollow""} ### `Pop` ```rux pub func Pop(self: &var PriorityQueue<T>) -> T? ``` Takes the largest element out. Logarithmic time. **Returns**: the element, or `none` when the queue is empty [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/PriorityQueue.rux#L69){rel=""nofollow""} ### `Clear` ```rux pub func Clear(self: &var PriorityQueue<T>) ``` Destroys every element, keeping the storage. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/PriorityQueue.rux#L91){rel=""nofollow""} ### `AsSlice` ```rux pub func AsSlice(self: &PriorityQueue<T>) -> T[..] ``` The elements in heap order: the largest first, the rest in no useful order. **Returns**: a view of them, valid until the queue next changes [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/PriorityQueue.rux#L98){rel=""nofollow""} # SmallVector\<T> A growable sequence that holds up to 64 bytes of elements without allocating. ```rux pub struct SmallVector<T> { // private fields } ``` Move-only: it owns its elements. ## Type parameters | Name | Description | | ---- | ---------------- | | `T` | the element type | ## Constructors ### `SmallVector` ```rux pub func SmallVector(allocator: Allocator) -> SmallVector<T> ``` An empty vector, holding its first elements inline. | Name | Type | Description | | ----------- | ----------- | ------------------------------------------------- | | `allocator` | `Allocator` | where the storage comes from once they outgrow it | **Returns**: the vector [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/SmallVector.rux#L37){rel=""nofollow""} ## Methods ### `InlineCapacity` ```rux pub func InlineCapacity(self: &SmallVector<T>) -> uint ``` How many elements fit inline: 64 bytes' worth, or none for an element larger than that or aligned to more than eight. **Returns**: the inline capacity [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/SmallVector.rux#L51){rel=""nofollow""} ### `IsInline` ```rux pub func IsInline(self: &SmallVector<T>) -> bool ``` Whether the elements are still inline, with nothing allocated. **Returns**: whether it is inline [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/SmallVector.rux#L60){rel=""nofollow""} ### `Length` ```rux pub func Length(self: &SmallVector<T>) -> uint ``` How many elements it holds. **Returns**: the count [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/SmallVector.rux#L67){rel=""nofollow""} ### `IsEmpty` ```rux pub func IsEmpty(self: &SmallVector<T>) -> bool ``` Whether it holds nothing. **Returns**: whether it is empty [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/SmallVector.rux#L74){rel=""nofollow""} ### `Capacity` ```rux pub func Capacity(self: &SmallVector<T>) -> uint ``` How many elements fit before the next allocation. **Returns**: the capacity [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/SmallVector.rux#L81){rel=""nofollow""} ### `Push` ```rux pub func Push( self: &var SmallVector<T>, value: T ) -> ! CollectionError ``` Appends `value`, moving it in, and allocating only once the inline room is full. | Name | Type | Description | | ------- | ---- | ----------- | | `value` | `T` | the element | **Returns**: nothing, or why there was no room; the vector is unchanged on failure [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/SmallVector.rux#L115){rel=""nofollow""} ### `TryPop` ```rux pub func TryPop( self: &var SmallVector<T>, value: *var T ) -> bool ``` Takes the last element out. | Name | Type | Description | | ------- | -------- | -------------------- | | `value` | `*var T` | receives the element | **Returns**: whether there was one [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/SmallVector.rux#L126){rel=""nofollow""} ### `Get` ```rux pub func Get(self: &SmallVector<T>, index: uint) -> T? ``` A copy of the element at `index`. | Name | Type | Description | | ------- | ------ | ----------- | | `index` | `uint` | which one | **Returns**: the element, or `none` past the end [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/SmallVector.rux#L138){rel=""nofollow""} ### `AsSlice` ```rux pub func AsSlice(self: &SmallVector<T>) -> T[..] ``` The elements, valid until the vector next changes or moves. **Returns**: a view of them [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/SmallVector.rux#L147){rel=""nofollow""} ### `AsMutableSlice` ```rux pub func AsMutableSlice(self: &var SmallVector<T>) -> var T[..] ``` The elements, writable, valid until the vector next changes or moves. **Returns**: a view of them [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/SmallVector.rux#L155){rel=""nofollow""} ### `Truncate` ```rux pub func Truncate(self: &var SmallVector<T>, length: uint) ``` Destroys the elements past `length`, keeping the storage. | Name | Type | Description | | -------- | ------ | ---------------- | | `length` | `uint` | how many to keep | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/SmallVector.rux#L163){rel=""nofollow""} ### `Clear` ```rux pub func Clear(self: &var SmallVector<T>) ``` Destroys every element, keeping the storage. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/SmallVector.rux#L176){rel=""nofollow""} ## Destructor ```rux func ~SmallVector(self: &var SmallVector<T>) ``` [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/SmallVector.rux#L180){rel=""nofollow""} # Table\<K, V> The open-addressing table [`HashMap`](https://rux-lang.dev/docs/api/collections/hash-map) and [`HashSet`](https://rux-lang.dev/docs/api/collections/hash-set) are both built on. ```rux pub struct Table<K, V> { // private fields } ``` Holds keys, values, one distance byte and one hash tag per slot in four parallel runs. A set instantiates the value type with something that occupies nothing worth reading, which is what lets one kernel serve both. Move-only: it owns its storage and entries, prohibits copying, and destroys both with [`~Table`](https://rux-lang.dev/docs/api/collections/table#destructor). ## Type parameters | Name | Description | | ---- | -------------- | | `K` | the key type | | `V` | the value type | ## Constructors ### `Table` ```rux pub func Table( allocator: Allocator, seed: TableSeed ) -> Table<K, V> ``` An empty table that has not allocated anything. `allocator` is borrowed for the call and kept; `seed` is read by value. Costs nothing: a table nothing is put into never allocates. | Name | Type | Description | | ----------- | ----------- | ----------------------------------------------------------------- | | `allocator` | `Allocator` | where the storage comes from | | `seed` | `TableSeed` | the two words that key the hash, which decide the iteration order | **Returns**: an empty table that has taken no storage yet [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/Table.rux#L125){rel=""nofollow""} ## Associated functions ### `CapacityFor` ```rux pub func CapacityFor(length: uint) -> uint ! CollectionError ``` The smallest power-of-two capacity that holds `length` entries without passing the three-quarter load factor. `length` is read by value. Derived from the entry count rather than from the current capacity, so one rule covers growing and settling alike. | Name | Type | Description | | -------- | ------ | ----------------- | | `length` | `uint` | how many elements | **Returns**: the table size that holds that many entries, or `CapacityOverflow` when there is none [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/Table.rux#L315){rel=""nofollow""} ## Methods ### `Length` ```rux pub func Length(self: &Table<K, V>) -> uint ``` How many entries the table holds. `self` is borrowed. **Returns**: how many entries it holds [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/Table.rux#L142){rel=""nofollow""} ### `Capacity` ```rux pub func Capacity(self: &Table<K, V>) -> uint ``` How many slots the table has. `self` is borrowed. A power of two, or zero. Not how many entries fit: the load factor keeps a quarter of them free, because a table run fuller than that spends its time displacing entries rather than storing them. **Returns**: how many slots it has [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/Table.rux#L151){rel=""nofollow""} ### `IsEmpty` ```rux pub func IsEmpty(self: &Table<K, V>) -> bool ``` Whether the table holds no entries. `self` is borrowed. **Returns**: whether it holds nothing [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/Table.rux#L159){rel=""nofollow""} ### `IsOccupied` ```rux pub func IsOccupied(self: &Table<K, V>, index: uint) -> bool ``` Whether the slot at `index` holds an entry. `self` is borrowed. This is what an iteration over the slots asks of each one. | Name | Type | Description | | ------- | ------ | ----------------------------- | | `index` | `uint` | which one, counting from zero | **Returns**: whether that slot holds an entry [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/Table.rux#L168){rel=""nofollow""} ### `Find` ```rux pub func Find( self: &Table<K, V>, key: K, hash: func(K, uint64, uint64) -> uint64, equals: func(K, K) -> bool ) -> uint? ``` The slot holding `key`, or `none` when the table does not have it. `self` is borrowed; `key` is read by value; `hash` and `equals` decide identity and must be the same pair the table was filled with. The seed is handed to `hash`, so a table's hashes are its own. Stops at the first slot whose occupant is closer to home than the search has travelled: the key would have displaced that occupant on its way past, so it cannot be further along. Runs in constant expected time and allocates nothing. | Name | Type | Description | | -------- | ----------------------------------- | ---------------------------------------------------------- | | `key` | `K` | the key to look up | | `hash` | `func(K, uint64, uint64) -> uint64` | how a key is hashed, taking the key and the two seed words | | `equals` | `func(K, K) -> bool` | whether two keys are the same | **Returns**: the slot the key belongs in, occupied or not [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/Table.rux#L193){rel=""nofollow""} ### `Rehash` ```rux pub func Rehash( self: &var Table<K, V>, capacity: uint, hash: func(K, uint64, uint64) -> uint64 ) -> ! CollectionError ``` Rebuilds the table at `capacity` slots, reinserting every entry. `self` is borrowed mutably; `hash` must be the one the table was filled with. A failure leaves the table exactly as it was: the new runs are taken and filled before the old ones are released. Runs in time proportional to the capacity. | Name | Type | Description | | ---------- | ----------------------------------- | ---------------------------------------------------------- | | `capacity` | `uint` | how many elements to make room for | | `hash` | `func(K, uint64, uint64) -> uint64` | how a key is hashed, taking the key and the two seed words | **Returns**: nothing when the operation succeeded, or why it did not [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/Table.rux#L335){rel=""nofollow""} ### `EnsureRoom` ```rux pub func EnsureRoom( self: &var Table<K, V>, hash: func(K, uint64, uint64) -> uint64 ) -> ! CollectionError ``` Makes sure one more entry will fit, growing the table when it will not. `self` is borrowed mutably; `hash` must be the one the table was filled with. | Name | Type | Description | | ------ | ----------------------------------- | ---------------------------------------------------------- | | `hash` | `func(K, uint64, uint64) -> uint64` | how a key is hashed, taking the key and the two seed words | **Returns**: nothing when the operation succeeded, or why it did not [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/Table.rux#L403){rel=""nofollow""} ### `Reserve` ```rux pub func Reserve( self: &var Table<K, V>, additional: uint, hash: func(K, uint64, uint64) -> uint64 ) -> ! CollectionError ``` Makes room for `additional` more entries on top of those already present. `self` is borrowed mutably; the length does not change. A failure leaves the table exactly as it was. | Name | Type | Description | | ------------ | ----------------------------------- | ---------------------------------------------------------- | | `additional` | `uint` | how many more elements to make room for | | `hash` | `func(K, uint64, uint64) -> uint64` | how a key is hashed, taking the key and the two seed words | **Returns**: nothing when the operation succeeded, or why it did not [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/Table.rux#L416){rel=""nofollow""} ### `ShrinkToFit` ```rux pub func ShrinkToFit( self: &var Table<K, V>, hash: func(K, uint64, uint64) -> uint64 ) -> ! CollectionError ``` Releases the capacity the entry count does not need. `self` is borrowed mutably. An empty table gives up its storage entirely. A failure leaves the table usable at its current capacity, since failing to hand memory back is never a reason to stop working. | Name | Type | Description | | ------ | ----------------------------------- | ---------------------------------------------------------- | | `hash` | `func(K, uint64, uint64) -> uint64` | how a key is hashed, taking the key and the two seed words | **Returns**: nothing when the operation succeeded, or why it did not [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/Table.rux#L430){rel=""nofollow""} ### `Clear` ```rux pub func Clear(self: &var Table<K, V>) ``` Destroys every entry, keeping the storage. `self` is borrowed mutably. Runs in time proportional to the capacity. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/Table.rux#L443){rel=""nofollow""} ## Destructor ```rux func ~Table(self: &var Table<K, V>) ``` Destroys every entry and releases the storage. Runs when the table's life ends. The entries go first and the runs second, since one destroyed after its storage was released would be read from freed memory. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/Table.rux#L477){rel=""nofollow""} ## Related ### `SlotEmpty` ```rux pub const SlotEmpty: uint8 = 0; ``` The state byte of a slot that has never held an entry, and does not now. Distances are stored one higher than they are, so zero can mean empty and nothing else has to. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/Table.rux#L33){rel=""nofollow""} ### `MaximumProbeDistance` ```rux pub const MaximumProbeDistance: uint = 254; ``` The furthest an entry may sit from home before the table gives up and grows. A byte holds the distance plus one, so 254 is what fits. Reaching it means the hash is doing nothing useful for these keys, and a table that grew would only spread the same collisions over more slots — so the insertion is refused rather than looped on. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/Table.rux#L40){rel=""nofollow""} ### `MinimumTableCapacity` ```rux pub const MinimumTableCapacity: uint = 8; ``` Eight slots is where a table starts. Below that the load factor rounds away to nothing useful. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/Table.rux#L45){rel=""nofollow""} # TableSeed A hash seed, drawn once and shared by every table that wants one. ```rux pub struct TableSeed { // private fields } ``` Two words, which is what `SipHash` takes as a key. Drawing one per table costs a system call each; a program making many should draw one and hand it to all of them, which is what this being a value rather than a hidden global is for. ## Associated functions ### `Random` ```rux pub func Random() -> TableSeed ``` A seed drawn from the operating system. Takes nothing. Falls back to a fixed pair of words when the system has no entropy to give, which keeps a table working on a system without a generator at the cost of the protection the seed exists for — a table keyed on adversarial input on such a system is as attackable as an unseeded one. Runs in constant time and allocates nothing. **Returns**: a seed drawn from the system, so two tables in one process iterate differently [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/Table.rux#L70){rel=""nofollow""} ### `Of` ```rux pub func Of(low: uint64, high: uint64) -> TableSeed ``` A seed with the words a caller chose. `low` and `high` are read by value. For a test that needs the same table twice, or a caller drawing one seed for many tables. | Name | Type | Description | | ------ | -------- | ------------------- | | `low` | `uint64` | the first seed word | | `high` | `uint64` | the second | **Returns**: a seed made of those two words, which makes the iteration order reproducible [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/Table.rux#L83){rel=""nofollow""} # Tree\<K, V> An ordered collection of entries, kept balanced by colouring. ```rux pub struct Tree<K, V> { pub root: *var TreeNode<K, V>; pub length: uint; // private fields } ``` Owns every node and everything in them, so it prohibits copying and destroys them with [`~Tree`](https://rux-lang.dev/docs/api/collections/tree#destructor). ## Type parameters | Name | Description | | ---- | -------------- | | `K` | the key type | | `V` | the value type | ## Fields | Name | Type | Description | | -------- | --------------------- | ---------------------------------------------------------- | | `root` | `*var TreeNode<K, V>` | The topmost node, or null for an empty tree. Always black. | | `length` | `uint` | How many nodes the tree holds. | ## Constructors ### `Tree` ```rux pub func Tree(allocator: Allocator) -> Tree<K, V> ``` An empty tree that has allocated nothing. `allocator` is borrowed for the call and kept for the tree's life. Cannot fail. Runs in constant time and allocates nothing. | Name | Type | Description | | ----------- | ----------- | ---------------------------- | | `allocator` | `Allocator` | where the storage comes from | **Returns**: an empty tree that has taken no storage yet [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/Tree.rux#L66){rel=""nofollow""} ## Associated functions ### `Minimum` ```rux pub func Minimum(from: *var TreeNode<K, V>) -> *var TreeNode<K, V> ``` The node holding the smallest key of the subtree at `from`, or null when `from` is null. Runs in time proportional to the height and allocates nothing. | Name | Type | Description | | ------ | --------------------- | --------------------- | | `from` | `*var TreeNode<K, V>` | the subtree to search | **Returns**: the leftmost node of that subtree, or null when it is empty [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/Tree.rux#L219){rel=""nofollow""} ### `Maximum` ```rux pub func Maximum(from: *var TreeNode<K, V>) -> *var TreeNode<K, V> ``` The node holding the largest key of the subtree at `from`, or null when `from` is null. Runs in time proportional to the height and allocates nothing. | Name | Type | Description | | ------ | --------------------- | --------------------- | | `from` | `*var TreeNode<K, V>` | the subtree to search | **Returns**: the rightmost node of that subtree, or null when it is empty [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/Tree.rux#L232){rel=""nofollow""} ### `Successor` ```rux pub func Successor(node: *var TreeNode<K, V>) -> *var TreeNode<K, V> ``` The node holding the next key after `node`'s, or null when `node` holds the largest or is itself null. Descends into the right subtree where there is one, and otherwise climbs past every ancestor `node` is the right child of — arriving at the first ancestor reached from the left, whose key is the next one up. Runs in time proportional to the height for a single step, but a walk of the whole tree by successor is linear in the length: every edge is crossed exactly twice across the walk. Allocates nothing. | Name | Type | Description | | ------ | --------------------- | ------------------ | | `node` | `*var TreeNode<K, V>` | the node to act on | **Returns**: the node with the next key in order, or null after the last [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/Tree.rux#L248){rel=""nofollow""} ### `Predecessor` ```rux pub func Predecessor(node: *var TreeNode<K, V>) -> *var TreeNode<K, V> ``` The node holding the key before `node`'s, or null when `node` holds the smallest or is itself null. The mirror of [`Successor`](https://rux-lang.dev/docs/api/collections/tree#successor), with the same costs. | Name | Type | Description | | ------ | --------------------- | ------------------ | | `node` | `*var TreeNode<K, V>` | the node to act on | **Returns**: the node with the previous key in order, or null before the first [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/Tree.rux#L265){rel=""nofollow""} ## Methods ### `Length` ```rux pub func Length(self: &Tree<K, V>) -> uint ``` How many entries the tree holds. `self` is borrowed. Cannot fail; runs in constant time and allocates nothing. **Returns**: how many nodes it holds [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/Tree.rux#L74){rel=""nofollow""} ### `IsEmpty` ```rux pub func IsEmpty(self: &Tree<K, V>) -> bool ``` Whether the tree holds no entries. `self` is borrowed. Cannot fail; runs in constant time and allocates nothing. **Returns**: whether it holds nothing [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/Tree.rux#L82){rel=""nofollow""} ### `Find` ```rux pub func Find( self: &Tree<K, V>, key: K, compare: func(K, K) -> Ordering ) -> *var TreeNode<K, V> ``` The node holding `key`, or null when the tree does not have it. `self` is borrowed. `compare` must impose the same order every call, and the same one every earlier insertion used — a tree searched by a different order than it was built with misses entries it holds. Runs in time proportional to the height, which the colouring holds to at most twice the logarithm of the length. Allocates nothing. | Name | Type | Description | | --------- | ------------------------ | ------------------------------------- | | `key` | `K` | the key to look up | | `compare` | `func(K, K) -> Ordering` | how two keys order against each other | **Returns**: the node with that key, or null when it is absent [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/Tree.rux#L150){rel=""nofollow""} ### `Above` ```rux pub func Above( self: &Tree<K, V>, key: K, compare: func(K, K) -> Ordering ) -> *var TreeNode<K, V> ``` The node holding the smallest key strictly above `key`, or null when no key is above it. `key` need not be in the tree. The descent keeps the last node it passed on the high side, which is the answer wherever it ends: once it has gone left of a key, nothing further down is larger than that key. This is what lets a walk survive removing what it is standing on. [`Successor`](https://rux-lang.dev/docs/api/collections/tree#successor) needs its node still linked into the tree, and removal relinks nodes around it; asking by key instead needs nothing to have stayed put, at the price of a descent per step rather than an edge. Runs in time proportional to the height and allocates nothing. | Name | Type | Description | | --------- | ------------------------ | ------------------------------------- | | `key` | `K` | the key to look up | | `compare` | `func(K, K) -> Ordering` | how two keys order against each other | **Returns**: the node with the smallest key above this one, or null [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/Tree.rux#L178){rel=""nofollow""} ### `Below` ```rux pub func Below( self: &Tree<K, V>, key: K, compare: func(K, K) -> Ordering ) -> *var TreeNode<K, V> ``` The node holding the largest key strictly below `key`, or null when no key is below it. The mirror of [`Above`](https://rux-lang.dev/docs/api/collections/tree#above), with the same costs and the same use. | Name | Type | Description | | --------- | ------------------------ | ------------------------------------- | | `key` | `K` | the key to look up | | `compare` | `func(K, K) -> Ordering` | how two keys order against each other | **Returns**: the node with the largest key below this one, or null [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/Tree.rux#L199){rel=""nofollow""} ### `Attach` ```rux pub func Attach( self: &var Tree<K, V>, key: K, value: V, compare: func(K, K) -> Ordering ) -> V? ! CollectionError ``` Puts `key` and `value` into the tree, replacing the value already stored under an equal key. Takes ownership of both. Hands back the value an equal key already had, or `none` when the key is new — so a caller learns whether anything was displaced without a lookup first, and gets the displaced value rather than having it quietly destroyed. When the key is already present the new key is destroyed rather than stored, since the one in the tree is equal to it and is what everything already hanging below it was ordered against. Reports `OutOfMemory` when the node cannot be allocated, having changed nothing — but `key` and `value` are destroyed rather than handed back, because there is nowhere left to put them. Runs in time proportional to the height, with at most two rotations. Allocates one node for a new key and nothing at all for one already present. | Name | Type | Description | | --------- | ------------------------ | ------------------------------------- | | `key` | `K` | the key to look up | | `value` | `V` | the value to act on | | `compare` | `func(K, K) -> Ordering` | how two keys order against each other | **Returns**: the value an equal key already held, or `none` when the key is new [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/Tree.rux#L346){rel=""nofollow""} ### `Detach` ```rux pub func Detach( self: &var Tree<K, V>, node: *var TreeNode<K, V> ) -> KeyValue<K, V> ``` Takes `node` out of the tree and hands back what it held. `node` must be a node of this tree, and is freed here — nothing may read through it afterwards. The key and value become the caller's, in the pair a hash map hands its entries back in. A node with two children is not emptied into: the successor is relinked in its place instead, so the entry that stays keeps the address it had and any pointer to it stays good. That is the whole reason the nodes are separate allocations, and it is why removal moves six pointers where copying two fields would do. Cannot fail. Runs in time proportional to the height, with at most three rotations, and allocates nothing. | Name | Type | Description | | ------ | --------------------- | ------------------ | | `node` | `*var TreeNode<K, V>` | the node to act on | **Returns**: the entry the node held [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/Tree.rux#L507){rel=""nofollow""} ### `Clear` ```rux pub func Clear(self: &var Tree<K, V>) ``` Destroys every entry and gives every node back to the allocator, leaving an empty tree. `self` is borrowed mutably and stays usable: entries may be attached again afterwards, and nothing has been kept back to make that cheaper, since a tree has no capacity to keep. Cannot fail. Runs in time proportional to the length and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/Tree.rux#L562){rel=""nofollow""} ## Destructor ```rux func ~Tree(self: &var Tree<K, V>) ``` Destroys every entry and gives every node back. Runs when the tree dies. Never called directly; a tree is move-only, so there is exactly one of these per tree however many times it was passed along. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/Tree.rux#L600){rel=""nofollow""} ## Related ### `TreeNode<K, V>` ```rux pub struct TreeNode<K, V> { pub key: K; pub value: V; pub left: *var TreeNode<K, V>; pub right: *var TreeNode<K, V>; pub parent: *var TreeNode<K, V>; pub red: bool; } ``` One node of a red-black tree. Its own allocation, so its address survives any rearrangement of the tree around it. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/Tree.rux#L27){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | -------------- | | `K` | the key type | | `V` | the value type | **Fields** | Name | Type | Description | | -------- | --------------------- | ----------------------------------------------------------------------------------------------------------- | | `key` | `K` | The key this node is ordered by. | | `value` | `V` | The value stored under that key. | | `left` | `*var TreeNode<K, V>` | The subtree of smaller keys, or null. | | `right` | `*var TreeNode<K, V>` | The subtree of larger keys, or null. | | `parent` | `*var TreeNode<K, V>` | The node this one hangs from, null only for the root. | | `red` | `bool` | Whether this node is red. A missing child counts as black, which is what makes null a colour and not a gap. | # TreeMap\<K, V> An ordered map from keys to values. ```rux pub struct TreeMap<K, V> { // private fields } ``` Move-only: it owns every node and everything in them. ## Type parameters | Name | Description | | ---- | -------------- | | `K` | the key type | | `V` | the value type | ## Constructors ### `TreeMap` ```rux pub func TreeMap( allocator: Allocator, compare: func(K, K) -> Ordering ) -> TreeMap<K, V> ``` An empty map ordered by `compare`, which has allocated nothing. `allocator` is borrowed for the call and kept for the map's life. `compare` must impose the same order every call; a map whose comparison changes under it loses entries it still holds. Cannot fail. Runs in constant time and allocates nothing. | Name | Type | Description | | ----------- | ------------------------ | ------------------------------------- | | `allocator` | `Allocator` | where the storage comes from | | `compare` | `func(K, K) -> Ordering` | how two keys order against each other | **Returns**: an empty collection that has taken no storage yet [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/TreeMap.rux#L38){rel=""nofollow""} ## Methods ### `Length` ```rux pub func Length(self: &TreeMap<K, V>) -> uint ``` How many entries the map holds. **Returns**: how many entries it holds [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/TreeMap.rux#L45){rel=""nofollow""} ### `IsEmpty` ```rux pub func IsEmpty(self: &TreeMap<K, V>) -> bool ``` Whether the map holds no entries. **Returns**: whether it holds nothing [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/TreeMap.rux#L52){rel=""nofollow""} ### `ContainsKey` ```rux pub func ContainsKey(self: &TreeMap<K, V>, key: K) -> bool ``` Whether `key` has a value in the map. Runs in time proportional to the height, which is at most twice the logarithm of the length. | Name | Type | Description | | ----- | ---- | ------------------ | | `key` | `K` | the key to look up | **Returns**: whether an entry with that key is present [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/TreeMap.rux#L61){rel=""nofollow""} ### `Get` ```rux pub func Get(self: &TreeMap<K, V>, key: K) -> V? ``` A copy of the value stored under `key`, or `none`. | Name | Type | Description | | ----- | ---- | ------------------ | | `key` | `K` | the key to look up | **Returns**: a copy of the value, or `none` when the key is absent [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/TreeMap.rux#L69){rel=""nofollow""} ### `Reference` ```rux pub func Reference(self: &TreeMap<K, V>, key: K) -> (*V)? ``` A borrow of the value stored under `key`, or `none`. The borrow stays valid while the map is untouched — and, unlike a hash map's, across insertions and removals of other keys too, since a node keeps its address while the tree is rearranged around it. It ends when this key is removed or the map dies. | Name | Type | Description | | ----- | ---- | ------------------ | | `key` | `K` | the key to look up | **Returns**: the address of the value, or `none` when the key is absent [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/TreeMap.rux#L82){rel=""nofollow""} ### `TryReferenceMutable` ```rux pub func TryReferenceMutable( self: &var TreeMap<K, V>, key: K, value: *var *var V ) -> bool ``` Points `value` at the value stored under `key` so it can be written through, and reports whether there was one. `value` is left untouched when this reports `false`. Two calls rather than an `(*var V)?` because an option of a writable pointer does not survive lowering; this is the same answer in the shape that does. | Name | Type | Description | | ------- | ------------- | ---------------------------------------- | | `key` | `K` | the key to look up | | `value` | `*var *var V` | receives the address of the stored value | **Returns**: whether the key was present [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/TreeMap.rux#L96){rel=""nofollow""} ### `Insert` ```rux pub func Insert( self: &var TreeMap<K, V>, key: K, value: V ) -> ! CollectionError ``` Stores `value` under `key`, replacing and destroying whatever was there. Takes ownership of both. Reports `OutOfMemory` when the node cannot be allocated, in which case the map is unchanged — but the key and the value are destroyed rather than handed back, since there is nowhere to put them. [`Replace`](https://rux-lang.dev/docs/api/collections/tree-map#replace) is the one to use when the displaced value is wanted. Runs in time proportional to the height, with at most two rotations, and allocates one node for a key that is new and nothing at all for one already there. | Name | Type | Description | | ------- | ---- | ------------------- | | `key` | `K` | the key to look up | | `value` | `V` | the value to act on | **Returns**: nothing when the operation succeeded, or why it did not [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/TreeMap.rux#L113){rel=""nofollow""} ### `Replace` ```rux pub func Replace( self: &var TreeMap<K, V>, key: K, value: V ) -> V? ! CollectionError ``` Stores `value` under `key` and hands back the value it displaced, or `none` for a key that was not there. A failure is reported apart from the absence, so "nothing was there" and "nothing was stored" never meet. | Name | Type | Description | | ------- | ---- | ------------------- | | `key` | `K` | the key to look up | | `value` | `V` | the value to act on | **Returns**: the value that was there, or `none` when the key was absent [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/TreeMap.rux#L124){rel=""nofollow""} ### `Remove` ```rux pub func Remove(self: &var TreeMap<K, V>, key: K) -> V? ``` Takes the entry stored under `key` out of the map and hands its value back, or `none`. Cannot fail. Runs in time proportional to the height, with at most three rotations, and allocates nothing. | Name | Type | Description | | ----- | ---- | ------------------ | | `key` | `K` | the key to look up | **Returns**: the value that was stored, or `none` when the key was absent [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/TreeMap.rux#L133){rel=""nofollow""} ### `RemoveEntry` ```rux pub func RemoveEntry( self: &var TreeMap<K, V>, key: K ) -> KeyValue<K, V>? ``` Takes the entry stored under `key` out and hands back the key as well as the value, or `none`. The key that comes back is the one the map was holding, which for a key type where equal is not identical is the one every entry below it was ordered against, not the one just passed in. | Name | Type | Description | | ----- | ---- | ------------------ | | `key` | `K` | the key to look up | **Returns**: the whole entry, or `none` when the key was absent [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/TreeMap.rux#L146){rel=""nofollow""} ### `Clear` ```rux pub func Clear(self: &var TreeMap<K, V>) ``` Destroys every entry, leaving an empty map that is still usable. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/TreeMap.rux#L155){rel=""nofollow""} ### `First` ```rux pub func First(self: &TreeMap<K, V>) -> KeyValue<K, V>? ``` The entry with the smallest key, or `none` for an empty map. Runs in time proportional to the height and allocates nothing. **Returns**: the entry with the smallest key, or `none` when empty [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/TreeMap.rux#L170){rel=""nofollow""} ### `Last` ```rux pub func Last(self: &TreeMap<K, V>) -> KeyValue<K, V>? ``` The entry with the largest key, or `none` for an empty map. **Returns**: the entry with the largest key, or `none` when empty [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/TreeMap.rux#L177){rel=""nofollow""} ### `Floor` ```rux pub func Floor( self: &TreeMap<K, V>, key: K ) -> KeyValue<K, V>? ``` The entry with the largest key at or below `key`, or `none` when every key is above it. The descent remembers the last node it passed on the low side, which is the answer wherever it ends: once it has gone right of a key, nothing further down is smaller than that key. Runs in time proportional to the height and allocates nothing. | Name | Type | Description | | ----- | ---- | ------------------ | | `key` | `K` | the key to look up | **Returns**: the entry with the largest key at or below `key`, or `none` [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/TreeMap.rux#L188){rel=""nofollow""} ### `Ceiling` ```rux pub func Ceiling( self: &TreeMap<K, V>, key: K ) -> KeyValue<K, V>? ``` The entry with the smallest key at or above `key`, or `none` when every key is below it. | Name | Type | Description | | ----- | ---- | ------------------ | | `key` | `K` | the key to look up | **Returns**: the entry with the smallest key at or above `key`, or `none` [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/TreeMap.rux#L209){rel=""nofollow""} ### `Iterate` ```rux pub func Iterate(self: &TreeMap<K, V>) -> TreeMapIterator<K, V> ``` A walk over this map, smallest key first, leaving it untouched. `self` is borrowed and must outlive the walk, which must not run across an insertion or a removal. **Returns**: a cursor over the entries in key order [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/TreeMap.rux#L230){rel=""nofollow""} ### `Range` ```rux pub func Range( self: &TreeMap<K, V>, start: K, end: K ) -> TreeMapRangeIterator<K, V> ``` A walk over the entries whose keys are at or above `start` and below `end`. Half-open, so `Range(a, b)` and `Range(b, c)` together give exactly `Range(a, c)` with nothing repeated and nothing missed. A range whose `end` is not above its `start` hands back nothing. Starting costs a descent rather than a walk from the smallest key, so a small range out of a large map is cheap. | Name | Type | Description | | ------- | ---- | ---------------------------------------- | | `start` | `K` | the first element, inclusive | | `end` | `K` | the element one past the last, exclusive | **Returns**: a cursor over the entries whose keys fall in `[start, end)` [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/TreeMap.rux#L243){rel=""nofollow""} ### `IntoIterator` ```rux pub func IntoIterator(self: TreeMap<K, V>) -> TreeMapIntoIterator<K, V> ``` A walk that consumes this map, smallest key first. Takes ownership; the map is gone afterwards. **Returns**: a cursor that consumes the map as it goes, in key order [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/TreeMap.rux#L267){rel=""nofollow""} ## Related ### `WriteTreeMapDebug<K, V>` ```rux pub func WriteTreeMapDebug<K: Debug, V: Debug>( writer: &var TextWriter, value: &TreeMap<K, V>, spec: FormatSpec ) -> ! FormatError ``` Writes a borrowed ordered map as `{key: value, key: value}`, in key order. An empty map is `{}`. The order is the map's own — the order `Iterate` walks, the order `First` and `Last` name the ends of — so two maps holding the same entries render identically and one map renders identically every time. That is what makes an ordered map's rendering usable in an assertion where a hash map's is not. The walk crosses every edge of the tree twice and allocates nothing, and nothing is taken out of the map: every key and value is shown through a borrow of the node holding it. `spec` is handed to each unchanged. Reports whatever the writer or an entry's implementation reported, stopping at the first refusal. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/Presentation.rux#L191){rel=""nofollow""} **Type parameters** | Name | Description | | ---------- | -------------------------------------------------- | | `K: Debug` | the key type, which must know how to show itself | | `V: Debug` | the value type, which must know how to show itself | **Parameters** | Name | Type | Description | | -------- | ----------------- | -------------------------------------- | | `writer` | `&var TextWriter` | the destination | | `value` | `&TreeMap<K, V>` | the map to show, borrowed for the call | | `spec` | `FormatSpec` | what to show each key and value under | **Returns**: success when the whole rendering was accepted ### `TreeMapIterator<K, V>` ```rux pub struct TreeMapIterator<K, V> { // private fields } ``` A walk over a borrowed map, smallest key first. Copies each entry out as it goes, so the map is untouched and keeps everything it holds. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/TreeMap.rux#L286){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | -------------- | | `K` | the key type | | `V` | the value type | **Methods** #### `Next` ```rux pub func Next(self: &var TreeMapIterator<K, V>) -> KeyValue<K, V>? ``` The next entry in key order, or `none` when there are no more. Runs in constant amortized time: every edge of the tree is crossed exactly twice across a whole walk. **Returns**: the next entry in key order, or `none` at the end [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/TreeMap.rux#L296){rel=""nofollow""} ### `TreeMapRangeIterator<K, V>` ```rux pub struct TreeMapRangeIterator<K, V> { // private fields } ``` A walk over a borrowed map that stops at a bound. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/TreeMap.rux#L308){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | -------------- | | `K` | the key type | | `V` | the value type | **Methods** #### `Next` ```rux pub func Next(self: &var TreeMapRangeIterator<K, V>) -> KeyValue<K, V>? ``` The next entry below the bound, or `none` once the walk reaches it. **Returns**: the next entry in key order, or `none` at the end [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/TreeMap.rux#L321){rel=""nofollow""} ### `TreeMapIntoIterator<K, V>` ```rux pub struct TreeMapIntoIterator<K, V> { // private fields } ``` A walk that consumes the map, smallest key first. Owns the nodes, and destroys whatever is left in them when it dies — so a walk stopped part-way destroys the rest exactly once, and nothing already handed out is destroyed twice. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/TreeMap.rux#L339){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | -------------- | | `K` | the key type | | `V` | the value type | **Methods** #### `Next` ```rux pub func Next(self: &var TreeMapIntoIterator<K, V>) -> KeyValue<K, V>? ``` The next entry in key order, or `none` when there are no more. Takes the smallest entry out of the tree rather than reading past it, which is what makes the entry the caller's and leaves the destructor with one less thing to do. Each step costs a removal, so a whole walk is linearithmic where the borrowed walk is linear — the price of handing out ownership one entry at a time. **Returns**: the next entry in key order, or `none` at the end [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/TreeMap.rux#L354){rel=""nofollow""} # TreeSet\<T> An ordered set of unique elements. ```rux pub struct TreeSet<T> { // private fields } ``` Move-only: it owns every node and every element in them. ## Type parameters | Name | Description | | ---- | ---------------- | | `T` | the element type | ## Constructors ### `TreeSet` ```rux pub func TreeSet( allocator: Allocator, compare: func(T, T) -> Ordering ) -> TreeSet<T> ``` An empty set ordered by `compare`, which has allocated nothing. `allocator` is borrowed for the call and kept for the set's life. `compare` must impose the same order every call; a set whose comparison changes under it loses elements it still holds. Cannot fail. Runs in constant time and allocates nothing. | Name | Type | Description | | ----------- | ------------------------ | ------------------------------------- | | `allocator` | `Allocator` | where the storage comes from | | `compare` | `func(T, T) -> Ordering` | how two keys order against each other | **Returns**: an empty collection that has taken no storage yet [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/TreeSet.rux#L45){rel=""nofollow""} ## Methods ### `Length` ```rux pub func Length(self: &TreeSet<T>) -> uint ``` How many elements the set holds. **Returns**: how many elements it holds [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/TreeSet.rux#L52){rel=""nofollow""} ### `IsEmpty` ```rux pub func IsEmpty(self: &TreeSet<T>) -> bool ``` Whether the set holds no elements. **Returns**: whether it holds nothing [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/TreeSet.rux#L59){rel=""nofollow""} ### `Contains` ```rux pub func Contains(self: &TreeSet<T>, value: T) -> bool ``` Whether `value` is in the set. Runs in time proportional to the height, which is at most twice the logarithm of the length. | Name | Type | Description | | ------- | ---- | ------------------- | | `value` | `T` | the value to act on | **Returns**: whether the value is present [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/TreeSet.rux#L68){rel=""nofollow""} ### `Insert` ```rux pub func Insert( self: &var TreeSet<T>, value: T ) -> bool ! CollectionError ``` Puts `value` into the set, and reports whether it was not already there. Takes ownership. An element equal to one already present is destroyed rather than stored, since the one in the set is equal to it and is what everything is already ordered against — so a set never grows past the number of distinct elements put into it. Reports `OutOfMemory` when the node cannot be allocated, having changed nothing. | Name | Type | Description | | ------- | ---- | ------------------- | | `value` | `T` | the value to act on | **Returns**: whether the value was new rather than already present [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/TreeSet.rux#L80){rel=""nofollow""} ### `Remove` ```rux pub func Remove(self: &var TreeSet<T>, value: T) -> bool ``` Takes `value` out of the set, reporting whether it was there. Cannot fail. Runs in time proportional to the height and allocates nothing. | Name | Type | Description | | ------- | ---- | ------------------- | | `value` | `T` | the value to act on | **Returns**: whether the value was there to remove [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/TreeSet.rux#L90){rel=""nofollow""} ### `Clear` ```rux pub func Clear(self: &var TreeSet<T>) ``` Destroys every element, leaving an empty set that is still usable. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/TreeSet.rux#L99){rel=""nofollow""} ### `First` ```rux pub func First(self: &TreeSet<T>) -> T? ``` The smallest element, or `none` for an empty set. Runs in time proportional to the height and allocates nothing. **Returns**: the smallest element, or `none` when empty [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/TreeSet.rux#L107){rel=""nofollow""} ### `Last` ```rux pub func Last(self: &TreeSet<T>) -> T? ``` The largest element, or `none` for an empty set. **Returns**: the largest element, or `none` when empty [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/TreeSet.rux#L114){rel=""nofollow""} ### `Floor` ```rux pub func Floor(self: &TreeSet<T>, value: T) -> T? ``` The largest element at or below `value`, or `none` when every element is above it. | Name | Type | Description | | ------- | ---- | ------------------- | | `value` | `T` | the value to act on | **Returns**: the largest element at or below `value`, or `none` [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/TreeSet.rux#L122){rel=""nofollow""} ### `Ceiling` ```rux pub func Ceiling(self: &TreeSet<T>, value: T) -> T? ``` The smallest element at or above `value`, or `none` when every element is below it. | Name | Type | Description | | ------- | ---- | ------------------- | | `value` | `T` | the value to act on | **Returns**: the smallest element at or above `value`, or `none` [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/TreeSet.rux#L132){rel=""nofollow""} ### `Iterate` ```rux pub func Iterate(self: &TreeSet<T>) -> TreeSetIterator<T> ``` A walk over this set, smallest element first, leaving it untouched. `self` is borrowed and must outlive the walk, which must not run across an insertion or a removal. **Returns**: a cursor over the elements in order [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/TreeSet.rux#L148){rel=""nofollow""} ### `Range` ```rux pub func Range( self: &TreeSet<T>, start: T, end: T ) -> TreeSetRangeIterator<T> ``` A walk over the elements at or above `start` and below `end`. Half-open, so `Range(a, b)` and `Range(b, c)` together give exactly `Range(a, c)` with nothing repeated and nothing missed. A range whose `end` is not above its `start` hands back nothing. | Name | Type | Description | | ------- | ---- | ---------------------------------------- | | `start` | `T` | the first element, inclusive | | `end` | `T` | the element one past the last, exclusive | **Returns**: a cursor over the elements that fall in `[start, end)` [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/TreeSet.rux#L159){rel=""nofollow""} ### `IntoIterator` ```rux pub func IntoIterator(self: TreeSet<T>) -> TreeSetIntoIterator<T> ``` A walk that consumes this set, smallest element first. Takes ownership; the set is gone afterwards. **Returns**: a cursor that consumes the set as it goes, in order [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/TreeSet.rux#L171){rel=""nofollow""} ### `IsSubsetOf` ```rux pub func IsSubsetOf( self: &TreeSet<T>, other: &TreeSet<T> ) -> bool ``` Whether every element of this set is in `other`. The empty set is a subset of everything, including itself. Allocates nothing and cannot fail. Runs in time proportional to this set's length times the logarithm of `other`'s. | Name | Type | Description | | ------- | ------------- | ----------------------------------------- | | `other` | `&TreeSet<T>` | the collection to compare or combine with | **Returns**: whether every element of this set is in `other` [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/TreeSet.rux#L190){rel=""nofollow""} ### `IsSupersetOf` ```rux pub func IsSupersetOf( self: &TreeSet<T>, other: &TreeSet<T> ) -> bool ``` Whether every element of `other` is in this set. | Name | Type | Description | | ------- | ------------- | ----------------------------------------- | | `other` | `&TreeSet<T>` | the collection to compare or combine with | **Returns**: whether every element of `other` is in this set [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/TreeSet.rux#L211){rel=""nofollow""} ### `IsDisjointFrom` ```rux pub func IsDisjointFrom( self: &TreeSet<T>, other: &TreeSet<T> ) -> bool ``` Whether the two sets share no element. The empty set is disjoint from everything, including itself. The smaller set is the one walked, since either walk gives the same answer and one of them is shorter. | Name | Type | Description | | ------- | ------------- | ----------------------------------------- | | `other` | `&TreeSet<T>` | the collection to compare or combine with | **Returns**: whether the two share no element [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/TreeSet.rux#L221){rel=""nofollow""} ### `Equals` ```rux pub func Equals( self: &TreeSet<T>, other: &TreeSet<T> ) -> bool ``` Whether the two sets hold exactly the same elements. Order is not part of the question — two sets are equal when each contains the other — but having an order makes the lengths enough to reject most pairs before looking at an element. | Name | Type | Description | | ------- | ------------- | ----------------------------------------- | | `other` | `&TreeSet<T>` | the collection to compare or combine with | **Returns**: whether both hold exactly the same elements [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/TreeSet.rux#L244){rel=""nofollow""} ### `UnionWith` ```rux pub func UnionWith( self: &var TreeSet<T>, other: &TreeSet<T> ) -> ! CollectionError ``` Adds every element of `other` that is not already here. Reports `OutOfMemory` if a node cannot be allocated, having added what it managed to before that — unlike the hash set's, which reserves the worst case first and is all-or-nothing. A tree has no capacity to reserve: every element is a separate allocation, so there is no point at which the whole operation can be paid for in advance. What it gives back instead is that a partial union is still a set with every invariant intact, and running the same call again finishes it. | Name | Type | Description | | ------- | ------------- | ----------------------------------------- | | `other` | `&TreeSet<T>` | the collection to compare or combine with | **Returns**: nothing when the operation succeeded, or why it did not [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/TreeSet.rux#L257){rel=""nofollow""} ### `IntersectWith` ```rux pub func IntersectWith( self: &var TreeSet<T>, other: &TreeSet<T> ) ``` Keeps only the elements that are also in `other`. Allocates nothing and cannot fail: a set only ever gets smaller here. The walk asks for the next element by key rather than by following a pointer, because removing relinks the nodes around what was removed — including, when it has two children, the very node a pointer walk would have been about to visit. A key survives that; a pointer does not. The price is a descent per element rather than an edge. | Name | Type | Description | | ------- | ------------- | ----------------------------------------- | | `other` | `&TreeSet<T>` | the collection to compare or combine with | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/TreeSet.rux#L281){rel=""nofollow""} ### `Subtract` ```rux pub func Subtract(self: &var TreeSet<T>, other: &TreeSet<T>) ``` Removes every element that is also in `other`. Allocates nothing and cannot fail, and walks the same way [`IntersectWith`](https://rux-lang.dev/docs/api/collections/tree-set#intersect-with) does and for the same reason. | Name | Type | Description | | ------- | ------------- | ----------------------------------------- | | `other` | `&TreeSet<T>` | the collection to compare or combine with | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/TreeSet.rux#L296){rel=""nofollow""} ### `SymmetricDifferenceWith` ```rux pub func SymmetricDifferenceWith( self: &var TreeSet<T>, other: &TreeSet<T> ) -> ! CollectionError ``` Keeps the elements that are in exactly one of the two sets. Reports `OutOfMemory` if a node cannot be allocated, having done what it managed to first. The removals and the additions cannot be interleaved: an element removed from this set would then look absent when `other`'s copy of it arrived, and be added straight back. So what is shared is taken out first, and only then is what is left of `other` put in. | Name | Type | Description | | ------- | ------------- | ----------------------------------------- | | `other` | `&TreeSet<T>` | the collection to compare or combine with | **Returns**: nothing when the operation succeeded, or why it did not [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/TreeSet.rux#L316){rel=""nofollow""} ### `Clone` ```rux pub func Clone(self: &TreeSet<T>) -> TreeSet<T> ! CollectionError ``` A set holding what this one holds, ordered the same way and allocating from the same allocator. A failed clone hands back nothing rather than half of a set. **Returns**: an independent copy [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/TreeSet.rux#L355){rel=""nofollow""} ## Related ### `WriteTreeSetDebug<T>` ```rux pub func WriteTreeSetDebug<T: Debug>( writer: &var TextWriter, value: &TreeSet<T>, spec: FormatSpec ) -> ! FormatError ``` Writes a borrowed ordered set as `{first, second, third}`, in order. An empty set is `{}`. The order is the set's own, so the rendering is stable between sets holding the same elements and between runs, unlike a hash set's. Every element is shown through a borrow of the node holding it, and `spec` is handed to each unchanged. Reports whatever the writer or an element's implementation reported, stopping at the first refusal. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/Presentation.rux#L220){rel=""nofollow""} **Type parameters** | Name | Description | | ---------- | ---------------------------------------------------- | | `T: Debug` | the element type, which must know how to show itself | **Parameters** | Name | Type | Description | | -------- | ----------------- | -------------------------------------- | | `writer` | `&var TextWriter` | the destination | | `value` | `&TreeSet<T>` | the set to show, borrowed for the call | | `spec` | `FormatSpec` | what to show each element under | **Returns**: success when the whole rendering was accepted ### `TreeSetIterator<T>` ```rux pub struct TreeSetIterator<T> { // private fields } ``` A walk over a borrowed set, smallest element first. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/TreeSet.rux#L365){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | ---------------- | | `T` | the element type | **Implements Iterator** `TreeSetIterator<T>` conforms to `Iterator`. #### `Next` ```rux pub func Next(self: &var TreeSetIterator<T>) -> T? ``` The next element in order, or `none` when there are no more. Runs in constant amortized time: a whole walk crosses every edge of the tree exactly twice. **Returns**: the next element in order, or `none` at the end [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/TreeSet.rux#L375){rel=""nofollow""} ### `TreeSetRangeIterator<T>` ```rux pub struct TreeSetRangeIterator<T> { // private fields } ``` A walk over a borrowed set that stops at a bound. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/TreeSet.rux#L386){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | ---------------- | | `T` | the element type | **Implements Iterator** `TreeSetRangeIterator<T>` conforms to `Iterator`. #### `Next` ```rux pub func Next(self: &var TreeSetRangeIterator<T>) -> T? ``` The next element below the bound, or `none` once the walk reaches it. **Returns**: the next element in order, or `none` at the end [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/TreeSet.rux#L399){rel=""nofollow""} ### `TreeSetIntoIterator<T>` ```rux pub struct TreeSetIntoIterator<T> { // private fields } ``` A walk that consumes the set, smallest element first. Owns the nodes, and destroys whatever is left in them when it dies — so a walk stopped part-way destroys the rest exactly once, and nothing already handed out is destroyed twice. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/TreeSet.rux#L416){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | ---------------- | | `T` | the element type | **Implements Iterator** `TreeSetIntoIterator<T>` conforms to `Iterator`. #### `Next` ```rux pub func Next(self: &var TreeSetIntoIterator<T>) -> T? ``` The next element in order, or `none` when there are no more. Takes the smallest element out of the tree rather than reading past it, which is what makes it the caller's. **Returns**: the next element in order, or `none` at the end [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/TreeSet.rux#L431){rel=""nofollow""} # Vector\<T> A growable contiguous run of elements on storage this vector owns. ```rux pub struct Vector<T> { // private fields } ``` Move-only: it owns its elements and storage, prohibits copying, and destroys both with [`~Vector`](https://rux-lang.dev/docs/api/collections/vector#destructor). ## Type parameters | Name | Description | | ---- | ---------------- | | `T` | the element type | ## Constructors ### `Vector` ```rux pub func Vector(allocator: Allocator) -> Vector<T> ``` An empty vector that has not allocated anything. `allocator` is borrowed for the call and kept. Costs nothing: a vector that is never pushed to never allocates, which is what makes one cheap to have and to return. Cannot fail. Runs in constant time. | Name | Type | Description | | ----------- | ----------- | ---------------------------- | | `allocator` | `Allocator` | where the storage comes from | **Returns**: an empty collection that has taken no storage yet [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/Vector.rux#L53){rel=""nofollow""} ## Associated functions ### `WithCapacity` ```rux pub func WithCapacity( allocator: Allocator, capacity: uint ) -> Vector<T> ! CollectionError ``` An empty vector with room for `capacity` elements already taken. `allocator` is borrowed for the call and kept. The vector starts empty — capacity is not length. | Name | Type | Description | | ----------- | ----------- | ---------------------------------- | | `allocator` | `Allocator` | where the storage comes from | | `capacity` | `uint` | how many elements to make room for | **Returns**: an empty vector with room for that many elements already taken [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/Vector.rux#L63){rel=""nofollow""} ### `FromSlice` ```rux pub func FromSlice( allocator: Allocator, items: T[..] ) -> Vector<T> ! CollectionError ``` A vector holding a copy of every element of `items`, in order. `allocator` is borrowed for the call and kept; `items` is borrowed and read. Copies its elements, so a move-only element type is built with [`Push`](https://rux-lang.dev/docs/api/collections/vector#push) instead. | Name | Type | Description | | ----------- | ----------- | ---------------------------- | | `allocator` | `Allocator` | where the storage comes from | | `items` | `T[..]` | the elements to take | **Returns**: a vector holding a copy of those elements [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/Vector.rux#L79){rel=""nofollow""} ## Methods ### `Clone` ```rux pub func Clone(self: &Vector<T>) -> Vector<T> ! CollectionError ``` An independent vector holding a copy of every element of this one. `self` is borrowed and left alone. The copy takes exactly the room it needs rather than matching this one's capacity, since the spare holds nothing worth reproducing. **Returns**: an independent copy [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/Vector.rux#L100){rel=""nofollow""} ### `Length` ```rux pub func Length(self: &Vector<T>) -> uint ``` How many elements the vector holds. `self` is borrowed. **Returns**: how many elements it holds [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/Vector.rux#L108){rel=""nofollow""} ### `Capacity` ```rux pub func Capacity(self: &Vector<T>) -> uint ``` How many elements the storage could hold without growing. `self` is borrowed. Never below the length, and never reduced except by [`ShrinkToFit`](https://rux-lang.dev/docs/api/collections/vector#shrink-to-fit). **Returns**: how many elements fit before the next growth [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/Vector.rux#L116){rel=""nofollow""} ### `IsEmpty` ```rux pub func IsEmpty(self: &Vector<T>) -> bool ``` Whether the vector holds no elements. `self` is borrowed. A vector with capacity and no elements is empty: capacity is not length. **Returns**: whether it holds nothing [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/Vector.rux#L124){rel=""nofollow""} ### `Reserve` ```rux pub func Reserve( self: &var Vector<T>, additional: uint ) -> ! CollectionError ``` Makes room for `additional` more elements on top of those already present. `self` is borrowed mutably; the length does not change. Capacity only grows here; [`ShrinkToFit`](https://rux-lang.dev/docs/api/collections/vector#shrink-to-fit) is what hands it back. A failure leaves the vector exactly as it was. Reports `CapacityOverflow` when the current length plus `additional` cannot be represented, which is what turns a `Reserve(uint::Max)` on a non-empty vector into a reported error rather than a silently tiny capacity. | Name | Type | Description | | ------------ | ------ | --------------------------------------- | | `additional` | `uint` | how many more elements to make room for | **Returns**: nothing when the operation succeeded, or why it did not [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/Vector.rux#L154){rel=""nofollow""} ### `ShrinkToFit` ```rux pub func ShrinkToFit(self: &var Vector<T>) -> ! CollectionError ``` Releases the capacity past the length. `self` is borrowed mutably. A vector with nothing in it gives up its storage entirely and becomes as cheap as a new one. A failure leaves the vector usable at its current capacity, since failing to hand memory back is never a reason to stop working. **Returns**: nothing when the operation succeeded, or why it did not [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/Vector.rux#L165){rel=""nofollow""} ### `Clear` ```rux pub func Clear(self: &var Vector<T>) ``` Destroys every element, keeping the storage. `self` is borrowed mutably. The vector is empty afterwards and can be refilled without allocating again. Runs in time proportional to the length. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/Vector.rux#L186){rel=""nofollow""} ### `Truncate` ```rux pub func Truncate(self: &var Vector<T>, length: uint) ``` Destroys the elements past `length`, keeping the storage. `self` is borrowed mutably. A `length` at or past the current one changes nothing, so this never grows. This is the other half of the `Rux/Algorithms` seam: `Unique`, `RemoveWhere`, `RemoveValue` and `Partition` compact survivors toward the front and report the surviving length without resizing anything, and this is how a vector is told about it. Runs in time proportional to how many elements go. | Name | Type | Description | | -------- | ------ | ----------------- | | `length` | `uint` | how many elements | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/Vector.rux#L198){rel=""nofollow""} ### `Push` ```rux pub func Push( self: &var Vector<T>, value: T ) -> ! CollectionError ``` Appends one element, growing the storage when it is full. `self` is borrowed mutably; `value` is read by value and moved into the vector. A failure leaves the vector exactly as it was and the value with the caller. Amortized constant time: the doubling is what spreads the cost of growing across the appends that caused it. | Name | Type | Description | | ------- | ---- | ------------------- | | `value` | `T` | the value to act on | **Returns**: nothing when the operation succeeded, or why it did not [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/Vector.rux#L231){rel=""nofollow""} ### `PushSlice` ```rux pub func PushSlice( self: &var Vector<T>, items: T[..] ) -> ! CollectionError ``` Appends a copy of every element of `items`, in order. `self` is borrowed mutably; `items` is borrowed and read. Room for all of them is taken first, so this either appends every element or none of them. | Name | Type | Description | | ------- | ------- | -------------------- | | `items` | `T[..]` | the elements to take | **Returns**: nothing when the operation succeeded, or why it did not [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/Vector.rux#L247){rel=""nofollow""} ### `TryPop` ```rux pub func TryPop(self: &var Vector<T>, value: *var T) -> bool ``` Takes the last element out of the vector. `self` is borrowed mutably; `value` receives the element, which is moved out rather than copied, so this is how an element that owns something leaves a vector without being destroyed. Reports false and writes nothing when the vector is empty. The storage is kept, so a vector emptied this way costs nothing to refill. | Name | Type | Description | | ------- | -------- | ---------------------------- | | `value` | `*var T` | receives the removed element | **Returns**: whether there was an element to remove [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/Vector.rux#L267){rel=""nofollow""} ### `Get` ```rux pub func Get(self: &Vector<T>, index: uint) -> T? ``` The element at `index`, or `none` when there is no such index. `self` is borrowed; the element is returned by copy. | Name | Type | Description | | ------- | ------ | ----------------------------- | | `index` | `uint` | which one, counting from zero | **Returns**: a copy of the element, or `none` when the index is out of range [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/Vector.rux#L279){rel=""nofollow""} ### `Reference` ```rux pub func Reference(self: &Vector<T>, index: uint) -> (*T)? ``` A pointer to the element at `index`, or `none` when there is no such index. `self` is borrowed; the pointer borrows the element where it sits. The pointer is valid until the vector grows, shrinks, or is destroyed. | Name | Type | Description | | ------- | ------ | ----------------------------- | | `index` | `uint` | which one, counting from zero | **Returns**: the address of the element, or `none` when the index is out of range [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/Vector.rux#L290){rel=""nofollow""} ### `Set` ```rux pub func Set( self: &var Vector<T>, index: uint, value: T ) -> ! CollectionError ``` Replaces the element at `index` with `value`. `self` is borrowed mutably. Reports `IndexOutOfRange` and changes nothing when there is no such index. The old element is overwritten rather than destroyed. For an element that owns something, take it out first. | Name | Type | Description | | ------- | ------ | ----------------------------- | | `index` | `uint` | which one, counting from zero | | `value` | `T` | the value to act on | **Returns**: nothing when the element was written, or `IndexOutOfRange` [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/Vector.rux#L302){rel=""nofollow""} ### `AsSlice` ```rux pub func AsSlice(self: &Vector<T>) -> T[..] ``` The initialized elements as a borrowed read-only view. `self` is borrowed. Never the spare capacity, which holds nothing. The view is valid until the vector grows, shrinks, or is destroyed. **Returns**: the elements, borrowed [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/Vector.rux#L313){rel=""nofollow""} ### `AsMutableSlice` ```rux pub func AsMutableSlice(self: &var Vector<T>) -> var T[..] ``` The initialized elements as a borrowed writable view. `self` is borrowed mutably. Never the spare capacity. The view is valid until the vector grows, shrinks, or is destroyed. **Returns**: the elements, borrowed for writing [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/Vector.rux#L322){rel=""nofollow""} ### `Iterate` ```rux pub func Iterate(self: &Vector<T>) -> ValueIterator<T> ``` An iterator over the elements, by copy. `self` is borrowed and must outlive the iterator. This is the method a `for` loop finds. The vector must not grow or shrink while the iterator is alive. **Returns**: a cursor yielding copies of the elements [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/Vector.rux#L331){rel=""nofollow""} ### `References` ```rux pub func References(self: &Vector<T>) -> ReferenceIterator<T> ``` An iterator over pointers to the elements. `self` is borrowed and must outlive the iterator. **Returns**: a cursor yielding the elements' addresses [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/Vector.rux#L339){rel=""nofollow""} ### `MutableReferences` ```rux pub func MutableReferences(self: &var Vector<T>) -> MutableReferenceIterator<T> ``` An iterator over writable pointers to initialized elements, without copying them. The vector's storage must outlive the iterator and every yielded pointer. Do not grow, shrink, destroy, or move the vector while any of them is in use, and coordinate aliases that access the same elements. **Returns**: a cursor yielding writable element addresses [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/Vector.rux#L348){rel=""nofollow""} ### `Insert` ```rux pub func Insert( self: &var Vector<T>, index: uint, value: T ) -> ! CollectionError ``` Inserts `value` at `index`, moving everything from there on one place along. `self` is borrowed mutably; `value` is moved in. An `index` equal to the length appends, which is what makes the rejection above it a boundary rather than a blanket refusal; anything past that reports `IndexOutOfRange` and changes nothing. Runs in time proportional to how many elements follow the insertion point. | Name | Type | Description | | ------- | ------ | ----------------------------- | | `index` | `uint` | which one, counting from zero | | `value` | `T` | the value to act on | **Returns**: nothing when the operation succeeded, or why it did not [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/Vector.rux#L361){rel=""nofollow""} ### `RemoveAt` ```rux pub func RemoveAt(self: &var Vector<T>, index: uint) -> T? ``` Takes the element at `index` out, moving everything after it one place back. `self` is borrowed mutably. The element is moved out and handed to the caller rather than destroyed, so an element that owns something leaves intact. Reports `none` and changes nothing when there is no such index. Order is preserved, which is what separates this from [`SwapRemoveAt`](https://rux-lang.dev/docs/api/collections/vector#swap-remove-at). Runs in time proportional to how many elements follow the one removed. | Name | Type | Description | | ------- | ------ | ----------------------------- | | `index` | `uint` | which one, counting from zero | **Returns**: the element removed, or `none` when the index is out of range [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/Vector.rux#L385){rel=""nofollow""} ### `SwapRemoveAt` ```rux pub func SwapRemoveAt( self: &var Vector<T>, index: uint ) -> T? ``` Takes the element at `index` out and moves the last one into its place. `self` is borrowed mutably. The element is moved out and handed to the caller. Reports `none` and changes nothing when there is no such index. Order is *not* preserved — whatever was last now sits where the removed element was — and that is the whole point: this is constant time where [`RemoveAt`](https://rux-lang.dev/docs/api/collections/vector#remove-at) is linear, and for a sequence nobody is reading in order the difference is free. | Name | Type | Description | | ------- | ------ | ----------------------------- | | `index` | `uint` | which one, counting from zero | **Returns**: the element removed, or `none` when the index is out of range [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/Vector.rux#L406){rel=""nofollow""} ### `First` ```rux pub func First(self: &Vector<T>) -> (*T)? ``` A pointer to the first element, or `none` for an empty vector. `self` is borrowed; the pointer borrows the element where it sits. **Returns**: the address of the first element, or `none` when empty [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/Vector.rux#L421){rel=""nofollow""} ### `Last` ```rux pub func Last(self: &Vector<T>) -> (*T)? ``` A pointer to the last element, or `none` for an empty vector. `self` is borrowed; the pointer borrows the element where it sits. **Returns**: the address of the last element, or `none` when empty [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/Vector.rux#L429){rel=""nofollow""} ### `Slice` ```rux pub func Slice( self: &Vector<T>, start: uint, count: uint ) -> T[..] ``` A borrowed read-only view of `count` elements starting at `start`. `self` is borrowed. A `start` at or past the length gives an empty view, and a `count` running past the end is clamped, so the result never covers storage the vector does not hold. The view is valid until the vector grows, shrinks, or is destroyed. | Name | Type | Description | | ------- | ------ | ---------------------------- | | `start` | `uint` | the first element, inclusive | | `count` | `uint` | how many elements | **Returns**: that run of elements, borrowed; empty when the range is out of bounds [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/Vector.rux#L442){rel=""nofollow""} ### `MutableSliceOf` ```rux pub func MutableSliceOf( self: &var Vector<T>, start: uint, count: uint ) -> var T[..] ``` A borrowed writable view of `count` elements starting at `start`. `self` is borrowed mutably. Clamped exactly as [`Slice`](https://rux-lang.dev/docs/api/collections/vector#slice) is. The view is valid until the vector grows, shrinks, or is destroyed. | Name | Type | Description | | ------- | ------ | ---------------------------- | | `start` | `uint` | the first element, inclusive | | `count` | `uint` | how many elements | **Returns**: that run borrowed for writing; empty when the range is out of bounds [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/Vector.rux#L459){rel=""nofollow""} ### `IntoIterator` ```rux pub func IntoIterator(self: Vector<T>) -> VectorIntoIterator<T> ``` Takes the vector apart into an iterator over its elements. Consumes the vector: it is moved into the iterator, and the storage goes with it, so nothing is copied and nothing is reallocated. Each element comes out by value, which is how one that owns something leaves. Whatever is not taken is destroyed when the iterator's life ends. Cannot fail. Runs in constant time and allocates nothing. **Returns**: a cursor that consumes the vector as it goes [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/Vector.rux#L476){rel=""nofollow""} ### `ToArray` ```rux pub func ToArray(self: &Vector<T>) -> Array<T> ! CollectionError ``` Copies the elements into a fixed-length array. `self` is borrowed and keeps its own storage, so both are released independently. Copies its elements, so this is for element types where copying means what it says — [`IntoArray`](https://rux-lang.dev/docs/api/collections/vector#into-array) is what moves them. **Returns**: an array holding a copy of the elements [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/Vector.rux#L499){rel=""nofollow""} ### `IntoArray` ```rux pub func IntoArray(self: Vector<T>) -> Array<T> ! CollectionError ``` Hands the storage itself to a fixed-length array, copying nothing. Consumes the vector. The spare capacity is trimmed first, and the trim has to succeed: an array releases its block with the layout of its length, so a block still carrying spare capacity would be given back under a layout it was not taken with. A failed trim is a failed transfer, and the vector is gone either way — it was consumed by the call — so its elements are destroyed and an empty array comes back. That costs the elements, which is why it is reported rather than silent; a shrink refused by an allocator is close to impossible, since it asks for less than it already holds. **Returns**: an array taking the vector's storage rather than copying it [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/Vector.rux#L513){rel=""nofollow""} ## Destructor ```rux func ~Vector(self: &var Vector<T>) ``` Destroys every element and releases the storage. Runs when the vector's life ends. The spare capacity past the length holds nothing and is not touched; the elements go first and the block second, since an element destroyed after its storage was released would be read from freed memory. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/Vector.rux#L215){rel=""nofollow""} ## Related ### `WriteVectorDebug<T>` ```rux pub func WriteVectorDebug<T: Debug>( writer: &var TextWriter, value: &Vector<T>, spec: FormatSpec ) -> ! FormatError ``` Writes a borrowed vector as `[first, second, third]`. An empty vector is `[]`, and its capacity is not shown: the spare room past the length holds nothing, so it is not part of what the vector is. The vector and every element are borrowed, so this may be called on a vector of a move-only element type and the vector still holds all of them afterwards. `spec` is handed to each element unchanged and means whatever that element type makes of it. The brackets and commas are punctuation and are never padded. Reports whatever the writer or an element's implementation reported, stopping at the first refusal. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/Presentation.rux#L63){rel=""nofollow""} **Type parameters** | Name | Description | | ---------- | ---------------------------------------------------- | | `T: Debug` | the element type, which must know how to show itself | **Parameters** | Name | Type | Description | | -------- | ----------------- | ----------------------------------------- | | `writer` | `&var TextWriter` | the destination | | `value` | `&Vector<T>` | the vector to show, borrowed for the call | | `spec` | `FormatSpec` | what to show each element under | **Returns**: success when the whole rendering was accepted ### `MinimumVectorCapacity` ```rux pub const MinimumVectorCapacity: uint = 4; ``` The capacity a vector takes when it first has to allocate. Four elements rather than one: the first few appends are the common case, and three reallocations to reach four elements is three more than the work is worth. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/Vector.rux#L25){rel=""nofollow""} ### `VectorIntoIterator<T>` ```rux pub struct VectorIntoIterator<T> { // private fields } ``` An iterator that takes a vector apart, yielding each element by value. Move-only: it owns the storage the vector owned, prohibits copying, and destroys it with [`~VectorIntoIterator`](https://rux-lang.dev/docs/api/collections/vector#vector-into-iterator-destructor). This is how a vector of elements that own something is emptied into somewhere else — each element is moved out rather than copied, and whatever is left when the iterator's life ends is destroyed with it. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/Vector.rux#L532){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | ---------------- | | `T` | the element type | **Implements Iterator** `VectorIntoIterator<T>` conforms to `Iterator`. #### `Next` ```rux pub func Next(self: &var VectorIntoIterator<T>) -> T? ``` The next element, moved out, or `none` once every element has been yielded. `self` is borrowed mutably and advanced. The element is moved rather than copied, so it is the caller's to keep or destroy; an exhausted iterator keeps reporting `none`. Cannot fail. Runs in constant time and allocates nothing. **Returns**: the next element, or `none` at the end [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/Vector.rux#L575){rel=""nofollow""} **Destructor** #### `~VectorIntoIterator` ```rux func ~VectorIntoIterator(self: &var VectorIntoIterator<T>) ``` Destroys whatever was not yielded and releases the storage. Runs when the iterator's life ends. Everything already yielded belongs to whoever took it and is not touched here, which is what makes stopping part-way through safe. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/Vector.rux#L553){rel=""nofollow""} # Comparing Ready-made ordering callbacks for the key types a tree map or set is keyed on. ## `CompareUint` ```rux pub func CompareUint(left: uint, right: uint) -> Ordering ``` The ordering of two `uint` values. Both are read by value. Cannot fail; runs in constant time and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/Comparing.rux#L19){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------- | ------ | --------------------- | | `left` | `uint` | one of the two values | | `right` | `uint` | the other | **Returns**: how `left` orders against `right` ## `CompareUint64` ```rux pub func CompareUint64( left: uint64, right: uint64 ) -> Ordering ``` The ordering of two `uint64` values. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/Comparing.rux#L30){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------- | -------- | --------------------- | | `left` | `uint64` | one of the two values | | `right` | `uint64` | the other | **Returns**: how `left` orders against `right` ## `CompareUint32` ```rux pub func CompareUint32( left: uint32, right: uint32 ) -> Ordering ``` The ordering of two `uint32` values. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/Comparing.rux#L41){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------- | -------- | --------------------- | | `left` | `uint32` | one of the two values | | `right` | `uint32` | the other | **Returns**: how `left` orders against `right` ## `CompareInt64` ```rux pub func CompareInt64(left: int64, right: int64) -> Ordering ``` The ordering of two `int64` values. Signed, so this is not the unsigned comparison of the same bits: a negative key sorts below every positive one. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/Comparing.rux#L53){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------- | ------- | --------------------- | | `left` | `int64` | one of the two values | | `right` | `int64` | the other | **Returns**: how `left` orders against `right` ## `CompareInt32` ```rux pub func CompareInt32(left: int32, right: int32) -> Ordering ``` The ordering of two `int32` values. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/Comparing.rux#L64){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------- | ------- | --------------------- | | `left` | `int32` | one of the two values | | `right` | `int32` | the other | **Returns**: how `left` orders against `right` ## `CompareChar8` ```rux pub func CompareChar8(left: char8, right: char8) -> Ordering ``` The ordering of two `char8` code units. By code unit, which for ASCII is alphabetical and for anything above it is UTF-8 byte order — which is the order of the code points, since UTF-8 is ordered that way by construction. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/Comparing.rux#L77){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------- | ------- | --------------------- | | `left` | `char8` | one of the two values | | `right` | `char8` | the other | **Returns**: how `left` orders against `right` ## `CompareSlice` ```rux pub func CompareSlice( left: char8[..], right: char8[..] ) -> Ordering ``` The ordering of two runs of characters, shortest-first where one is a prefix of the other. Both are borrowed and read. Compares code unit by code unit and, where every shared position agrees, orders the shorter one first — which is the ordering a dictionary uses, and the one `Rux/Algorithms` sorts by. Cannot fail. Runs in time proportional to the shorter length and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/Comparing.rux#L91){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------- | ----------- | --------------------- | | `left` | `char8[..]` | one of the two values | | `right` | `char8[..]` | the other | **Returns**: how the two order byte by byte, then by length # Hashing Ready-made seeded hash and equality callbacks for the key types a hash map or set is keyed on. ## `HashUint` ```rux pub func HashUint( value: uint, low: uint64, high: uint64 ) -> uint64 ``` The seeded hash of a `uint`. `value`, `low` and `high` are read by value. The seed is the table's, and two tables with different seeds hash the same value differently. Cannot fail. Runs in constant time and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/Hashing.rux#L25){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------- | -------- | ------------------- | | `value` | `uint` | the value to act on | | `low` | `uint64` | the first seed word | | `high` | `uint64` | the second | **Returns**: the value's hash under that seed ## `HashUint64` ```rux pub func HashUint64( value: uint64, low: uint64, high: uint64 ) -> uint64 ``` The seeded hash of a `uint64`. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/Hashing.rux#L37){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------- | -------- | ------------------- | | `value` | `uint64` | the value to act on | | `low` | `uint64` | the first seed word | | `high` | `uint64` | the second | **Returns**: the value's hash under that seed ## `HashUint32` ```rux pub func HashUint32( value: uint32, low: uint64, high: uint64 ) -> uint64 ``` The seeded hash of a `uint32`. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/Hashing.rux#L49){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------- | -------- | ------------------- | | `value` | `uint32` | the value to act on | | `low` | `uint64` | the first seed word | | `high` | `uint64` | the second | **Returns**: the value's hash under that seed ## `HashInt64` ```rux pub func HashInt64( value: int64, low: uint64, high: uint64 ) -> uint64 ``` The seeded hash of an `int64`. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/Hashing.rux#L61){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------- | -------- | ------------------- | | `value` | `int64` | the value to act on | | `low` | `uint64` | the first seed word | | `high` | `uint64` | the second | **Returns**: the value's hash under that seed ## `HashInt32` ```rux pub func HashInt32( value: int32, low: uint64, high: uint64 ) -> uint64 ``` The seeded hash of an `int32`. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/Hashing.rux#L73){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------- | -------- | ------------------- | | `value` | `int32` | the value to act on | | `low` | `uint64` | the first seed word | | `high` | `uint64` | the second | **Returns**: the value's hash under that seed ## `HashChar8` ```rux pub func HashChar8( value: char8, low: uint64, high: uint64 ) -> uint64 ``` The seeded hash of a `char8`. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/Hashing.rux#L85){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------- | -------- | ------------------- | | `value` | `char8` | the value to act on | | `low` | `uint64` | the first seed word | | `high` | `uint64` | the second | **Returns**: the value's hash under that seed ## `HashSlice` ```rux pub func HashSlice( text: char8[..], low: uint64, high: uint64 ) -> uint64 ``` The seeded hash of a run of characters, which is what a string key comes to. `text` is borrowed and read. Two slices holding the same characters hash the same however they were built, which is what makes a text key usable at all. Runs in time proportional to the length and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/Hashing.rux#L100){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------ | ----------- | ------------------- | | `text` | `char8[..]` | the bytes to hash | | `low` | `uint64` | the first seed word | | `high` | `uint64` | the second | **Returns**: the bytes' hash under that seed ## `EqualsUint` ```rux pub func EqualsUint(left: uint, right: uint) -> bool ``` Whether two `uint` keys are the same. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/Hashing.rux#L109){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------- | ------ | --------------------- | | `left` | `uint` | one of the two values | | `right` | `uint` | the other | **Returns**: whether the two are equal ## `EqualsUint64` ```rux pub func EqualsUint64(left: uint64, right: uint64) -> bool ``` Whether two `uint64` keys are the same. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/Hashing.rux#L118){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------- | -------- | --------------------- | | `left` | `uint64` | one of the two values | | `right` | `uint64` | the other | **Returns**: whether the two are equal ## `EqualsUint32` ```rux pub func EqualsUint32(left: uint32, right: uint32) -> bool ``` Whether two `uint32` keys are the same. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/Hashing.rux#L127){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------- | -------- | --------------------- | | `left` | `uint32` | one of the two values | | `right` | `uint32` | the other | **Returns**: whether the two are equal ## `EqualsInt64` ```rux pub func EqualsInt64(left: int64, right: int64) -> bool ``` Whether two `int64` keys are the same. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/Hashing.rux#L136){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------- | ------- | --------------------- | | `left` | `int64` | one of the two values | | `right` | `int64` | the other | **Returns**: whether the two are equal ## `EqualsInt32` ```rux pub func EqualsInt32(left: int32, right: int32) -> bool ``` Whether two `int32` keys are the same. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/Hashing.rux#L145){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------- | ------- | --------------------- | | `left` | `int32` | one of the two values | | `right` | `int32` | the other | **Returns**: whether the two are equal ## `EqualsChar8` ```rux pub func EqualsChar8(left: char8, right: char8) -> bool ``` Whether two `char8` keys are the same. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/Hashing.rux#L154){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------- | ------- | --------------------- | | `left` | `char8` | one of the two values | | `right` | `char8` | the other | **Returns**: whether the two are equal ## `EqualsSlice` ```rux pub func EqualsSlice( left: char8[..], right: char8[..] ) -> bool ``` Whether two runs of characters hold the same characters. Both are borrowed and read. Different lengths are never equal, and two empty slices are, whatever their data pointers hold. Compares eight bytes at a time, finishing with the last eight, which may overlap words already compared; runs of four to seven bytes compare their first and last four. Only shorter runs go byte by byte. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Collections/Src/Hashing.rux#L167){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------- | ----------- | --------------------- | | `left` | `char8[..]` | one of the two values | | `right` | `char8[..]` | the other | **Returns**: whether both hold the same bytes # Algorithms Generic algorithms over slices and mutable slices. ## Installation Add `Algorithms` to the `[Dependencies]` table of your package's `Rux.toml`: ```toml [Dependencies] Algorithms = { Namespace = "Rux", Version = "0.1.0" } ``` Standard packages are declared by hand: the registry does not serve them, so `rux add Rux/Algorithms` cannot add them. ## Dependencies - [`Core`](https://rux-lang.dev/docs/api/core) 0.1.0 ## Guide Generic algorithms over slices and mutable slices. Sorting, searching, and the transformations that pair with the slice types in [`Rux/Core`](https://github.com/rux-lang/Rux/blob/main/Packages/Algorithms/../Core){rel=""nofollow""} and the containers in [`Rux/Collections`](https://github.com/rux-lang/Rux/blob/main/Packages/Algorithms/../Collections){rel=""nofollow""}. ### Status | Module | Takes | Requires on `T` | Provides | | --------------------------------------------------------------- | ----------- | --------------- | ---------------------------------------------------------- | | `Find` | `T[..]` | — or `==` | Linear queries, sequence comparison, by value or predicate | | `MinMax` | `T[..]` | — or `<` | Sequence extremes and clamping | | `Search` | `T[..]` | `<` | Sortedness checks, bounds and binary search | | `Modify` | `var T[..]` | — or `==` | Reordering, bulk movement, removal and partitioning | | [`Sort`](https://rux-lang.dev/docs/api/algorithms/sorting#sort) | `var T[..]` | `<` | Introsort, selection, and partial sorting | | `Stable` | `var T[..]` | `<` | Merge sort, with scratch the caller supplies | | `Heap` | `var T[..]` | `<` | Max-heap arrangement, push, pop and heapsort | | [`Fold`](https://rux-lang.dev/docs/api/algorithms/folding#fold) | `T[..]` | — or `+`/`*` | Folds in both directions, sum, product and transform | | `Numeric` | `var T[..]` | — or `+` | Running sums and scans, counting sequences, midpoints | Everything takes a view: a `T[..]` where it only reads, and a `var T[..]` where it writes. Modules are split by what they ask of the element type, so a type that defines only one of the two comparison operators can still use the modules that need it, and a missing operator is reported against one module rather than the whole package. A **predicate-taking** function asks nothing of `T` at all — the caller's function supplies the test — so those work on any element type whatsoever. ### What a search answers with A search that found something answers with the index it found, as an optional `uint?` that is `none` when nothing was found: ```rux func IndexOf<T>(items: T[..], value: T) -> uint? ``` Not found is an ordinary outcome, not a failure, and a sentinel index is a bug waiting for the one sequence long enough to reach it. An empty slice is not a special case anywhere: it contains nothing, matches no search, satisfies every universal claim and no existential one. A comparison answers with an `Ordering` rather than a `bool`, and takes one where it needs the caller to decide. [`Compare`](https://rux-lang.dev/docs/api/algorithms/comparing#compare) is lexicographic — the first differing element decides, and the shorter of two otherwise-equal sequences is the smaller — and [`CompareBy`](https://rux-lang.dev/docs/api/algorithms/comparing#compare-by) is the same for a type with no ordering of its own. ### What the ordered searches assume Every search in `Search` assumes the slice is already sorted by the same order the search uses. That is the caller's promise, and nothing checks it on the way in — checking would cost the linear scan a binary search exists to avoid. A search over an unsorted slice does not fail; it answers, and the answer is meaningless. [`IsSorted`](https://rux-lang.dev/docs/api/algorithms/sorted-slices#is-sorted) is there for a caller who wants to check once, where checking is worth it. A bound is a position rather than an element. [`LowerBound`](https://rux-lang.dev/docs/api/algorithms/sorted-slices#lower-bound) is the first position the value could be inserted at without breaking the order and [`UpperBound`](https://rux-lang.dev/docs/api/algorithms/sorted-slices#upper-bound) is the last, so between them lie exactly the equal elements — which is what [`EqualRange`](https://rux-lang.dev/docs/api/algorithms/sorted-slices#equal-range) returns in one pass. All three answer for a value that is not there at all: the range is empty, and its start is where the value would go. Equality in these searches is the ordering's, not the type's. Two elements neither of which is less than the other are equal here, whatever `==` would say. When several compare equal, [`BinarySearch`](https://rux-lang.dev/docs/api/algorithms/sorted-slices#binary-search) reports the first, so the answer depends on the sequence rather than on how the search happened to divide it. ### Nothing here resizes anything None of these own the storage they work on, so a removal cannot shorten it. [`Unique`](https://rux-lang.dev/docs/api/algorithms/modifying#unique), [`RemoveValue`](https://rux-lang.dev/docs/api/algorithms/modifying#remove-value) and [`RemoveWhere`](https://rux-lang.dev/docs/api/algorithms/modifying#remove-where) compact the survivors toward the front and report how many are left; the caller, who does own the storage, is what truncates it. What lies past that count is unspecified. It is neither cleared nor preserved — the elements there were moved from, and reading them back gives whatever the compaction happened to leave. For a `Copy` element that is a stale duplicate; for anything else it is a value with no owner. [`Partition`](https://rux-lang.dev/docs/api/algorithms/modifying#partition) is unstable: it exchanges elements from both ends inward, which is what keeps it to one pass and no scratch storage, and means the order within each group is not the order it started in. A caller that needs the original order needs a stable partition, which needs somewhere to put things. ### Heaps A heap is an arrangement rather than a type: element `i` is at least as large as elements `2i+1` and `2i+2`, which puts the largest at the front and makes both removing it and adding another logarithmic. That is what a priority queue is, and it is why these are here rather than in a container — any sequence a caller already has can be one. The arrangement is not an order. A heap is not sorted, and only its first element is where a sorted sequence would put it; [`SortHeap`](https://rux-lang.dev/docs/api/algorithms/heaps#sort-heap) turns one into the other, which is heapsort. Growing and shrinking stay the caller's: [`PushHeap`](https://rux-lang.dev/docs/api/algorithms/heaps#push-heap) is told about an element already appended, and [`PopHeap`](https://rux-lang.dev/docs/api/algorithms/heaps#pop-heap) leaves the removed element at the end for the caller to drop. This package does not own storage anywhere. ### Folds A fold is the general form — an accumulator, a starting value, and a function — and the accumulator's type is independent of the element's, so the same operation both sums a sequence and builds something else entirely out of one. Direction is part of the contract: [`Fold`](https://rux-lang.dev/docs/api/algorithms/folding#fold) runs left to right and [`FoldRight`](https://rux-lang.dev/docs/api/algorithms/folding#fold-right) right to left, which are different answers for any combine that is not associative. [`Sum`](https://rux-lang.dev/docs/api/algorithms/folding#sum) and [`Product`](https://rux-lang.dev/docs/api/algorithms/folding#product) are folds with the function already chosen. They take the starting value rather than assuming one, because a generic `T` has no zero this package could name. Overflow is the element type's business: they use `+` and `*` and behave exactly as those do, and a caller who needs checking folds a checked addition instead. ### Stability, and what it costs [`Sort`](https://rux-lang.dev/docs/api/algorithms/sorting#sort) is faster and needs no storage at all, and for most sequences the difference between equal elements is not observable. It becomes observable the moment a second key is involved: sort a table by one column, then by another, and only a stable sort leaves the first ordering intact within each group of the second. [`StableSort`](https://rux-lang.dev/docs/api/algorithms/sorting#stable-sort) is a bottom-up merge sort, so it needs somewhere to merge into. It asks the caller for scratch as long as the sequence — [`RequiredScratch`](https://rux-lang.dev/docs/api/algorithms/sorting#required-scratch) says how much — and reports false, changing nothing, when given less. Asking rather than allocating is deliberate: this package allocates nothing anywhere, which is what lets it be used where allocation is not available, and a caller who already has a buffer should not have a second one taken behind their back. Its comparisons and moves are O(n log n) for every input. There is no bad case, unlike a quicksort; what it costs over [`Sort`](https://rux-lang.dev/docs/api/algorithms/sorting#sort) is the storage and about a constant factor. ### What sorting promises [`Sort`](https://rux-lang.dev/docs/api/algorithms/sorting#sort) is an introsort: quicksort with a three-way partition, falling back to heapsort once the recursion budget is spent and to insertion sort on small partitions. Each part covers the others' weakness, and the combination has a genuine O(n log n) worst case that no one of the three has alone. Precisely: comparisons are O(n log n) for **every** input, with nothing probabilistic about it — the depth budget is `2 * floor(log2 n)`, and a range still unsorted when it runs out goes to heapsort, which never degrades. Auxiliary storage is O(1). Stack depth is O(log n) frames, about sixty-four for any addressable length, because the recursive call always takes the smaller side of a partition while the loop handles the larger. Sorting is **not stable**: equal elements may come out in a different order than they went in. It is deterministic — no randomized pivots, so the same input always gives the same output and the same number of comparisons — but a caller who needs equal elements to keep their order needs a stable sort, which needs somewhere to put things. Type arguments are always explicit — Rux does not infer them for free functions. ```rux import Algorithms::{ Reverse, Unique }; var numbers: int32[3] = [3, 1, 1]; let view = (@numbers[0])[..3]; Reverse<int32>(view); // Unique compacts the survivors toward the front and returns how many are // left, without resizing the caller-owned storage. let kept = Unique<int32>(view); ``` A fixed array supplies a writable view directly through range indexing: ```rux import Algorithms::Rotate; var values: int32[5] = [1, 2, 3, 4, 5]; let view = (@values[0])[..5]; Rotate<int32>(view, 2); ``` ### What it provides | Function | Mutates | Returns | Complexity | Requires on `T` | | -------------------------------------------------------------------------------- | ------- | ----------------------------- | ---------- | --------------- | | [`Swap`](https://rux-lang.dev/docs/api/algorithms/modifying#swap) | yes | — | O(1) | — | | [`Reverse`](https://rux-lang.dev/docs/api/algorithms/modifying#reverse) | yes | — | O(n) | — | | [`Rotate`](https://rux-lang.dev/docs/api/algorithms/modifying#rotate) | yes | `false` if `middle > length` | O(n) | — | | [`Fill`](https://rux-lang.dev/docs/api/algorithms/modifying#fill) | yes | — | O(n) | — | | `Copy` | yes | `false` on a null with length | O(n) | — | | `CopyBackward` | yes | `false` on a null with length | O(n) | — | | [`Unique`](https://rux-lang.dev/docs/api/algorithms/modifying#unique) | yes | surviving length | O(n) | `==` | | [`RemoveValue`](https://rux-lang.dev/docs/api/algorithms/modifying#remove-value) | yes | surviving length | O(n) | `==` | [`Unique`](https://rux-lang.dev/docs/api/algorithms/modifying#unique) and [`RemoveValue`](https://rux-lang.dev/docs/api/algorithms/modifying#remove-value) compact survivors toward the front and return the new length. They do not resize the storage, and elements from the returned length onward are left unspecified rather than cleared — the same contract as their C++ counterparts. `Copy` moves elements front to back and `CopyBackward` back to front, so overlapping ranges are correct when the destination is respectively at or below the source and at or above the source. Neither detects overlap for you. #### Predicates — requiring nothing of `T` A predicate is an ordinary function value of type `func(T) -> bool`. Rux has no closures, so it carries no captured state: anything the test needs beyond the element has to be reachable from the function itself. | Function | Mutates | Returns | Complexity | | -------------------------------------------------------------------------------------- | ------- | ----------------------------------------------- | ---------- | | `TryFindIf` | no | `true` + the first accepted index | O(n) | | `TryFindLastIf` | no | `true` + the last accepted index | O(n) | | `CountIf` | no | how many elements are accepted | O(n) | | `All` | no | whether every element is accepted | O(n) | | `Any` | no | whether any element is accepted | O(n) | | `None` | no | the exact negation of `Any` | O(n) | | `RemoveIf` | yes | surviving length, order preserved | O(n) | | [`Partition`](https://rux-lang.dev/docs/api/algorithms/modifying#partition) | yes | the boundary between accepted and rejected | O(n) | | [`PartitionPoint`](https://rux-lang.dev/docs/api/algorithms/modifying#partition-point) | no | the boundary of an already-partitioned sequence | O(log n) | | [`Transform`](https://rux-lang.dev/docs/api/algorithms/folding#transform) | yes | `false` on a null with length | O(n) | | [`Fold`](https://rux-lang.dev/docs/api/algorithms/folding#fold) | no | the accumulator | O(n) | An empty sequence satisfies `All` vacuously and `Any` never, so `All` and `None` are both true only when there is nothing to test. [`Partition`](https://rux-lang.dev/docs/api/algorithms/modifying#partition) does **not** preserve order within either group: it swaps ends inward for one pass and no memory. `RemoveIf` does preserve it. A stable partition would need an auxiliary buffer or a rotation per element and is not offered. [`Transform`](https://rux-lang.dev/docs/api/algorithms/folding#transform) and [`Fold`](https://rux-lang.dev/docs/api/algorithms/folding#fold) let the result type differ from the element type, so [`Fold`](https://rux-lang.dev/docs/api/algorithms/folding#fold) both sums a sequence and builds something else entirely out of one: ```rux import Algorithms::{ CountWhere, Fold, Partition }; func IsEven(value: int32) -> bool { return value % 2 == 0; } func Add(total: int32, value: int32) -> int32 { return total + value; } var values: int32[5] = [1, 2, 3, 4, 5]; let view = (@values[0])[..5]; let evens = CountWhere<int32>(view, IsEven); let sum = Fold<int32, int32>(view, 0, Add); let boundary = Partition<int32>(view, IsEven); ``` #### Comparators — ordering by something other than `<` Every ordering function has a `*By` counterpart taking an explicit comparator: [`SortBy`](https://rux-lang.dev/docs/api/algorithms/sorting#sort-by), [`SortDescendingBy`](https://rux-lang.dev/docs/api/algorithms/sorting#sort-descending-by), [`NthElementBy`](https://rux-lang.dev/docs/api/algorithms/sorting#nth-element-by), [`PartialSortBy`](https://rux-lang.dev/docs/api/algorithms/sorting#partial-sort-by), [`IsSortedBy`](https://rux-lang.dev/docs/api/algorithms/sorted-slices#is-sorted-by), [`IsSortedUntilBy`](https://rux-lang.dev/docs/api/algorithms/sorted-slices#is-sorted-until-by), [`LowerBoundBy`](https://rux-lang.dev/docs/api/algorithms/sorted-slices#lower-bound-by), [`UpperBoundBy`](https://rux-lang.dev/docs/api/algorithms/sorted-slices#upper-bound-by), `TryBinarySearchBy`, [`EqualRangeBy`](https://rux-lang.dev/docs/api/algorithms/sorted-slices#equal-range-by), `TryMinIndexBy`, `TryMaxIndexBy`, `TryMinMaxIndexBy` and [`ClampBy`](https://rux-lang.dev/docs/api/algorithms/min-max#clamp-by). The comparator answers "does `a` come strictly before `b`" — the same question `<` answers — and must be a strict weak ordering. Equivalence is derived from it alone, so **a comparator is enough on its own**: the element type need not define any operator at all. ```rux import Algorithms::SortBy; import Core::Ordering; struct Task { priority: int32; id: int32; } // A comparison answers with an Ordering rather than a boolean, so one call settles which of the three cases holds. func ByPriority(a: Task, b: Task) -> Ordering { if a.priority < b.priority { return Ordering::Less; } return a.priority > b.priority ? Ordering::Greater : Ordering::Equal; } func ById(a: Task, b: Task) -> Ordering { if a.id < b.id { return Ordering::Less; } return a.id > b.id ? Ordering::Greater : Ordering::Equal; } var tasks: Task[3] = [Task { priority: 3, id: 40 }, Task { priority: 1, id: 50 }, Task { priority: 2, id: 30 }]; let view = (@tasks[0])[..3]; SortBy<Task>(view, ByPriority); SortBy<Task>(view, ById); ``` They are separate names rather than overloads of the operator forms. Rux resolves an untyped integer literal against a single candidate but not against an overload set, so adding an overload would have made `Sort<int32>(data, 8)` stop compiling for everyone already calling it. #### `Find` — linear queries, requiring `==` | Function | Returns | Complexity | | ------------------------------------------------------------------------- | ---------------------------------------- | ---------- | | [`Contains`](https://rux-lang.dev/docs/api/algorithms/searching#contains) | whether any element matches | O(n) | | [`Count`](https://rux-lang.dev/docs/api/algorithms/searching#count) | how many elements match | O(n) | | `TryFind` | `true` + the first matching index | O(n) | | `TryFindLast` | `true` + the last matching index | O(n) | | `Equal` | whether two sequences match element-wise | O(n) | | `TryMismatch` | `true` + the first differing index | O(n) | #### `Search` — ordered queries, requiring `<` | Function | Returns | Complexity | | ----------------------------------------------------------------------------------------- | ----------------------------------------------- | ---------- | | [`IsSorted`](https://rux-lang.dev/docs/api/algorithms/sorted-slices#is-sorted) | whether the sequence is non-decreasing | O(n) | | [`IsSortedUntil`](https://rux-lang.dev/docs/api/algorithms/sorted-slices#is-sorted-until) | the first index breaking the order, else length | O(n) | | [`LowerBound`](https://rux-lang.dev/docs/api/algorithms/sorted-slices#lower-bound) | the first index not less than the value | O(log n) | | [`UpperBound`](https://rux-lang.dev/docs/api/algorithms/sorted-slices#upper-bound) | the first index greater than the value | O(log n) | | `TryBinarySearch` | `true` + the lowest equivalent index | O(log n) | | [`EqualRange`](https://rux-lang.dev/docs/api/algorithms/sorted-slices#equal-range) | the `uint..uint` of equivalent elements | O(log n) | The four bounded searches require the sequence to be sorted by the same `<`; [`IsSorted`](https://rux-lang.dev/docs/api/algorithms/sorted-slices#is-sorted) checks exactly that precondition. An unsorted sequence yields an unspecified index but never an access outside it. [`LowerBound`](https://rux-lang.dev/docs/api/algorithms/sorted-slices#lower-bound), [`UpperBound`](https://rux-lang.dev/docs/api/algorithms/sorted-slices#upper-bound) and [`IsSortedUntil`](https://rux-lang.dev/docs/api/algorithms/sorted-slices#is-sorted-until) return a position in `0..=length`, so every result is meaningful and none of them doubles as a not-found marker. Where a query really can fail, the `Try*` form writes through an out-parameter and returns a `bool`, leaving the index untouched on a miss so a caller can seed it with a fallback. A null out-parameter reports failure rather than searching. [`EqualRange`](https://rux-lang.dev/docs/api/algorithms/sorted-slices#equal-range) returns an empty range when nothing matched, and its endpoints are then the single position where the value would be inserted — so the absent case still answers "where would this go?". Equivalence in this module is derived as `!(a < b) && !(b < a)`, never from `==`. A type that orders but does not define equality works here in full. #### `Sort` — ordering, requiring `<` | Function | Mutates | Returns | Complexity | Stability | | ------------------------------------------------------------------------------------ | ------- | --------------------------- | --------------------- | --------- | | [`Sort`](https://rux-lang.dev/docs/api/algorithms/sorting#sort) | yes | — | O(n log n) worst case | unstable | | [`SortDescending`](https://rux-lang.dev/docs/api/algorithms/sorting#sort-descending) | yes | — | O(n log n) worst case | unstable | | [`NthElement`](https://rux-lang.dev/docs/api/algorithms/sorting#nth-element) | yes | `false` if `n >= length` | O(n) expected | unstable | | [`PartialSort`](https://rux-lang.dev/docs/api/algorithms/sorting#partial-sort) | yes | `false` if `count > length` | O(n log count) | unstable | [`Sort`](https://rux-lang.dev/docs/api/algorithms/sorting#sort) is an introsort: quicksort with a three-way partition, falling back to heapsort once its recursion budget is spent and to insertion sort below 16 elements. The three-way partition means an all-equal sequence costs a single linear pass rather than the quadratic behavior a two-way partition produces on it, and input drawn from a small set of distinct values stops being a worst case. The heapsort fallback is what makes O(n log n) a guarantee rather than an average. It allocates nothing and recurses only into the smaller side of each partition, so stack depth stays at about log2(n) — on the order of 64 frames for any sequence that fits in memory — however badly the pivots are chosen. Sorting is **unstable**: equivalent elements may be reordered. It is deterministic, though — there is no randomized pivot, so the same input always produces the same output. [`SortDescending`](https://rux-lang.dev/docs/api/algorithms/sorting#sort-descending) sorts ascending and then reverses. That costs one extra linear pass and avoids maintaining a mirrored copy of every helper, which matters more than the pass does; order among equivalent elements is unspecified in both directions anyway. [`NthElement`](https://rux-lang.dev/docs/api/algorithms/sorting#nth-element) places the element that a full sort would put at `n` and partitions around it, without ordering either side. Reach for it when only one order statistic is wanted — a median, a percentile — since it is linear on average where a sort is not. [`PartialSort`](https://rux-lang.dev/docs/api/algorithms/sorting#partial-sort) orders the `count` smallest into the front and leaves the rest unspecified, at O(n log count) rather than O(n log n). Both allocate nothing, and neither recurses. #### `MinMax` — extremes and clamping, requiring `<` | Function | Returns | Complexity | | ----------------------------------------------------------------- | ------------------------------------------- | ---------- | | `TryMinIndex` | `true` + the first smallest element's index | O(n) | | `TryMaxIndex` | `true` + the first largest element's index | O(n) | | `TryMinMaxIndex` | `true` + both, in one pass | O(n) | | [`Clamp`](https://rux-lang.dev/docs/api/algorithms/min-max#clamp) | the value restricted to `low..=high` | O(1) | The extremes are reported as indices, not values, so the caller keeps the identity of the element it found — with a type ordered by one field, two equivalent elements are not interchangeable. All three report the *first* extreme, so `TryMinMaxIndex` agrees exactly with calling the two single searches separately. Scalar two-argument [`Min`](https://rux-lang.dev/docs/api/algorithms/min-max#min) and [`Max`](https://rux-lang.dev/docs/api/algorithms/min-max#max) are deliberately absent: [`Rux/Math`](https://github.com/rux-lang/Rux/blob/main/Packages/Algorithms/../Math){rel=""nofollow""} already owns those names for floating-point values, and a same-named generic here would make a bare `Min(1.0, 2.0)` ambiguous. ### Custom element types Anything requiring `==` works on a struct that defines it: ```rux struct Record { key: int32; origin: int32; } extend Record { func ==(self: &Record, other: Record) -> bool { return self.key == other.key && self.origin == other.origin; } } ``` The receiver is a shared reference: comparison borrows the stored element and cannot mutate, consume, or be null. The right operand remains the operator's value argument. Plain records are structural `Copy` values; types that prohibit copying cannot use algorithms whose operator or callback takes `T` by value. Ordering and search algorithms require `func <` in the same form. A missing operator is reported where the algorithm is instantiated, not where it is declared. ### Guarantees and limitations - **No allocation.** Every function is O(1) auxiliary space and the package depends only on `Rux/Core`. - **Unchecked indexing**, matching native slices and the `At`/`Set` pair on every [`Rux/Collections`](https://github.com/rux-lang/Rux/blob/main/Packages/Algorithms/../Collections){rel=""nofollow""} container: a length larger than the storage is undefined behavior, not a reported error. Those containers also offer `TryGet`/`TrySet`, which check; nothing here does. - **Borrowing, not owning.** A view must not outlive the storage it borrows, and a `Vector` view is invalidated by any growth. - **No closures.** A predicate or comparator is a plain function value carrying no captured state; anything it needs beyond the elements must be reachable from the function itself. - **Caller-provided stability.** [`StableSort`](https://rux-lang.dev/docs/api/algorithms/sorting#stable-sort) requires a scratch `var T[..]` as long as the input, preserving the package's zero-allocation property. - `Algorithms::CopyTo` copies typed elements, while [`Memory::Copy`](https://github.com/rux-lang/Rux/blob/main/Packages/Algorithms/../Memory){rel=""nofollow""} copies raw bytes. `T[..]` and `var T[..]` are borrowed views and copy only their pointer and length, never their elements. Internal pointers used for indexing and pointer arithmetic remain raw. The few scalar output parameters also remain raw pointers; pass writable addresses such as `@smallest` and never pass null unless the function documents it. ## Index ### Functions | Name | Summary | | ------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | [`Contains<T>`](https://rux-lang.dev/docs/api/algorithms/searching#contains) | Whether any element of `items` equals `value`. | | [`Count<T>`](https://rux-lang.dev/docs/api/algorithms/searching#count) | How many elements of `items` equal `value`. | | [`IndexOf<T>`](https://rux-lang.dev/docs/api/algorithms/searching#index-of) | The index of the first element of `items` equal to `value`. | | [`LastIndexOf<T>`](https://rux-lang.dev/docs/api/algorithms/searching#last-index-of) | The index of the last element of `items` equal to `value`. | | [`IndexWhere<T>`](https://rux-lang.dev/docs/api/algorithms/searching#index-where) | The index of the first element of `items` that `predicate` accepts. | | [`LastIndexWhere<T>`](https://rux-lang.dev/docs/api/algorithms/searching#last-index-where) | The index of the last element of `items` that `predicate` accepts. | | [`CountWhere<T>`](https://rux-lang.dev/docs/api/algorithms/searching#count-where) | How many elements of `items` the predicate accepts. | | [`AllOf<T>`](https://rux-lang.dev/docs/api/algorithms/searching#all-of) | Whether `predicate` accepts every element of `items`. | | [`AnyOf<T>`](https://rux-lang.dev/docs/api/algorithms/searching#any-of) | Whether `predicate` accepts at least one element of `items`. | | [`NoneOf<T>`](https://rux-lang.dev/docs/api/algorithms/searching#none-of) | Whether `predicate` accepts no element of `items`. | | [`Mismatch<T>`](https://rux-lang.dev/docs/api/algorithms/comparing#mismatch) | The index of the first position where `left` and `right` differ. | | [`SequenceEqual<T>`](https://rux-lang.dev/docs/api/algorithms/comparing#sequence-equal) | Whether `left` and `right` hold the same elements in the same order. | | [`Compare<T>`](https://rux-lang.dev/docs/api/algorithms/comparing#compare) | How `left` orders against `right`, element by element. | | [`CompareBy<T>`](https://rux-lang.dev/docs/api/algorithms/comparing#compare-by) | How `left` orders against `right`, with `compare` deciding each pair. | | [`Fold<T, A>`](https://rux-lang.dev/docs/api/algorithms/folding#fold) | Folds every element of `items` into an accumulator, left to right. | | [`FoldRight<T, A>`](https://rux-lang.dev/docs/api/algorithms/folding#fold-right) | Folds every element of `items` into an accumulator, right to left. | | [`Sum<T>`](https://rux-lang.dev/docs/api/algorithms/folding#sum) | The sum of `initial` and every element of `items`. | | [`Product<T>`](https://rux-lang.dev/docs/api/algorithms/folding#product) | The product of `initial` and every element of `items`. | | [`Transform<T, U>`](https://rux-lang.dev/docs/api/algorithms/folding#transform) | Writes `transform` of each element of `source` into `destination`. | | [`MakeHeap<T>`](https://rux-lang.dev/docs/api/algorithms/heaps#make-heap) | Rearranges `items` into a max-heap. | | [`PushHeap<T>`](https://rux-lang.dev/docs/api/algorithms/heaps#push-heap) | Restores the heap property after an element has been appended to `items`. | | [`PopHeap<T>`](https://rux-lang.dev/docs/api/algorithms/heaps#pop-heap) | Moves the largest element of `items` to its end and restores the heap property over the rest. | | [`SortHeap<T>`](https://rux-lang.dev/docs/api/algorithms/heaps#sort-heap) | Turns the heap `items` into a sorted sequence, smallest first. | | [`IsHeap<T>`](https://rux-lang.dev/docs/api/algorithms/heaps#is-heap) | Whether `items` is arranged as a max-heap. | | [`IsHeapUntil<T>`](https://rux-lang.dev/docs/api/algorithms/heaps#is-heap-until) | How much of `items` from the front is arranged as a max-heap. | | [`MakeHeapBy<T>`](https://rux-lang.dev/docs/api/algorithms/heaps#make-heap-by) | Rearranges `items` into a max-heap under `compare`. | | [`PushHeapBy<T>`](https://rux-lang.dev/docs/api/algorithms/heaps#push-heap-by) | Restores the heap property under `compare` after an element has been appended to `items`. | | [`PopHeapBy<T>`](https://rux-lang.dev/docs/api/algorithms/heaps#pop-heap-by) | Moves the largest element of `items` under `compare` to its end and restores the heap over the rest. | | [`SortHeapBy<T>`](https://rux-lang.dev/docs/api/algorithms/heaps#sort-heap-by) | Turns the heap `items` into a sequence sorted by `compare`, smallest first. | | [`IsHeapBy<T>`](https://rux-lang.dev/docs/api/algorithms/heaps#is-heap-by) | Whether `items` is arranged as a max-heap under `compare`. | | [`IsHeapUntilBy<T>`](https://rux-lang.dev/docs/api/algorithms/heaps#is-heap-until-by) | How much of `items` from the front is arranged as a max-heap under `compare`. | | [`MinIndex<T>`](https://rux-lang.dev/docs/api/algorithms/min-max#min-index) | The index of the smallest element of `items`. | | [`MaxIndex<T>`](https://rux-lang.dev/docs/api/algorithms/min-max#max-index) | The index of the largest element of `items`. | | [`MinIndexBy<T>`](https://rux-lang.dev/docs/api/algorithms/min-max#min-index-by) | The index of the smallest element of `items`, with `compare` deciding. | | [`MaxIndexBy<T>`](https://rux-lang.dev/docs/api/algorithms/min-max#max-index-by) | The index of the largest element of `items`, with `compare` deciding. | | [`MinMaxIndex<T>`](https://rux-lang.dev/docs/api/algorithms/min-max#min-max-index) | The indices of the smallest and largest elements of `items`, in one pass. | | [`MinMaxIndexBy<T>`](https://rux-lang.dev/docs/api/algorithms/min-max#min-max-index-by) | The indices of the smallest and largest elements of `items`, in one pass, with `compare` deciding. | | [`Min<T>`](https://rux-lang.dev/docs/api/algorithms/min-max#min) | The smaller of two values, or `left` when neither is smaller. | | [`Max<T>`](https://rux-lang.dev/docs/api/algorithms/min-max#max) | The larger of two values, or `left` when neither is larger. | | [`Clamp<T>`](https://rux-lang.dev/docs/api/algorithms/min-max#clamp) | `value` brought into the range `low` to `high`, inclusive at both ends. | | [`ClampBy<T>`](https://rux-lang.dev/docs/api/algorithms/min-max#clamp-by) | `value` brought into the range `low` to `high`, with `compare` deciding. | | [`Swap<T>`](https://rux-lang.dev/docs/api/algorithms/modifying#swap) | Exchanges the values at two locations. | | [`Reverse<T>`](https://rux-lang.dev/docs/api/algorithms/modifying#reverse) | Reverses the order of `items` in place. | | [`Rotate<T>`](https://rux-lang.dev/docs/api/algorithms/modifying#rotate) | Rotates `items` left so that the element at `middle` becomes the first. | | [`Fill<T>`](https://rux-lang.dev/docs/api/algorithms/modifying#fill) | Writes `value` into every position of `items`. | | [`CopyTo<T>`](https://rux-lang.dev/docs/api/algorithms/modifying#copy-to) | Copies `source` into `destination`, front to back. | | [`MoveTo<T>`](https://rux-lang.dev/docs/api/algorithms/modifying#move-to) | Copies `source` into `destination`, correctly however the two overlap. | | [`Unique<T>`](https://rux-lang.dev/docs/api/algorithms/modifying#unique) | Collapses each run of adjacent equal elements in `items` to one, and reports how many are left. | | [`RemoveValue<T>`](https://rux-lang.dev/docs/api/algorithms/modifying#remove-value) | Removes every element of `items` equal to `value`, and reports how many are left. | | [`RemoveWhere<T>`](https://rux-lang.dev/docs/api/algorithms/modifying#remove-where) | Removes every element of `items` that `predicate` accepts, and reports how many are left. | | [`Partition<T>`](https://rux-lang.dev/docs/api/algorithms/modifying#partition) | Moves every element `predicate` accepts to the front of `items`, and reports how many there were. | | [`PartitionPoint<T>`](https://rux-lang.dev/docs/api/algorithms/modifying#partition-point) | Where the accepted elements of an already-partitioned `items` end. | | [`PartialSum<T>`](https://rux-lang.dev/docs/api/algorithms/numeric#partial-sum) | Writes the running sums of `items` into `into`: element `i` becomes the sum of the first `i + 1` elements. | | [`InclusiveScan<T>`](https://rux-lang.dev/docs/api/algorithms/numeric#inclusive-scan) | Writes the running combination of `items` into `into`: element `i` becomes the first `i + 1` elements combined left to right with `combine`. | | [`ExclusiveScan<T>`](https://rux-lang.dev/docs/api/algorithms/numeric#exclusive-scan) | Writes the running combination of `items` before each element into `into`: element `i` becomes `initial` combined with the first `i` elements, so the first result is `initial` and the last element of `items` takes part in none. | | [`Iota<T>`](https://rux-lang.dev/docs/api/algorithms/numeric#iota) | Fills `into` with `start`, `start + step`, `start + 2 * step` and so on. | | [`Midpoint`](https://rux-lang.dev/docs/api/algorithms/numeric#midpoint) | Halfway between `a` and `b`, without overflowing to infinity when both are near the largest finite value. | | [`IsSorted<T>`](https://rux-lang.dev/docs/api/algorithms/sorted-slices#is-sorted) | Whether `items` is in non-decreasing order. | | [`IsSortedUntil<T>`](https://rux-lang.dev/docs/api/algorithms/sorted-slices#is-sorted-until) | How far `items` is in non-decreasing order. | | [`LowerBound<T>`](https://rux-lang.dev/docs/api/algorithms/sorted-slices#lower-bound) | The first position where `value` could be inserted without breaking the order. | | [`UpperBound<T>`](https://rux-lang.dev/docs/api/algorithms/sorted-slices#upper-bound) | The last position where `value` could be inserted without breaking the order. | | [`BinarySearch<T>`](https://rux-lang.dev/docs/api/algorithms/sorted-slices#binary-search) | The index of an element of `items` equal to `value`. | | [`EqualRange<T>`](https://rux-lang.dev/docs/api/algorithms/sorted-slices#equal-range) | The range of positions in `items` holding elements equal to `value`. | | [`IsSortedBy<T>`](https://rux-lang.dev/docs/api/algorithms/sorted-slices#is-sorted-by) | Whether `items` is in non-decreasing order under `compare`. | | [`IsSortedUntilBy<T>`](https://rux-lang.dev/docs/api/algorithms/sorted-slices#is-sorted-until-by) | How far `items` is in non-decreasing order under `compare`. | | [`LowerBoundBy<T>`](https://rux-lang.dev/docs/api/algorithms/sorted-slices#lower-bound-by) | The first position where `value` could be inserted into `items` under `compare` without breaking the order. | | [`UpperBoundBy<T>`](https://rux-lang.dev/docs/api/algorithms/sorted-slices#upper-bound-by) | The last position where `value` could be inserted into `items` under `compare` without breaking the order. | | [`BinarySearchBy<T>`](https://rux-lang.dev/docs/api/algorithms/sorted-slices#binary-search-by) | The index of an element of `items` that `compare` calls equal to `value`. | | [`EqualRangeBy<T>`](https://rux-lang.dev/docs/api/algorithms/sorted-slices#equal-range-by) | The range of positions in `items` holding elements `compare` calls equal to `value`. | | [`Sort<T>`](https://rux-lang.dev/docs/api/algorithms/sorting#sort) | Puts `items` into non-decreasing order. | | [`SortDescending<T>`](https://rux-lang.dev/docs/api/algorithms/sorting#sort-descending) | Puts `items` into non-increasing order. | | [`NthElement<T>`](https://rux-lang.dev/docs/api/algorithms/sorting#nth-element) | Puts the element that belongs at `n` in a fully sorted `items` at `n`, and partitions around it. | | [`PartialSort<T>`](https://rux-lang.dev/docs/api/algorithms/sorting#partial-sort) | Puts the `count` smallest elements of `items` in order at its front. | | [`InsertionSortRange<T>`](https://rux-lang.dev/docs/api/algorithms/sorting#insertion-sort-range) | Provides the public `InsertionSortRange` operation. | | [`HeapSortRange<T>`](https://rux-lang.dev/docs/api/algorithms/sorting#heap-sort-range) | Provides the public `HeapSortRange` operation. | | [`SortBy<T>`](https://rux-lang.dev/docs/api/algorithms/sorting#sort-by) | Puts `items` into the order `compare` describes, smallest first. | | [`SortDescendingBy<T>`](https://rux-lang.dev/docs/api/algorithms/sorting#sort-descending-by) | Puts `items` into the reverse of the order `compare` describes. | | [`NthElementBy<T>`](https://rux-lang.dev/docs/api/algorithms/sorting#nth-element-by) | Puts the element that belongs at `n` under `compare` at `n`, and partitions around it. | | [`PartialSortBy<T>`](https://rux-lang.dev/docs/api/algorithms/sorting#partial-sort-by) | Puts the `count` smallest elements of `items` under `compare` in order at its front. | | [`RequiredScratch`](https://rux-lang.dev/docs/api/algorithms/sorting#required-scratch) | How much scratch storage a stable sort of `length` elements needs. | | [`StableSort<T>`](https://rux-lang.dev/docs/api/algorithms/sorting#stable-sort) | Puts `items` into non-decreasing order, leaving equal elements in the order they were in. | | [`StableSortBy<T>`](https://rux-lang.dev/docs/api/algorithms/sorting#stable-sort-by) | Puts `items` into the order `compare` describes, leaving equivalent elements in the order they were in. | # Comparing slices Element-by-element equality, the first difference and lexicographic order between two slices. ## `Mismatch<T>` ```rux pub func Mismatch<T>(left: T[..], right: T[..]) -> uint? ``` The index of the first position where `left` and `right` differ. Both are borrowed and read. Reports `none` when neither runs out before a difference is found and the two are equal for their whole common length — so two slices of different lengths that agree on the shorter one report the shorter length, and two identical slices report `none`. Cannot fail. Runs in time proportional to the shorter length and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Algorithms/Src/Find.rux#L194){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | ---------------- | | `T` | the element type | **Parameters** | Name | Type | Description | | ------- | ------- | ------------------------ | | `left` | `T[..]` | one of the two sequences | | `right` | `T[..]` | the other | **Returns**: the first index where the two differ, or `none` when neither runs out first ## `SequenceEqual<T>` ```rux pub func SequenceEqual<T>(left: T[..], right: T[..]) -> bool ``` Whether `left` and `right` hold the same elements in the same order. Both are borrowed and read. Different lengths are never equal, and two empty slices are, whatever their data pointers hold. Cannot fail. Runs in time proportional to the shorter length and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Algorithms/Src/Find.rux#L214){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | ---------------- | | `T` | the element type | **Parameters** | Name | Type | Description | | ------- | ------- | ------------------------ | | `left` | `T[..]` | one of the two sequences | | `right` | `T[..]` | the other | **Returns**: whether both hold the same elements in the same order ## `Compare<T>` ```rux pub func Compare<T>(left: T[..], right: T[..]) -> Ordering ``` How `left` orders against `right`, element by element. Both are borrowed and read. The comparison is lexicographic, which is the order a dictionary uses: the first position where the two differ decides, and if neither differs before one runs out, the shorter is the smaller. Two equal-length slices that never differ are `Equal`. Requires `<` and `==` on the element type. Use [`CompareBy`](https://rux-lang.dev/docs/api/algorithms/comparing#compare-by) where the element has no ordering of its own or the wanted order is not its own. Cannot fail. Runs in time proportional to the shorter length and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Algorithms/Src/Find.rux#L231){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | ---------------- | | `T` | the element type | **Parameters** | Name | Type | Description | | ------- | ------- | ------------------------ | | `left` | `T[..]` | one of the two sequences | | `right` | `T[..]` | the other | **Returns**: how `left` orders against `right`, comparing element by element then by length ## `CompareBy<T>` ```rux pub func CompareBy<T>( left: T[..], right: T[..], compare: func(T, T) -> Ordering ) -> Ordering ``` How `left` orders against `right`, with `compare` deciding each pair. Both slices are borrowed and read; `compare` is called at most once per position of the shorter one. Lexicographic exactly as [`Compare`](https://rux-lang.dev/docs/api/algorithms/comparing#compare) is, and the way to order a sequence whose elements have no `<` of their own — or to order it by something other than their own. Cannot fail. Runs in time proportional to the shorter length and allocates nothing beyond whatever `compare` does. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Algorithms/Src/Find.rux#L255){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | ---------------- | | `T` | the element type | **Parameters** | Name | Type | Description | | --------- | ------------------------ | ----------------------------------------- | | `left` | `T[..]` | one of the two sequences | | `right` | `T[..]` | the other | | `compare` | `func(T, T) -> Ordering` | how two elements order against each other | **Returns**: how `left` orders against `right` under `compare`, then by length # Folding Reducing a slice to one value, and mapping one slice onto another. ## `Fold<T, A>` ```rux pub func Fold<T, A>( items: T[..], initial: A, combine: func(A, T) -> A ) -> A ``` Folds every element of `items` into an accumulator, left to right. `items` is borrowed and read; `initial` is read by value and returned when the sequence is empty; `combine` is called once per element with the accumulator so far and the element. The accumulator's type is independent of the element's. Left to right is part of the contract rather than an implementation detail: a `combine` that is not associative gives a different answer in the other direction, and callers depend on the order. Cannot fail. Runs in time proportional to the length and allocates nothing beyond whatever `combine` does. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Algorithms/Src/Fold.rux#L29){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | ---------------------------- | | `T` | the element type | | `A` | the accumulated value's type | **Parameters** | Name | Type | Description | | --------- | ----------------- | --------------------------------------------- | | `items` | `T[..]` | the sequence to work on | | `initial` | `A` | the value to start from | | `combine` | `func(A, T) -> A` | how to fold an element into the running value | **Returns**: the value left after folding every element into it ## `FoldRight<T, A>` ```rux pub func FoldRight<T, A>( items: T[..], initial: A, combine: func(A, T) -> A ) -> A ``` Folds every element of `items` into an accumulator, right to left. `items` is borrowed and read; `initial` is read by value and returned when the sequence is empty; `combine` is called once per element with the accumulator so far and the element, starting from the last. The mirror of [`Fold`](https://rux-lang.dev/docs/api/algorithms/folding#fold), and a different answer for any `combine` that is not associative. Cannot fail. Runs in time proportional to the length and allocates nothing beyond whatever `combine` does. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Algorithms/Src/Fold.rux#L51){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | ---------------------------- | | `T` | the element type | | `A` | the accumulated value's type | **Parameters** | Name | Type | Description | | --------- | ----------------- | --------------------------------------------- | | `items` | `T[..]` | the sequence to work on | | `initial` | `A` | the value to start from | | `combine` | `func(A, T) -> A` | how to fold an element into the running value | **Returns**: the value left after folding every element into it, from the end ## `Sum<T>` ```rux pub func Sum<T>(items: T[..], initial: T) -> T ``` The sum of `initial` and every element of `items`. `items` is borrowed and read; `initial` is read by value and is what an empty sequence gives back. The starting value is asked for rather than assumed, because a generic element type has no zero this package could name. Requires `+` on the element type. Overflow behaves exactly as `+` does on that type: this does not check, and a caller who needs checking folds a checked addition instead. Cannot fail. Runs in time proportional to the length and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Algorithms/Src/Fold.rux#L72){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | ---------------- | | `T` | the element type | **Parameters** | Name | Type | Description | | --------- | ------- | ----------------------- | | `items` | `T[..]` | the sequence to work on | | `initial` | `T` | the value to start from | **Returns**: `initial` plus every element ## `Product<T>` ```rux pub func Product<T>(items: T[..], initial: T) -> T ``` The product of `initial` and every element of `items`. `items` is borrowed and read; `initial` is read by value and is what an empty sequence gives back — which is why it must be one rather than zero for the answer to mean anything. Requires `*` on the element type. Overflow behaves exactly as `*` does on that type. Cannot fail. Runs in time proportional to the length and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Algorithms/Src/Fold.rux#L92){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | ---------------- | | `T` | the element type | **Parameters** | Name | Type | Description | | --------- | ------- | ----------------------- | | `items` | `T[..]` | the sequence to work on | | `initial` | `T` | the value to start from | **Returns**: `initial` times every element ## `Transform<T, U>` ```rux pub func Transform<T, U>( destination: var U[..], source: T[..], transform: func(T) -> U ) -> bool ``` Writes `transform` of each element of `source` into `destination`. `source` is borrowed and read; `destination` is borrowed mutably and written; `transform` is called once per element. The two sequences may have different element types, and may be the same storage when they do not. Reports false, having written nothing, when the two lengths differ — for the same reason [`CopyTo`](https://rux-lang.dev/docs/api/algorithms/modifying#copy-to) does: a partial result is worse than a refused one when the caller cannot tell how far it got. Runs in time proportional to the length and allocates nothing beyond whatever `transform` does. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Algorithms/Src/Fold.rux#L115){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | ---------------------------- | | `T` | the element type | | `U` | the destination element type | **Parameters** | Name | Type | Description | | ------------- | -------------- | --------------------------------------------------- | | `destination` | `var U[..]` | where the results go | | `source` | `T[..]` | where the elements come from | | `transform` | `func(T) -> U` | how to turn a source element into a destination one | **Returns**: whether `destination` was long enough to hold every result # Heaps A binary max-heap laid out in the slice itself, the building block of a priority queue. ## `MakeHeap<T>` ```rux pub func MakeHeap<T>(items: var T[..]) ``` Rearranges `items` into a max-heap. `items` is borrowed mutably and rewritten. Fewer than two elements are already a heap. The arrangement is not an order: only the first element ends up where a sorted sequence would put it. Requires `<` on the element type. Cannot fail. Runs in time proportional to the length — linear, not `n log n`, because sifting from the bottom up does most of its work on the short subtrees near the leaves. Allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Algorithms/Src/Heap.rux#L24){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | ---------------- | | `T` | the element type | **Parameters** | Name | Type | Description | | ------- | ----------- | ----------------------- | | `items` | `var T[..]` | the sequence to work on | ## `PushHeap<T>` ```rux pub func PushHeap<T>(items: var T[..]) ``` Restores the heap property after an element has been appended to `items`. `items` is borrowed mutably and rewritten; it must be the whole heap including the new last element, and everything before that element must already be a heap. An empty view does nothing. The caller appends and this repairs, because appending is the storage owner's business. Requires `<` on the element type. Cannot fail. Runs in time proportional to the logarithm of the length and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Algorithms/Src/Heap.rux#L42){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | ---------------- | | `T` | the element type | **Parameters** | Name | Type | Description | | ------- | ----------- | ----------------------- | | `items` | `var T[..]` | the sequence to work on | ## `PopHeap<T>` ```rux pub func PopHeap<T>(items: var T[..]) ``` Moves the largest element of `items` to its end and restores the heap property over the rest. `items` is borrowed mutably and rewritten. Afterwards the largest element sits at the last position and the first `length - 1` positions are a heap again; the caller is what shortens the sequence, or leaves the element there. Fewer than two elements do nothing. Requires `<` on the element type. Cannot fail. Runs in time proportional to the logarithm of the length and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Algorithms/Src/Heap.rux#L56){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | ---------------- | | `T` | the element type | **Parameters** | Name | Type | Description | | ------- | ----------- | ----------------------- | | `items` | `var T[..]` | the sequence to work on | ## `SortHeap<T>` ```rux pub func SortHeap<T>(items: var T[..]) ``` Turns the heap `items` into a sorted sequence, smallest first. `items` is borrowed mutably and rewritten; it must already be a heap, which [`MakeHeap`](https://rux-lang.dev/docs/api/algorithms/heaps#make-heap) is what makes it. Repeated popping, which is exactly heapsort. A sequence that is not a heap does not fail; it comes out rearranged and not sorted. Requires `<` on the element type. Cannot fail. Makes O(n log n) comparisons and allocates nothing. Equal elements may be reordered. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Algorithms/Src/Heap.rux#L74){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | ---------------- | | `T` | the element type | **Parameters** | Name | Type | Description | | ------- | ----------- | ----------------------- | | `items` | `var T[..]` | the sequence to work on | ## `IsHeap<T>` ```rux pub func IsHeap<T>(items: T[..]) -> bool ``` Whether `items` is arranged as a max-heap. `items` is borrowed and read. An empty sequence and a single element are heaps, there being no pair to violate the property. Requires `<` on the element type. Cannot fail. Runs in time proportional to the length and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Algorithms/Src/Heap.rux#L91){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | ---------------- | | `T` | the element type | **Parameters** | Name | Type | Description | | ------- | ------- | ----------------------- | | `items` | `T[..]` | the sequence to work on | **Returns**: whether the sequence satisfies the heap property throughout ## `IsHeapUntil<T>` ```rux pub func IsHeapUntil<T>(items: T[..]) -> uint ``` How much of `items` from the front is arranged as a max-heap. `items` is borrowed and read. Returns the length when the whole sequence is a heap, and otherwise the index of the first element larger than its parent. Requires `<` on the element type. Cannot fail. Runs in time proportional to the answer and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Algorithms/Src/Heap.rux#L104){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | ---------------- | | `T` | the element type | **Parameters** | Name | Type | Description | | ------- | ------- | ----------------------- | | `items` | `T[..]` | the sequence to work on | **Returns**: how many leading elements satisfy the heap property ## `MakeHeapBy<T>` ```rux pub func MakeHeapBy<T>( items: var T[..], compare: func(T, T) -> Ordering ) ``` Rearranges `items` into a max-heap under `compare`. `items` is borrowed mutably and rewritten; `compare` must be a strict weak ordering. Fewer than two elements are already a heap. Cannot fail. Runs in time proportional to the length and allocates nothing beyond whatever `compare` does. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Algorithms/Src/Heap.rux#L153){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | ---------------- | | `T` | the element type | **Parameters** | Name | Type | Description | | --------- | ------------------------ | ----------------------------------------- | | `items` | `var T[..]` | the sequence to work on | | `compare` | `func(T, T) -> Ordering` | how two elements order against each other | ## `PushHeapBy<T>` ```rux pub func PushHeapBy<T>( items: var T[..], compare: func(T, T) -> Ordering ) ``` Restores the heap property under `compare` after an element has been appended to `items`. `items` is borrowed mutably and rewritten; everything before its last element must already be a heap. Cannot fail. Runs in time proportional to the logarithm of the length and allocates nothing beyond whatever `compare` does. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Algorithms/Src/Heap.rux#L170){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | ---------------- | | `T` | the element type | **Parameters** | Name | Type | Description | | --------- | ------------------------ | ----------------------------------------- | | `items` | `var T[..]` | the sequence to work on | | `compare` | `func(T, T) -> Ordering` | how two elements order against each other | ## `PopHeapBy<T>` ```rux pub func PopHeapBy<T>( items: var T[..], compare: func(T, T) -> Ordering ) ``` Moves the largest element of `items` under `compare` to its end and restores the heap over the rest. `items` is borrowed mutably and rewritten. The caller is what shortens the sequence afterwards. Cannot fail. Runs in time proportional to the logarithm of the length and allocates nothing beyond whatever `compare` does. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Algorithms/Src/Heap.rux#L183){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | ---------------- | | `T` | the element type | **Parameters** | Name | Type | Description | | --------- | ------------------------ | ----------------------------------------- | | `items` | `var T[..]` | the sequence to work on | | `compare` | `func(T, T) -> Ordering` | how two elements order against each other | ## `SortHeapBy<T>` ```rux pub func SortHeapBy<T>( items: var T[..], compare: func(T, T) -> Ordering ) ``` Turns the heap `items` into a sequence sorted by `compare`, smallest first. `items` is borrowed mutably and rewritten and must already be a heap under the same comparison. Cannot fail. Makes O(n log n) comparisons and allocates nothing beyond whatever `compare` does. Equivalent elements may be reordered. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Algorithms/Src/Heap.rux#L200){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | ---------------- | | `T` | the element type | **Parameters** | Name | Type | Description | | --------- | ------------------------ | ----------------------------------------- | | `items` | `var T[..]` | the sequence to work on | | `compare` | `func(T, T) -> Ordering` | how two elements order against each other | ## `IsHeapBy<T>` ```rux pub func IsHeapBy<T>( items: T[..], compare: func(T, T) -> Ordering ) -> bool ``` Whether `items` is arranged as a max-heap under `compare`. `items` is borrowed and read. An empty sequence and a single element are heaps. Cannot fail. Runs in time proportional to the length and allocates nothing beyond whatever `compare` does. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Algorithms/Src/Heap.rux#L216){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | ---------------- | | `T` | the element type | **Parameters** | Name | Type | Description | | --------- | ------------------------ | ----------------------------------------- | | `items` | `T[..]` | the sequence to work on | | `compare` | `func(T, T) -> Ordering` | how two elements order against each other | **Returns**: whether the sequence satisfies the heap property throughout under `compare` ## `IsHeapUntilBy<T>` ```rux pub func IsHeapUntilBy<T>( items: T[..], compare: func(T, T) -> Ordering ) -> uint ``` How much of `items` from the front is arranged as a max-heap under `compare`. `items` is borrowed and read. Returns the length when the whole sequence is a heap, and otherwise the index of the first element larger than its parent. Cannot fail. Runs in time proportional to the answer and allocates nothing beyond whatever `compare` does. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Algorithms/Src/Heap.rux#L229){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | ---------------- | | `T` | the element type | **Parameters** | Name | Type | Description | | --------- | ------------------------ | ----------------------------------------- | | `items` | `T[..]` | the sequence to work on | | `compare` | `func(T, T) -> Ordering` | how two elements order against each other | **Returns**: how many leading elements satisfy the heap property under `compare` # Minimum and maximum The smallest and largest elements of a slice, and clamping a value into a range. ## `MinIndex<T>` ```rux pub func MinIndex<T>(items: T[..]) -> uint? ``` The index of the smallest element of `items`. `items` is borrowed and read. Reports `none` for an empty slice, and the earliest index when several elements tie. Requires `<` on the element type. Cannot fail. Runs in time proportional to the length, comparing each element once, and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Algorithms/Src/MinMax.rux#L22){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | ---------------- | | `T` | the element type | **Parameters** | Name | Type | Description | | ------- | ------- | ----------------------- | | `items` | `T[..]` | the sequence to work on | **Returns**: the index of the smallest element, the first when several tie, or `none` when empty ## `MaxIndex<T>` ```rux pub func MaxIndex<T>(items: T[..]) -> uint? ``` The index of the largest element of `items`. `items` is borrowed and read. Reports `none` for an empty slice, and the earliest index when several elements tie. Requires `<` on the element type. Cannot fail. Runs in time proportional to the length and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Algorithms/Src/MinMax.rux#L44){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | ---------------- | | `T` | the element type | **Parameters** | Name | Type | Description | | ------- | ------- | ----------------------- | | `items` | `T[..]` | the sequence to work on | **Returns**: the index of the largest element, the first when several tie, or `none` when empty ## `MinIndexBy<T>` ```rux pub func MinIndexBy<T>( items: T[..], compare: func(T, T) -> Ordering ) -> uint? ``` The index of the smallest element of `items`, with `compare` deciding. `items` is borrowed and read; `compare` is called once per element after the first. Reports `none` for an empty slice, and the earliest index when several elements tie. Cannot fail. Runs in time proportional to the length and allocates nothing beyond whatever `compare` does. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Algorithms/Src/MinMax.rux#L66){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | ---------------- | | `T` | the element type | **Parameters** | Name | Type | Description | | --------- | ------------------------ | ----------------------------------------- | | `items` | `T[..]` | the sequence to work on | | `compare` | `func(T, T) -> Ordering` | how two elements order against each other | **Returns**: the index of the smallest element under `compare`, or `none` when empty ## `MaxIndexBy<T>` ```rux pub func MaxIndexBy<T>( items: T[..], compare: func(T, T) -> Ordering ) -> uint? ``` The index of the largest element of `items`, with `compare` deciding. `items` is borrowed and read; `compare` is called once per element after the first. Reports `none` for an empty slice, and the earliest index when several elements tie. Cannot fail. Runs in time proportional to the length and allocates nothing beyond whatever `compare` does. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Algorithms/Src/MinMax.rux#L88){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | ---------------- | | `T` | the element type | **Parameters** | Name | Type | Description | | --------- | ------------------------ | ----------------------------------------- | | `items` | `T[..]` | the sequence to work on | | `compare` | `func(T, T) -> Ordering` | how two elements order against each other | **Returns**: the index of the largest element under `compare`, or `none` when empty ## `MinMaxIndex<T>` ```rux pub func MinMaxIndex<T>( items: T[..], smallest: *var uint, largest: *var uint ) -> bool ``` The indices of the smallest and largest elements of `items`, in one pass. `items` is borrowed and read; `smallest` and `largest` are written only when this reports true. Reports false for an empty slice and writes neither. Ties go to the earliest index on both ends, exactly as the single-ended searches promise. Two separate passes would compare each element twice; this compares them in pairs and so makes about three comparisons for every two elements. Requires `<` on the element type. Cannot fail. Runs in time proportional to the length and allocates nothing. `smallest` and `largest` must be non-null and writable. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Algorithms/Src/MinMax.rux#L116){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | ---------------- | | `T` | the element type | **Parameters** | Name | Type | Description | | ---------- | ----------- | ------------------------------------------ | | `items` | `T[..]` | the sequence to work on | | `smallest` | `*var uint` | receives the index of the smallest element | | `largest` | `*var uint` | receives the index of the largest element | **Returns**: whether there was anything to report, which an empty sequence is not ## `MinMaxIndexBy<T>` ```rux pub func MinMaxIndexBy<T>( items: T[..], compare: func(T, T) -> Ordering, smallest: *var uint, largest: *var uint ) -> bool ``` The indices of the smallest and largest elements of `items`, in one pass, with `compare` deciding. `items` is borrowed and read; `smallest` and `largest` are written only when this reports true. Reports false for an empty slice and writes neither. Ties go to the earliest index on both ends. Cannot fail. Runs in time proportional to the length and allocates nothing beyond whatever `compare` does. `smallest` and `largest` must be non-null and writable. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Algorithms/Src/MinMax.rux#L147){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | ---------------- | | `T` | the element type | **Parameters** | Name | Type | Description | | ---------- | ------------------------ | ------------------------------------------ | | `items` | `T[..]` | the sequence to work on | | `compare` | `func(T, T) -> Ordering` | how two elements order against each other | | `smallest` | `*var uint` | receives the index of the smallest element | | `largest` | `*var uint` | receives the index of the largest element | **Returns**: whether there was anything to report, which an empty sequence is not ## `Min<T>` ```rux pub func Min<T>(left: T, right: T) -> T ``` The smaller of two values, or `left` when neither is smaller. Both are read by value and one is returned by copy. Requires `<` on the type. Cannot fail. Runs in constant time and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Algorithms/Src/MinMax.rux#L175){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | ---------------- | | `T` | the element type | **Parameters** | Name | Type | Description | | ------- | ---- | --------------------- | | `left` | `T` | one of the two values | | `right` | `T` | the other | **Returns**: the smaller of the two, or `left` when they tie ## `Max<T>` ```rux pub func Max<T>(left: T, right: T) -> T ``` The larger of two values, or `left` when neither is larger. Both are read by value and one is returned by copy. Requires `<` on the type. Cannot fail. Runs in constant time and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Algorithms/Src/MinMax.rux#L188){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | ---------------- | | `T` | the element type | **Parameters** | Name | Type | Description | | ------- | ---- | --------------------- | | `left` | `T` | one of the two values | | `right` | `T` | the other | **Returns**: the larger of the two, or `left` when they tie ## `Clamp<T>` ```rux pub func Clamp<T>(value: T, low: T, high: T) -> T ``` `value` brought into the range `low` to `high`, inclusive at both ends. All three are read by value and one is returned by copy. A `low` above `high` is an empty range with no answer that could be right, so `low` is returned — the caller passed a range it cannot have meant. Requires `<` on the type. Cannot fail. Runs in constant time and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Algorithms/Src/MinMax.rux#L204){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | ---------------- | | `T` | the element type | **Parameters** | Name | Type | Description | | ------- | ---- | ----------------------------- | | `value` | `T` | the value to bring into range | | `low` | `T` | the lowest allowed value | | `high` | `T` | the highest allowed value | **Returns**: `value` brought into `[low, high]` ## `ClampBy<T>` ```rux pub func ClampBy<T>( value: T, low: T, high: T, compare: func(T, T) -> Ordering ) -> T ``` `value` brought into the range `low` to `high`, with `compare` deciding. All three values are read by value and one is returned by copy; `compare` is called at most three times. A `low` above `high` returns `low`, exactly as [`Clamp`](https://rux-lang.dev/docs/api/algorithms/min-max#clamp) does. Cannot fail. Runs in constant time and allocates nothing beyond whatever `compare` does. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Algorithms/Src/MinMax.rux#L222){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | ---------------- | | `T` | the element type | **Parameters** | Name | Type | Description | | --------- | ------------------------ | ----------------------------------------- | | `value` | `T` | the value to bring into range | | `low` | `T` | the lowest allowed value | | `high` | `T` | the highest allowed value | | `compare` | `func(T, T) -> Ordering` | how two elements order against each other | **Returns**: `value` brought into `[low, high]` under `compare` # Modifying Rearranging a slice in place, removing elements, and moving elements between slices. ## `Swap<T>` ```rux pub func Swap<T>(left: *var T, right: *var T) ``` Exchanges the values at two locations. Both are borrowed mutably and both are written. Passing the same location twice is legal and leaves it alone. Cannot fail. Runs in constant time and allocates nothing. Both pointers must be non-null and writable. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Algorithms/Src/Modify.rux#L20){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | ---------------- | | `T` | the element type | **Parameters** | Name | Type | Description | | ------- | -------- | ----------------------- | | `left` | `*var T` | one of the two elements | | `right` | `*var T` | the other | ## `Reverse<T>` ```rux pub func Reverse<T>(items: var T[..]) ``` Reverses the order of `items` in place. `items` is borrowed mutably and rewritten. An empty slice and a single element are already reversed, so neither is a special case. Cannot fail. Runs in time proportional to the length, making half as many exchanges, and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Algorithms/Src/Modify.rux#L33){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | ---------------- | | `T` | the element type | **Parameters** | Name | Type | Description | | ------- | ----------- | ----------------------- | | `items` | `var T[..]` | the sequence to work on | ## `Rotate<T>` ```rux pub func Rotate<T>(items: var T[..], middle: uint) -> bool ``` Rotates `items` left so that the element at `middle` becomes the first. `items` is borrowed mutably and rewritten. A `middle` of zero or of the whole length leaves the order alone; anything past the length is refused, since there is no such element to bring to the front. Done as three reversals — the front, the back, then the whole — which needs no scratch storage and touches every element at most twice. Reports false only for a `middle` past the length. Runs in time proportional to the length and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Algorithms/Src/Modify.rux#L56){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | ---------------- | | `T` | the element type | **Parameters** | Name | Type | Description | | -------- | ----------- | -------------------------------------------- | | `items` | `var T[..]` | the sequence to work on | | `middle` | `uint` | the index that becomes the new first element | **Returns**: whether `middle` was a usable index ## `Fill<T>` ```rux pub func Fill<T>(items: var T[..], value: T) ``` Writes `value` into every position of `items`. `items` is borrowed mutably and rewritten; `value` is read by value and copied into each position. An empty slice writes nothing. Cannot fail. Runs in time proportional to the length and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Algorithms/Src/Modify.rux#L73){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | ---------------- | | `T` | the element type | **Parameters** | Name | Type | Description | | ------- | ----------- | ----------------------------------- | | `items` | `var T[..]` | the sequence to work on | | `value` | `T` | the value to write to every element | ## `CopyTo<T>` ```rux pub func CopyTo<T>( destination: var T[..], source: T[..] ) -> bool ``` Copies `source` into `destination`, front to back. `destination` is borrowed mutably and written; `source` is borrowed and read. Reports false when the two lengths differ, having written nothing: a partial copy is worse than a refused one, since the caller cannot tell how far it got. The two must not overlap, unless `destination` begins at or before `source`. Use [`MoveTo`](https://rux-lang.dev/docs/api/algorithms/modifying#move-to) where they might. Runs in time proportional to the length and allocates nothing. Overlapping the wrong way silently copies elements that were already overwritten. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Algorithms/Src/Modify.rux#L93){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | ---------------- | | `T` | the element type | **Parameters** | Name | Type | Description | | ------------- | ----------- | ---------------------------- | | `destination` | `var T[..]` | where the results go | | `source` | `T[..]` | where the elements come from | **Returns**: whether `destination` was long enough ## `MoveTo<T>` ```rux pub func MoveTo<T>( destination: var T[..], source: T[..] ) -> bool ``` Copies `source` into `destination`, correctly however the two overlap. `destination` is borrowed mutably and written; `source` is borrowed and read. Reports false when the two lengths differ, having written nothing. Copies back to front when `destination` starts after `source`, and front to back otherwise, which is what makes shifting a run of elements along its own storage safe in either direction. Runs in time proportional to the length and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Algorithms/Src/Modify.rux#L114){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | ---------------- | | `T` | the element type | **Parameters** | Name | Type | Description | | ------------- | ----------- | ---------------------------- | | `destination` | `var T[..]` | where the results go | | `source` | `T[..]` | where the elements come from | **Returns**: whether `destination` was long enough ## `Unique<T>` ```rux pub func Unique<T>(items: var T[..]) -> uint ``` Collapses each run of adjacent equal elements in `items` to one, and reports how many are left. `items` is borrowed mutably and rewritten. Only *adjacent* duplicates go: on a sorted slice that removes every duplicate, and on an unsorted one it removes only the runs, which is the useful behaviour rather than a compromise — it makes this the second half of sort-then-unique without paying for a second sort. Relative order among the survivors is preserved, nothing is resized, and what lies past the reported length is unspecified. Requires `==` on the element type. Cannot fail. Runs in time proportional to the length and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Algorithms/Src/Modify.rux#L137){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | ---------------- | | `T` | the element type | **Parameters** | Name | Type | Description | | ------- | ----------- | ----------------------- | | `items` | `var T[..]` | the sequence to work on | **Returns**: how many elements are left after collapsing each run of equal neighbours to one ## `RemoveValue<T>` ```rux pub func RemoveValue<T>(items: var T[..], value: T) -> uint ``` Removes every element of `items` equal to `value`, and reports how many are left. `items` is borrowed mutably and rewritten; `value` is read by value. Survivors are compacted toward the front in their original order, nothing is resized, and what lies past the reported length is unspecified. Requires `==` on the element type. Cannot fail. Runs in time proportional to the length and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Algorithms/Src/Modify.rux#L161){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | ---------------- | | `T` | the element type | **Parameters** | Name | Type | Description | | ------- | ----------- | --------------------------------------- | | `items` | `var T[..]` | the sequence to work on | | `value` | `T` | the value to remove every occurrence of | **Returns**: how many elements are left ## `RemoveWhere<T>` ```rux pub func RemoveWhere<T>( items: var T[..], predicate: func(T) -> bool ) -> uint ``` Removes every element of `items` that `predicate` accepts, and reports how many are left. `items` is borrowed mutably and rewritten; `predicate` is called once per element. Survivors are compacted toward the front in their original order, nothing is resized, and what lies past the reported length is unspecified. Cannot fail. Runs in time proportional to the length and allocates nothing beyond whatever `predicate` does. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Algorithms/Src/Modify.rux#L183){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | ---------------- | | `T` | the element type | **Parameters** | Name | Type | Description | | ----------- | ----------------- | ------------------------------- | | `items` | `var T[..]` | the sequence to work on | | `predicate` | `func(T) -> bool` | the test each element is put to | **Returns**: how many elements are left ## `Partition<T>` ```rux pub func Partition<T>( items: var T[..], predicate: func(T) -> bool ) -> uint ``` Moves every element `predicate` accepts to the front of `items`, and reports how many there were. `items` is borrowed mutably and rewritten; `predicate` is called once per element. Everything before the reported index satisfies the predicate and everything from it on does not. Order within each group is *not* preserved: this exchanges elements from both ends inward, which is what keeps it to one pass and no scratch storage. A caller that needs the original order within each group needs a stable partition, which needs somewhere to put things. Cannot fail. Runs in time proportional to the length and allocates nothing beyond whatever `predicate` does. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Algorithms/Src/Modify.rux#L208){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | ---------------- | | `T` | the element type | **Parameters** | Name | Type | Description | | ----------- | ----------------- | ------------------------------- | | `items` | `var T[..]` | the sequence to work on | | `predicate` | `func(T) -> bool` | the test each element is put to | **Returns**: the index of the first element that fails `predicate` ## `PartitionPoint<T>` ```rux pub func PartitionPoint<T>( items: T[..], predicate: func(T) -> bool ) -> uint ``` Where the accepted elements of an already-partitioned `items` end. `items` is borrowed and read; `predicate` is called about as many times as the logarithm of the length. Requires that every element the predicate accepts comes before every element it rejects — which is what [`Partition`](https://rux-lang.dev/docs/api/algorithms/modifying#partition) leaves behind, and what a sorted slice is with respect to any threshold predicate. A slice that is not partitioned this way does not fail; it answers, and the answer is meaningless. Cannot fail. Runs in time proportional to the logarithm of the length and allocates nothing beyond whatever `predicate` does. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Algorithms/Src/Modify.rux#L235){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | ---------------- | | `T` | the element type | **Parameters** | Name | Type | Description | | ----------- | ----------------- | ------------------------------- | | `items` | `T[..]` | the sequence to work on | | `predicate` | `func(T) -> bool` | the test each element is put to | **Returns**: the index of the first element that fails `predicate`, assuming the sequence is partitioned # Numeric sequences Running sums and scans, counting sequences, and an overflow-free midpoint. ## `PartialSum<T>` ```rux pub func PartialSum<T>( items: T[..], into: var T[..] ) -> bool ``` Writes the running sums of `items` into `into`: element `i` becomes the sum of the first `i + 1` elements. `into` may be `items` itself. Requires `+` on the element type, with whatever overflow it has. Runs in time proportional to the length and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Algorithms/Src/Numeric.rux#L17){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | ---------------- | | `T` | the element type | **Parameters** | Name | Type | Description | | ------- | ----------- | ---------------------------------------------- | | `items` | `T[..]` | the sequence to sum | | `into` | `var T[..]` | where the sums go, at least as long as `items` | **Returns**: whether `into` was long enough; nothing is written when it was not ## `InclusiveScan<T>` ```rux pub func InclusiveScan<T>( items: T[..], into: var T[..], combine: func(T, T) -> T ) -> bool ``` Writes the running combination of `items` into `into`: element `i` becomes the first `i + 1` elements combined left to right with `combine`. [`PartialSum`](https://rux-lang.dev/docs/api/algorithms/numeric#partial-sum) is this scan with `+`. `into` may be `items` itself. Runs in time proportional to the length and allocates nothing beyond whatever `combine` does. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Algorithms/Src/Numeric.rux#L41){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | ---------------- | | `T` | the element type | **Parameters** | Name | Type | Description | | --------- | ----------------- | ------------------------------------------------- | | `items` | `T[..]` | the sequence to scan | | `into` | `var T[..]` | where the results go, at least as long as `items` | | `combine` | `func(T, T) -> T` | how two values combine | **Returns**: whether `into` was long enough; nothing is written when it was not ## `ExclusiveScan<T>` ```rux pub func ExclusiveScan<T>( items: T[..], into: var T[..], initial: T, combine: func(T, T) -> T ) -> bool ``` Writes the running combination of `items` before each element into `into`: element `i` becomes `initial` combined with the first `i` elements, so the first result is `initial` and the last element of `items` takes part in none. `into` may be `items` itself. Runs in time proportional to the length and allocates nothing beyond whatever `combine` does. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Algorithms/Src/Numeric.rux#L67){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | ---------------- | | `T` | the element type | **Parameters** | Name | Type | Description | | --------- | ----------------- | ------------------------------------------------- | | `items` | `T[..]` | the sequence to scan | | `into` | `var T[..]` | where the results go, at least as long as `items` | | `initial` | `T` | the value before anything is combined | | `combine` | `func(T, T) -> T` | how two values combine | **Returns**: whether `into` was long enough; nothing is written when it was not ## `Iota<T>` ```rux pub func Iota<T>(into: var T[..], start: T, step: T) ``` Fills `into` with `start`, `start + step`, `start + 2 * step` and so on. Requires `+` on the element type, with whatever overflow it has. Runs in time proportional to the length and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Algorithms/Src/Numeric.rux#L88){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | ---------------- | | `T` | the element type | **Parameters** | Name | Type | Description | | ------- | ----------- | -------------------------------------- | | `into` | `var T[..]` | the sequence to fill | | `start` | `T` | the first value | | `step` | `T` | what each value adds to the one before | ## `Midpoint` ```rux pub func Midpoint(a: int64, b: int64) -> int64 pub func Midpoint(a: int32, b: int32) -> int32 pub func Midpoint(a: uint64, b: uint64) -> uint64 pub func Midpoint(a: uint32, b: uint32) -> uint32 pub func Midpoint(a: float64, b: float64) -> float64 ``` Halfway between `a` and `b`, without overflowing to infinity when both are near the largest finite value. | Overload | Summary | | ------------------------------------------------------ | --------------------------------------------------------------------------------------------------------- | | `pub func Midpoint(a: int64, b: int64) -> int64` | Halfway between `a` and `b`, rounded toward `a`, without overflowing however far apart they are. | | `pub func Midpoint(a: int32, b: int32) -> int32` | Halfway between `a` and `b`, rounded toward `a`, without overflowing however far apart they are. | | `pub func Midpoint(a: uint64, b: uint64) -> uint64` | Halfway between `a` and `b`, rounded toward `a`, without overflowing however far apart they are. | | `pub func Midpoint(a: uint32, b: uint32) -> uint32` | Halfway between `a` and `b`, rounded toward `a`, without overflowing however far apart they are. | | `pub func Midpoint(a: float64, b: float64) -> float64` | Halfway between `a` and `b`, without overflowing to infinity when both are near the largest finite value. | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Algorithms/Src/Numeric.rux#L103){rel=""nofollow""} **Parameters** | Name | Type | Description | | ---- | --------------------------------------------------- | ------------- | | `a` | `int64` / `int32` / `uint64` / `uint32` / `float64` | one end | | `b` | `int64` / `int32` / `uint64` / `uint32` / `float64` | the other end | **Returns**: the midpoint # Searching Linear queries over a slice in no particular order: whether it holds a value, where, and how many. ## `Contains<T>` ```rux pub func Contains<T>(items: T[..], value: T) -> bool ``` Whether any element of `items` equals `value`. `items` is borrowed and read; `value` is read by value. An empty slice contains nothing, so this is false. Cannot fail. Runs in time proportional to the length, stopping at the first match, and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Algorithms/Src/Find.rux#L23){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | ---------------- | | `T` | the element type | **Parameters** | Name | Type | Description | | ------- | ------- | ----------------------- | | `items` | `T[..]` | the sequence to work on | | `value` | `T` | the value to look for | **Returns**: whether any element equals `value` ## `Count<T>` ```rux pub func Count<T>(items: T[..], value: T) -> uint ``` How many elements of `items` equal `value`. `items` is borrowed and read; `value` is read by value. An empty slice gives zero. Cannot fail. Runs in time proportional to the length and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Algorithms/Src/Find.rux#L35){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | ---------------- | | `T` | the element type | **Parameters** | Name | Type | Description | | ------- | ------- | ----------------------- | | `items` | `T[..]` | the sequence to work on | | `value` | `T` | the value to look for | **Returns**: how many elements equal `value` ## `IndexOf<T>` ```rux pub func IndexOf<T>(items: T[..], value: T) -> uint? ``` The index of the first element of `items` equal to `value`. `items` is borrowed and read; `value` is read by value. Reports `none` when no element matches, including for an empty slice. Cannot fail. Runs in time proportional to the length, stopping at the first match, and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Algorithms/Src/Find.rux#L56){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | ---------------- | | `T` | the element type | **Parameters** | Name | Type | Description | | ------- | ------- | ----------------------- | | `items` | `T[..]` | the sequence to work on | | `value` | `T` | the value to look for | **Returns**: the first index holding `value`, or `none` ## `LastIndexOf<T>` ```rux pub func LastIndexOf<T>(items: T[..], value: T) -> uint? ``` The index of the last element of `items` equal to `value`. `items` is borrowed and read; `value` is read by value. Reports `none` when no element matches. Cannot fail. Runs in time proportional to the length, stopping at the first match from the end, and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Algorithms/Src/Find.rux#L74){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | ---------------- | | `T` | the element type | **Parameters** | Name | Type | Description | | ------- | ------- | ----------------------- | | `items` | `T[..]` | the sequence to work on | | `value` | `T` | the value to look for | **Returns**: the last index holding `value`, or `none` ## `IndexWhere<T>` ```rux pub func IndexWhere<T>( items: T[..], predicate: func(T) -> bool ) -> uint? ``` The index of the first element of `items` that `predicate` accepts. `items` is borrowed and read; `predicate` is called once per element until it accepts one. Reports `none` when it accepts none. Cannot fail. Runs in time proportional to the length and allocates nothing beyond whatever `predicate` does. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Algorithms/Src/Find.rux#L92){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | ---------------- | | `T` | the element type | **Parameters** | Name | Type | Description | | ----------- | ----------------- | ------------------------------- | | `items` | `T[..]` | the sequence to work on | | `predicate` | `func(T) -> bool` | the test each element is put to | **Returns**: the first index whose element satisfies `predicate`, or `none` ## `LastIndexWhere<T>` ```rux pub func LastIndexWhere<T>( items: T[..], predicate: func(T) -> bool ) -> uint? ``` The index of the last element of `items` that `predicate` accepts. `items` is borrowed and read; `predicate` is called once per element from the end until it accepts one. Reports `none` when it accepts none. Cannot fail. Runs in time proportional to the length and allocates nothing beyond whatever `predicate` does. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Algorithms/Src/Find.rux#L110){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | ---------------- | | `T` | the element type | **Parameters** | Name | Type | Description | | ----------- | ----------------- | ------------------------------- | | `items` | `T[..]` | the sequence to work on | | `predicate` | `func(T) -> bool` | the test each element is put to | **Returns**: the last index whose element satisfies `predicate`, or `none` ## `CountWhere<T>` ```rux pub func CountWhere<T>( items: T[..], predicate: func(T) -> bool ) -> uint ``` How many elements of `items` the predicate accepts. `items` is borrowed and read; `predicate` is called once per element. An empty slice gives zero. Cannot fail. Runs in time proportional to the length and allocates nothing beyond whatever `predicate` does. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Algorithms/Src/Find.rux#L127){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | ---------------- | | `T` | the element type | **Parameters** | Name | Type | Description | | ----------- | ----------------- | ------------------------------- | | `items` | `T[..]` | the sequence to work on | | `predicate` | `func(T) -> bool` | the test each element is put to | **Returns**: how many elements satisfy `predicate` ## `AllOf<T>` ```rux pub func AllOf<T>( items: T[..], predicate: func(T) -> bool ) -> bool ``` Whether `predicate` accepts every element of `items`. `items` is borrowed and read. An empty slice satisfies this, as it satisfies every universal claim: there is no element that fails. Cannot fail. Runs in time proportional to the length, stopping at the first rejection, and allocates nothing beyond whatever `predicate` does. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Algorithms/Src/Find.rux#L149){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | ---------------- | | `T` | the element type | **Parameters** | Name | Type | Description | | ----------- | ----------------- | ------------------------------- | | `items` | `T[..]` | the sequence to work on | | `predicate` | `func(T) -> bool` | the test each element is put to | **Returns**: whether every element satisfies `predicate`; true for an empty sequence ## `AnyOf<T>` ```rux pub func AnyOf<T>( items: T[..], predicate: func(T) -> bool ) -> bool ``` Whether `predicate` accepts at least one element of `items`. `items` is borrowed and read. An empty slice does not satisfy this: there is no element that passes. Cannot fail. Runs in time proportional to the length, stopping at the first acceptance, and allocates nothing beyond whatever `predicate` does. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Algorithms/Src/Find.rux#L167){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | ---------------- | | `T` | the element type | **Parameters** | Name | Type | Description | | ----------- | ----------------- | ------------------------------- | | `items` | `T[..]` | the sequence to work on | | `predicate` | `func(T) -> bool` | the test each element is put to | **Returns**: whether any element satisfies `predicate`; false for an empty sequence ## `NoneOf<T>` ```rux pub func NoneOf<T>( items: T[..], predicate: func(T) -> bool ) -> bool ``` Whether `predicate` accepts no element of `items`. `items` is borrowed and read. An empty slice satisfies this, for the same reason it satisfies [`AllOf`](https://rux-lang.dev/docs/api/algorithms/searching#all-of). Cannot fail. Runs in time proportional to the length, stopping at the first acceptance, and allocates nothing beyond whatever `predicate` does. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Algorithms/Src/Find.rux#L180){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | ---------------- | | `T` | the element type | **Parameters** | Name | Type | Description | | ----------- | ----------------- | ------------------------------- | | `items` | `T[..]` | the sequence to work on | | `predicate` | `func(T) -> bool` | the test each element is put to | **Returns**: whether no element satisfies `predicate`; true for an empty sequence # Sorted slices Binary search and bounds over a slice that is already in order, and checking that it is. ## `IsSorted<T>` ```rux pub func IsSorted<T>(items: T[..]) -> bool ``` Whether `items` is in non-decreasing order. `items` is borrowed and read. An empty slice and a single element are sorted, there being no pair to be out of order. Equal neighbours are in order: this asks for non-decreasing, not strictly increasing. Requires `<` on the element type. Cannot fail. Runs in time proportional to the length, stopping at the first pair out of order, and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Algorithms/Src/Search.rux#L27){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | ---------------- | | `T` | the element type | **Parameters** | Name | Type | Description | | ------- | ------- | ----------------------- | | `items` | `T[..]` | the sequence to work on | **Returns**: whether the sequence is in non-descending order ## `IsSortedUntil<T>` ```rux pub func IsSortedUntil<T>(items: T[..]) -> uint ``` How far `items` is in non-decreasing order. `items` is borrowed and read. Returns the length of the longest sorted run starting at the front, which is the whole length when the slice is sorted, and the index of the first element smaller than the one before it otherwise. An empty slice gives zero and a single element gives one. Requires `<` on the element type. Cannot fail. Runs in time proportional to the answer and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Algorithms/Src/Search.rux#L41){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | ---------------- | | `T` | the element type | **Parameters** | Name | Type | Description | | ------- | ------- | ----------------------- | | `items` | `T[..]` | the sequence to work on | **Returns**: how many leading elements are in non-descending order ## `LowerBound<T>` ```rux pub func LowerBound<T>(items: T[..], value: T) -> uint ``` The first position where `value` could be inserted without breaking the order. `items` is borrowed and read; `value` is read by value. This is the index of the first element not less than `value` — the first equal one when there are equals, and where it would go when there are none. A value larger than everything gives the length. Requires `<` on the element type, and requires `items` to be sorted by that order. Cannot fail. Runs in time proportional to the logarithm of the length and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Algorithms/Src/Search.rux#L62){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | ---------------- | | `T` | the element type | **Parameters** | Name | Type | Description | | ------- | ------- | ----------------------- | | `items` | `T[..]` | the sequence to work on | | `value` | `T` | the value to place | **Returns**: the first index where `value` could be inserted and keep the order ## `UpperBound<T>` ```rux pub func UpperBound<T>(items: T[..], value: T) -> uint ``` The last position where `value` could be inserted without breaking the order. `items` is borrowed and read; `value` is read by value. This is the index of the first element greater than `value` — one past the last equal one when there are equals, and the same as [`LowerBound`](https://rux-lang.dev/docs/api/algorithms/sorted-slices#lower-bound) when there are none. Requires `<` on the element type, and requires `items` to be sorted by that order. Cannot fail. Runs in time proportional to the logarithm of the length and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Algorithms/Src/Search.rux#L87){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | ---------------- | | `T` | the element type | **Parameters** | Name | Type | Description | | ------- | ------- | ----------------------- | | `items` | `T[..]` | the sequence to work on | | `value` | `T` | the value to place | **Returns**: the last index where `value` could be inserted and keep the order ## `BinarySearch<T>` ```rux pub func BinarySearch<T>(items: T[..], value: T) -> uint? ``` The index of an element of `items` equal to `value`. `items` is borrowed and read; `value` is read by value. Reports `none` when no element is equal. When several are, the one reported is the first of them, which makes the answer depend on the sequence rather than on how the search happened to divide it. Requires `<` on the element type, and requires `items` to be sorted by that order. Equality is decided by the ordering rather than by `==`: two elements neither of which is less than the other are equal here, whatever `==` would say about them. Cannot fail. Runs in time proportional to the logarithm of the length and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Algorithms/Src/Search.rux#L115){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | ---------------- | | `T` | the element type | **Parameters** | Name | Type | Description | | ------- | ------- | ----------------------- | | `items` | `T[..]` | the sequence to work on | | `value` | `T` | the value to look for | **Returns**: the index of a matching element, or `none`; which one is unspecified when several match ## `EqualRange<T>` ```rux pub func EqualRange<T>(items: T[..], value: T) -> uint..uint ``` The range of positions in `items` holding elements equal to `value`. `items` is borrowed and read; `value` is read by value. The range runs from [`LowerBound`](https://rux-lang.dev/docs/api/algorithms/sorted-slices#lower-bound) to [`UpperBound`](https://rux-lang.dev/docs/api/algorithms/sorted-slices#upper-bound), so it is empty when no element is equal — and its `start` is then where the value would be inserted, which is the answer a caller inserting into a sorted sequence wants. Requires `<` on the element type, and requires `items` to be sorted by that order. Cannot fail. Runs in time proportional to the logarithm of the length and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Algorithms/Src/Search.rux#L132){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | ---------------- | | `T` | the element type | **Parameters** | Name | Type | Description | | ------- | ------- | ----------------------- | | `items` | `T[..]` | the sequence to work on | | `value` | `T` | the value to bracket | **Returns**: the range of indices holding elements equal to `value`, empty when none does ## `IsSortedBy<T>` ```rux pub func IsSortedBy<T>( items: T[..], compare: func(T, T) -> Ordering ) -> bool ``` Whether `items` is in non-decreasing order under `compare`. `items` is borrowed and read; `compare` is called once per neighbouring pair until one is out of order. An empty slice and a single element are sorted, and equal neighbours are in order. Cannot fail. Runs in time proportional to the length and allocates nothing beyond whatever `compare` does. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Algorithms/Src/Search.rux#L145){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | ---------------- | | `T` | the element type | **Parameters** | Name | Type | Description | | --------- | ------------------------ | ----------------------------------------- | | `items` | `T[..]` | the sequence to work on | | `compare` | `func(T, T) -> Ordering` | how two elements order against each other | **Returns**: whether the sequence is in non-descending order under `compare` ## `IsSortedUntilBy<T>` ```rux pub func IsSortedUntilBy<T>( items: T[..], compare: func(T, T) -> Ordering ) -> uint ``` How far `items` is in non-decreasing order under `compare`. `items` is borrowed and read. Returns the length of the longest sorted run starting at the front, exactly as [`IsSortedUntil`](https://rux-lang.dev/docs/api/algorithms/sorted-slices#is-sorted-until) does for the element type's own order. Cannot fail. Runs in time proportional to the answer and allocates nothing beyond whatever `compare` does. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Algorithms/Src/Search.rux#L158){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | ---------------- | | `T` | the element type | **Parameters** | Name | Type | Description | | --------- | ------------------------ | ----------------------------------------- | | `items` | `T[..]` | the sequence to work on | | `compare` | `func(T, T) -> Ordering` | how two elements order against each other | **Returns**: how many leading elements are in non-descending order under `compare` ## `LowerBoundBy<T>` ```rux pub func LowerBoundBy<T>( items: T[..], value: T, compare: func(T, T) -> Ordering ) -> uint ``` The first position where `value` could be inserted into `items` under `compare` without breaking the order. `items` is borrowed and read; `value` is read by value. `compare` must be the order `items` was sorted by. Cannot fail. Runs in time proportional to the logarithm of the length and allocates nothing beyond whatever `compare` does. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Algorithms/Src/Search.rux#L178){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | ---------------- | | `T` | the element type | **Parameters** | Name | Type | Description | | --------- | ------------------------ | ----------------------------------------- | | `items` | `T[..]` | the sequence to work on | | `value` | `T` | the value to place | | `compare` | `func(T, T) -> Ordering` | how two elements order against each other | **Returns**: the first index where `value` could be inserted and keep the order under `compare` ## `UpperBoundBy<T>` ```rux pub func UpperBoundBy<T>( items: T[..], value: T, compare: func(T, T) -> Ordering ) -> uint ``` The last position where `value` could be inserted into `items` under `compare` without breaking the order. `items` is borrowed and read; `value` is read by value. `compare` must be the order `items` was sorted by. Cannot fail. Runs in time proportional to the logarithm of the length and allocates nothing beyond whatever `compare` does. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Algorithms/Src/Search.rux#L203){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | ---------------- | | `T` | the element type | **Parameters** | Name | Type | Description | | --------- | ------------------------ | ----------------------------------------- | | `items` | `T[..]` | the sequence to work on | | `value` | `T` | the value to place | | `compare` | `func(T, T) -> Ordering` | how two elements order against each other | **Returns**: the last index where `value` could be inserted and keep the order under `compare` ## `BinarySearchBy<T>` ```rux pub func BinarySearchBy<T>( items: T[..], value: T, compare: func(T, T) -> Ordering ) -> uint? ``` The index of an element of `items` that `compare` calls equal to `value`. `items` is borrowed and read; `value` is read by value. Reports `none` when no element is equal, and the first of them when several are. `compare` must be the order `items` was sorted by. Cannot fail. Runs in time proportional to the logarithm of the length and allocates nothing beyond whatever `compare` does. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Algorithms/Src/Search.rux#L229){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | ---------------- | | `T` | the element type | **Parameters** | Name | Type | Description | | --------- | ------------------------ | ----------------------------------------- | | `items` | `T[..]` | the sequence to work on | | `value` | `T` | the value to look for | | `compare` | `func(T, T) -> Ordering` | how two elements order against each other | **Returns**: the index of a matching element under `compare`, or `none` ## `EqualRangeBy<T>` ```rux pub func EqualRangeBy<T>( items: T[..], value: T, compare: func(T, T) -> Ordering ) -> uint..uint ``` The range of positions in `items` holding elements `compare` calls equal to `value`. `items` is borrowed and read; `value` is read by value. Empty when no element is equal, with its `start` at the position the value would be inserted. `compare` must be the order `items` was sorted by. Cannot fail. Runs in time proportional to the logarithm of the length and allocates nothing beyond whatever `compare` does. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Algorithms/Src/Search.rux#L246){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | ---------------- | | `T` | the element type | **Parameters** | Name | Type | Description | | --------- | ------------------------ | ----------------------------------------- | | `items` | `T[..]` | the sequence to work on | | `value` | `T` | the value to bracket | | `compare` | `func(T, T) -> Ordering` | how two elements order against each other | **Returns**: the range of indices holding elements equal to `value` under `compare` # Sorting Putting a slice in order in place, unstably with no storage or stably with caller scratch. ## `Sort<T>` ```rux pub func Sort<T>(items: var T[..]) ``` Puts `items` into non-decreasing order. `items` is borrowed mutably and rewritten. Fewer than two elements are already sorted, so the data pointer is never read in that case and an empty view is not a special case. Requires `<` on the element type, as a strict weak ordering. Equal elements may be reordered: this is not stable. Cannot fail. Makes O(n log n) comparisons for every input, uses O(1) storage beyond the sequence, and recurses O(log n) deep. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Algorithms/Src/Sort.rux#L42){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | ---------------- | | `T` | the element type | **Parameters** | Name | Type | Description | | ------- | ----------- | ----------------------- | | `items` | `var T[..]` | the sequence to work on | ## `SortDescending<T>` ```rux pub func SortDescending<T>(items: var T[..]) ``` Puts `items` into non-increasing order. `items` is borrowed mutably and rewritten. An ascending sort followed by a reversal, rather than a mirrored copy of every helper below: threading a direction flag through the partition and both fallbacks would cost a branch in the innermost comparison, and duplicating the helpers would double the amount of subtle index arithmetic to maintain, all for one extra linear pass. Sorting is unstable in either direction, so reversing costs nothing in ordering either. Requires `<` on the element type. Equal elements may be reordered. Cannot fail. Makes O(n log n) comparisons and uses O(1) storage beyond the sequence. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Algorithms/Src/Sort.rux#L69){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | ---------------- | | `T` | the element type | **Parameters** | Name | Type | Description | | ------- | ----------- | ----------------------- | | `items` | `var T[..]` | the sequence to work on | ## `NthElement<T>` ```rux pub func NthElement<T>(items: var T[..], n: uint) -> bool ``` Puts the element that belongs at `n` in a fully sorted `items` at `n`, and partitions around it. `items` is borrowed mutably and rewritten; `n` is read by value. Afterwards everything before `n` is at most the element at `n` and everything after is at least it. Neither side is ordered any further, which is the whole point: this is what to reach for when only one order statistic is wanted — a median, a percentile — because it is linear on average where a full sort is not. Reports false, changing nothing, when `n` is not an index into `items`. That is the only way this fails. Quickselect over the same partition [`Sort`](https://rux-lang.dev/docs/api/algorithms/sorting#sort) uses, but iterative: only one side of a partition can contain `n`, so there is nothing to recurse into and the stack stays flat. The same depth budget bounds the worst case at O(n log n), against O(n) on average. Requires `<` on the element type. Equal elements may be reordered. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Algorithms/Src/Sort.rux#L89){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | ---------------- | | `T` | the element type | **Parameters** | Name | Type | Description | | ------- | ----------- | --------------------------------------------------------- | | `items` | `var T[..]` | the sequence to work on | | `n` | `uint` | the index whose element should end up in its sorted place | **Returns**: whether `n` was a usable index ## `PartialSort<T>` ```rux pub func PartialSort<T>( items: var T[..], count: uint ) -> bool ``` Puts the `count` smallest elements of `items` in order at its front. `items` is borrowed mutably and rewritten; `count` is read by value. The first `count` positions hold the smallest elements in non-decreasing order, and the rest hold everything else in no particular order. Reports false, changing nothing, when `count` is larger than the length. A `count` of zero succeeds and does nothing. A max-heap over the first `count` elements, which each later element is compared against and displaces only if it is smaller: O(n log count) comparisons, against the O(n log n) a full sort would cost. That is worth having when `count` is much smaller than the length and not otherwise. Requires `<` on the element type. Equal elements may be reordered. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Algorithms/Src/Sort.rux#L149){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | ---------------- | | `T` | the element type | **Parameters** | Name | Type | Description | | ------- | ----------- | ------------------------------------------ | | `items` | `var T[..]` | the sequence to work on | | `count` | `uint` | how many of the smallest elements to place | **Returns**: whether `count` was a usable length ## `InsertionSortRange<T>` ```rux pub func InsertionSortRange<T>( data: *var T, low: uint, high: uint ) ``` Provides the public `InsertionSortRange` operation. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Algorithms/Src/Sort.rux#L260){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | ---------------- | | `T` | the element type | **Parameters** | Name | Type | Description | | ------ | -------- | ---------------------------- | | `data` | `*var T` | the sequence to work on | | `low` | `uint` | the first index of the range | | `high` | `uint` | the index one past the range | ## `HeapSortRange<T>` ```rux pub func HeapSortRange<T>( data: *var T, low: uint, high: uint ) ``` Provides the public `HeapSortRange` operation. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Algorithms/Src/Sort.rux#L313){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | ---------------- | | `T` | the element type | **Parameters** | Name | Type | Description | | ------ | -------- | ---------------------------- | | `data` | `*var T` | the sequence to work on | | `low` | `uint` | the first index of the range | | `high` | `uint` | the index one past the range | ## `SortBy<T>` ```rux pub func SortBy<T>( items: var T[..], compare: func(T, T) -> Ordering ) ``` Puts `items` into the order `compare` describes, smallest first. `items` is borrowed mutably and rewritten; `compare` is called O(n log n) times and must be a strict weak ordering, exactly as `<` must be. Equivalence is derived from it alone, so the element type need not define any operator at all. Cannot fail. Makes O(n log n) comparisons for every input, uses O(1) storage beyond the sequence, and recurses O(log n) deep. Equal elements may be reordered: this is not stable. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Algorithms/Src/Sort.rux#L391){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | ---------------- | | `T` | the element type | **Parameters** | Name | Type | Description | | --------- | ------------------------ | ----------------------------------------- | | `items` | `var T[..]` | the sequence to work on | | `compare` | `func(T, T) -> Ordering` | how two elements order against each other | ## `SortDescendingBy<T>` ```rux pub func SortDescendingBy<T>( items: var T[..], compare: func(T, T) -> Ordering ) ``` Puts `items` into the reverse of the order `compare` describes. `items` is borrowed mutably and rewritten; `compare` is called O(n log n) times. An ascending sort followed by a reversal, for the same reason [`SortDescending`](https://rux-lang.dev/docs/api/algorithms/sorting#sort-descending) is. Cannot fail. Makes O(n log n) comparisons and uses O(1) storage beyond the sequence. Equal elements may be reordered. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Algorithms/Src/Sort.rux#L412){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | ---------------- | | `T` | the element type | **Parameters** | Name | Type | Description | | --------- | ------------------------ | ----------------------------------------- | | `items` | `var T[..]` | the sequence to work on | | `compare` | `func(T, T) -> Ordering` | how two elements order against each other | ## `NthElementBy<T>` ```rux pub func NthElementBy<T>( items: var T[..], n: uint, compare: func(T, T) -> Ordering ) -> bool ``` Puts the element that belongs at `n` under `compare` at `n`, and partitions around it. `items` is borrowed mutably and rewritten; `n` is read by value; `compare` must be a strict weak ordering. Exactly [`NthElement`](https://rux-lang.dev/docs/api/algorithms/sorting#nth-element), with the order supplied rather than taken from the element type. Reports false, changing nothing, when `n` is not an index into `items`. O(n) comparisons on average and O(n log n) at worst. Equivalent elements may be reordered. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Algorithms/Src/Sort.rux#L428){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | ---------------- | | `T` | the element type | **Parameters** | Name | Type | Description | | --------- | ------------------------ | --------------------------------------------------------- | | `items` | `var T[..]` | the sequence to work on | | `n` | `uint` | the index whose element should end up in its sorted place | | `compare` | `func(T, T) -> Ordering` | how two elements order against each other | **Returns**: whether `n` was a usable index ## `PartialSortBy<T>` ```rux pub func PartialSortBy<T>( items: var T[..], count: uint, compare: func(T, T) -> Ordering ) -> bool ``` Puts the `count` smallest elements of `items` under `compare` in order at its front. `items` is borrowed mutably and rewritten; `count` is read by value; `compare` must be a strict weak ordering. Exactly [`PartialSort`](https://rux-lang.dev/docs/api/algorithms/sorting#partial-sort), with the order supplied rather than taken from the element type. Reports false, changing nothing, when `count` is larger than the length. O(n log count) comparisons. Equivalent elements may be reordered. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Algorithms/Src/Sort.rux#L481){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | ---------------- | | `T` | the element type | **Parameters** | Name | Type | Description | | --------- | ------------------------ | ------------------------------------------ | | `items` | `var T[..]` | the sequence to work on | | `count` | `uint` | how many of the smallest elements to place | | `compare` | `func(T, T) -> Ordering` | how two elements order against each other | **Returns**: whether `count` was a usable length ## `RequiredScratch` ```rux pub func RequiredScratch(length: uint) -> uint ``` How much scratch storage a stable sort of `length` elements needs. `length` is read by value. The answer is `length` itself: a merge writes its output somewhere other than either of the two runs it reads, and the last merge reads the whole sequence. Written as a function rather than left to the reader so that a caller sizing a buffer does not have to know that, and so that it stays right if it ever stops being the whole length. Cannot fail. Runs in constant time and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Algorithms/Src/Stable.rux#L28){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | ------ | ---------------------------------- | | `length` | `uint` | how many elements are to be sorted | **Returns**: how many elements of working storage a stable sort of that length needs ## `StableSort<T>` ```rux pub func StableSort<T>( items: var T[..], scratch: var T[..] ) -> bool ``` Puts `items` into non-decreasing order, leaving equal elements in the order they were in. `items` is borrowed mutably and rewritten; `scratch` is borrowed mutably and used as working storage, and what it holds afterwards is unspecified. Fewer than two elements are already sorted and need no scratch at all. Reports false, changing nothing, when `scratch` is shorter than `RequiredScratch(items.length)`. That is the only way this fails. Requires `<` on the element type, as a strict weak ordering. Makes O(n log n) comparisons and moves for every input — there is no bad case — and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Algorithms/Src/Stable.rux#L44){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | ---------------- | | `T` | the element type | **Parameters** | Name | Type | Description | | --------- | ----------- | -------------------------------------------------------------------- | | `items` | `var T[..]` | the sequence to work on | | `scratch` | `var T[..]` | working storage of at least `RequiredScratch(items.length)` elements | **Returns**: whether `scratch` was large enough; the sequence is untouched when it was not ## `StableSortBy<T>` ```rux pub func StableSortBy<T>( items: var T[..], scratch: var T[..], compare: func(T, T) -> Ordering ) -> bool ``` Puts `items` into the order `compare` describes, leaving equivalent elements in the order they were in. `items` is borrowed mutably and rewritten; `scratch` is borrowed mutably and used as working storage, and what it holds afterwards is unspecified. `compare` is called O(n log n) times and must be a strict weak ordering. Reports false, changing nothing, when `scratch` is shorter than `RequiredScratch(items.length)`. Makes O(n log n) comparisons and moves for every input, and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Algorithms/Src/Stable.rux#L104){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | ---------------- | | `T` | the element type | **Parameters** | Name | Type | Description | | --------- | ------------------------ | -------------------------------------------------------------------- | | `items` | `var T[..]` | the sequence to work on | | `scratch` | `var T[..]` | working storage of at least `RequiredScratch(items.length)` elements | | `compare` | `func(T, T) -> Ordering` | how two elements order against each other | **Returns**: whether `scratch` was large enough; the sequence is untouched when it was not # Hash Named non-cryptographic hashes and checksums. ## Installation Add `Hash` to the `[Dependencies]` table of your package's `Rux.toml`: ```toml [Dependencies] Hash = { Namespace = "Rux", Version = "0.1.0" } ``` Standard packages are declared by hand: the registry does not serve them, so `rux add Rux/Hash` cannot add them. ## Dependencies - [`Core`](https://rux-lang.dev/docs/api/core) 0.1.0 ## Guide ### What it provides | Module | Covers | | ----------------------------------------------------- | ------------------------------------------------------------------------------------------------------------- | | [`Hasher`](https://rux-lang.dev/docs/api/hash/hasher) | the [`Hasher`](https://rux-lang.dev/docs/api/hash/hasher) contract, and the writers every caller of one needs | | `Fnv` | FNV-1a over 32 and 64 bits, incremental and one-shot | | `Crc` | CRC-32 and CRC-32C, their tables and their polynomials | | `Adler` | Adler-32, the checksum the zlib format ends with | | `XxHash` | xxHash64, seeded, streaming and one-shot | | `SipHash` | keyed SipHash-2-4, for tables whose keys someone else chooses | ### Design Every hash here is built the same way: make one, write bytes into it in order, and ask for the answer. That shape is what lets a value be hashed without first being turned into a contiguous buffer — a struct writes each of its fields in turn, and a collection each of its elements, with nothing copied anywhere. Take a hasher by generic bound and mutable reference. `func Digest<H: Hasher>(hasher: &var H)` borrows the caller's own state and resolves at instantiation, so mutations are visible without copying. The interface exists to be the bound. All hasher states are structural `Copy` values and own no external resources. Copying one intentionally snapshots the stream; later writes to either value are independent. Construct unseeded states with type calls such as [`Fnv1a64()`](https://rux-lang.dev/docs/api/hash/fnv1a64), [`Crc32()`](https://rux-lang.dev/docs/api/hash/crc32), and [`XxHash64()`](https://rux-lang.dev/docs/api/hash/xx-hash64). Raw pointers remain only on byte-range APIs because those ranges may be nullable when empty and support pointer arithmetic; callers must provide `length` readable bytes. [`WriteUint32`](https://rux-lang.dev/docs/api/hash/hasher#write-uint32) and [`WriteUint64`](https://rux-lang.dev/docs/api/hash/hasher#write-uint64) use a fixed byte order rather than the machine's, so a value hashes the same on every target. That is what makes the hash of a struct mean the same thing everywhere, and it costs nothing on a little-endian machine. ### Speed [`XxHash64`](https://rux-lang.dev/docs/api/hash/xx-hash64) is the one to reach for when there is a lot of data. Where FNV-1a takes a byte at a time, it takes thirty-two: four independent accumulators, so a wide machine has four chains to run at once rather than one dependency chain to wait on. The mixing is arithmetic rather than table lookup, which is what keeps it fast on data that does not fit in cache — there is no table to evict. A seed is part of the algorithm rather than an afterthought: two hashers with different seeds give unrelated answers for the same input, which keeps accidental collisions from following data between tables. It is not enough to stop a deliberate one. Streaming is exact. Any division of the same byte stream into writes gives the same answer, including one byte at a time and including a write that lands one byte short of a block boundary. ### Checksums [`Crc32`](https://rux-lang.dev/docs/api/hash/crc32) and [`Crc32c`](https://rux-lang.dev/docs/api/hash/crc32c) are cyclic redundancy checks, and what they buy over a sum is a guarantee rather than a hope: a 32-bit CRC detects every burst error up to 32 bits long, every single-bit and double-bit error, and every error of odd weight — none of which a general-purpose hash promises about anything. Both are the reflected, table-driven forms every implementation uses, so a value computed here matches gzip, PNG and zip for [`Crc32`](https://rux-lang.dev/docs/api/hash/crc32), and iSCSI, ext4, Btrfs and SCTP for [`Crc32c`](https://rux-lang.dev/docs/api/hash/crc32c). Prefer [`Crc32c`](https://rux-lang.dev/docs/api/hash/crc32c) for new work: it detects more of the double-bit errors that appear at storage-record lengths, and both supported architectures implement it in hardware. This implementation is the table rather than the instruction — correct everywhere, and about a byte per cycle. A CRC detects accident, never intent. Given any message and any target value, producing a message with that CRC is arithmetic a beginner can do. They implement [`Hasher`](https://rux-lang.dev/docs/api/hash/hasher) because feeding them bytes has the same shape, not because they substitute for one. ### Keying Every other hash here has a fixed, public structure, so anyone can compute inputs that collide. Feed a few thousand of those to a hash table and every one lands in the same bucket: lookups that should be constant become linear, and a service doing fine falls over on traffic that looks perfectly ordinary. [`SipHash24`](https://rux-lang.dev/docs/api/hash/sip-hash24) is what stops that. It stops it by being keyed. Without the key, finding two colliding inputs is as hard as breaking the function, and the key is a secret the program draws from `Rux/Entropy` at startup and never publishes. A key compiled into a program is a published key, and a published key is no key at all. The price is speed — two rounds per eight bytes and four more at the end, against xxHash64's one round across four independent lanes. For a table's short keys that is small and worth paying. For hashing a large file it is not. Sixty-four bits is enough to make collisions unfindable at hash-table scale and not enough to authenticate a message. `Rux/Crypto` has HMAC for that. ### What this is not None of these are cryptographic. They are fast, they are named, and they are documented — but an adversary who gets to choose the input can find collisions in any of them except `SipHash`, and even `SipHash` promises only that doing so is hard without the key. Anything that must resist an adversary belongs in `Rux/Crypto`, which is also where SHA-2, SHA-3, BLAKE3 and the explicitly named legacy MD5 and SHA-1 live. A hash from this package is stable: FNV-1a here will agree with any other correct implementation, which is what makes it worth naming an algorithm rather than promising only "some hash". `Core::Hashable` makes no such promise — its answers are not stable across runs, versions or targets, and nothing that outlives the process should be keyed on one. ## Index ### Interfaces | Name | Summary | | ----------------------------------------------------- | ------------------------------------------- | | [`Hasher`](https://rux-lang.dev/docs/api/hash/hasher) | A hash being computed, one write at a time. | ### Types | Name | Summary | | --------------------------------------------------------------------- | --------------------------------------------------------------------- | | [`Adler32`](https://rux-lang.dev/docs/api/hash/adler32) | The Adler-32 of a message, computed a batch of bytes at a time. | | [`Crc32`](https://rux-lang.dev/docs/api/hash/crc32) | The CRC-32 of a message, computed a byte at a time. | | [`Crc32c`](https://rux-lang.dev/docs/api/hash/crc32c) | The CRC-32C of a message, computed a byte at a time. | | [`Fnv1a32`](https://rux-lang.dev/docs/api/hash/fnv1a32) | FNV-1a over 32 bits, computed one byte at a time. | | [`Fnv1a64`](https://rux-lang.dev/docs/api/hash/fnv1a64) | FNV-1a over 64 bits, computed one byte at a time. | | [`SipState`](https://rux-lang.dev/docs/api/hash/sip-hash24#sip-state) | The four words SipHash mixes, and the round that mixes them. | | [`SipHash24`](https://rux-lang.dev/docs/api/hash/sip-hash24) | SipHash-2-4 over a stream of bytes, keyed with 128 bits. | | [`XxHash64`](https://rux-lang.dev/docs/api/hash/xx-hash64) | xxHash64 over a stream of bytes, in as many writes as the caller has. | ### Functions | Name | Summary | | ----------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------- | | [`Crc32Of`](https://rux-lang.dev/docs/api/hash/crc32#crc32-of) | The CRC-32 of `length` bytes at `bytes`. | | [`Crc32cOf`](https://rux-lang.dev/docs/api/hash/crc32c#crc32c-of) | The CRC-32C of `length` bytes at `bytes`. | | [`Fnv1a32Of`](https://rux-lang.dev/docs/api/hash/fnv1a32#fnv1a32-of) | The 32-bit FNV-1a hash of `length` bytes at `bytes`. | | [`Fnv1a64Of`](https://rux-lang.dev/docs/api/hash/fnv1a64#fnv1a64-of) | The 64-bit FNV-1a hash of `length` bytes at `bytes`. | | [`HashBytes<H>`](https://rux-lang.dev/docs/api/hash/hasher#hash-bytes) | Writes `length` bytes and returns the hash, for a caller with nothing else to add. | | [`WriteByte<H>`](https://rux-lang.dev/docs/api/hash/hasher#write-byte) | Writes one byte into `hasher`. | | [`WriteUint32<H>`](https://rux-lang.dev/docs/api/hash/hasher#write-uint32) | Writes a 32-bit value into `hasher`, least significant byte first. | | [`WriteUint64<H>`](https://rux-lang.dev/docs/api/hash/hasher#write-uint64) | Writes a 64-bit value into `hasher`, least significant byte first. | | [`SipWord`](https://rux-lang.dev/docs/api/hash/sip-hash24#sip-word) | The eight bytes at `bytes` as a 64-bit word, least significant byte first. | | [`SipHash24Of`](https://rux-lang.dev/docs/api/hash/sip-hash24#sip-hash24-of) | The SipHash-2-4 of `length` bytes at `bytes`, keyed with `low` and `high`. | | [`ReadLittleEndian64`](https://rux-lang.dev/docs/api/hash/xx-hash64#read-little-endian64) | The eight bytes at `bytes` as a 64-bit value, least significant byte first. | | [`ReadLittleEndian32`](https://rux-lang.dev/docs/api/hash/xx-hash64#read-little-endian32) | The four bytes at `bytes` as a 32-bit value, least significant byte first. | | [`XxRound`](https://rux-lang.dev/docs/api/hash/xx-hash64#xx-round) | One accumulator round: mix `lane` into `accumulator`. | | [`XxMerge`](https://rux-lang.dev/docs/api/hash/xx-hash64#xx-merge) | Folds one finished accumulator into the running hash. | | [`XxAvalanche`](https://rux-lang.dev/docs/api/hash/xx-hash64#xx-avalanche) | The final mixing step, which spreads every input bit across the whole result. | | [`XxHash64SeededOf`](https://rux-lang.dev/docs/api/hash/xx-hash64#xx-hash64-seeded-of) | The xxHash64 of `length` bytes at `bytes`, using `seed`. | | [`XxHash64Of`](https://rux-lang.dev/docs/api/hash/xx-hash64#xx-hash64-of) | The xxHash64 of `length` bytes at `bytes`, seeded with zero. | ### Constants | Name | Summary | | ------------------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------- | | [`Crc32Polynomial`](https://rux-lang.dev/docs/api/hash/crc32#crc32-polynomial) | The reflected IEEE 802.3 generator polynomial, which is what gzip, PNG and zip mean by "CRC-32". | | [`Crc32cPolynomial`](https://rux-lang.dev/docs/api/hash/crc32c#crc32c-polynomial) | The reflected Castagnoli generator polynomial, which is what iSCSI, ext4, Btrfs and SCTP mean by "CRC-32C". | | [`Crc32Initial`](https://rux-lang.dev/docs/api/hash/crc32#crc32-initial) | The value a CRC register starts at, and the value the finished register is complemented against. | | [`Crc32Table`](https://rux-lang.dev/docs/api/hash/crc32#crc32-table) | One byte of division by [`Crc32Polynomial`](https://rux-lang.dev/docs/api/hash/crc32#crc32-polynomial), precomputed for every possible byte. | | [`Crc32cTable`](https://rux-lang.dev/docs/api/hash/crc32c#crc32c-table) | One byte of division by [`Crc32cPolynomial`](https://rux-lang.dev/docs/api/hash/crc32c#crc32c-polynomial), precomputed for every possible byte. | | [`FnvOffsetBasis32`](https://rux-lang.dev/docs/api/hash/fnv1a32#fnv-offset-basis32) | The 32-bit FNV-1a offset basis, which is what an empty input hashes to. | | [`FnvPrime32`](https://rux-lang.dev/docs/api/hash/fnv1a32#fnv-prime32) | The 32-bit FNV prime. | | [`FnvOffsetBasis64`](https://rux-lang.dev/docs/api/hash/fnv1a64#fnv-offset-basis64) | The 64-bit FNV-1a offset basis, which is what an empty input hashes to. | | [`FnvPrime64`](https://rux-lang.dev/docs/api/hash/fnv1a64#fnv-prime64) | The 64-bit FNV prime. | | [`SipInit0`](https://rux-lang.dev/docs/api/hash/sip-hash24#sip-init0) | The first initialization constant, mixed with the low half of the key. | | [`SipInit1`](https://rux-lang.dev/docs/api/hash/sip-hash24#sip-init1) | The second initialization constant, mixed with the high half of the key. | | [`SipInit2`](https://rux-lang.dev/docs/api/hash/sip-hash24#sip-init2) | The third initialization constant, mixed with the low half of the key. | | [`SipInit3`](https://rux-lang.dev/docs/api/hash/sip-hash24#sip-init3) | The fourth initialization constant, mixed with the high half of the key. | | [`SipCompressionRounds`](https://rux-lang.dev/docs/api/hash/sip-hash24#sip-compression-rounds) | How many rounds each eight-byte word of input is mixed with: the 2 of SipHash-2-4. | | [`SipFinalizationRounds`](https://rux-lang.dev/docs/api/hash/sip-hash24#sip-finalization-rounds) | How many rounds finish the hash after the last word: the 4 of SipHash-2-4. | | [`XxPrime1`](https://rux-lang.dev/docs/api/hash/xx-hash64#xx-prime1) | The first xxHash64 prime, which every round multiplies by. | | [`XxPrime2`](https://rux-lang.dev/docs/api/hash/xx-hash64#xx-prime2) | The second xxHash64 prime, which scales each input lane before it is rotated in. | | [`XxPrime3`](https://rux-lang.dev/docs/api/hash/xx-hash64#xx-prime3) | The third xxHash64 prime, used in the four-byte tail step and the avalanche. | | [`XxPrime4`](https://rux-lang.dev/docs/api/hash/xx-hash64#xx-prime4) | The fourth xxHash64 prime, added after each merge and after each eight-byte tail step. | | [`XxPrime5`](https://rux-lang.dev/docs/api/hash/xx-hash64#xx-prime5) | The fifth xxHash64 prime, which seeds an input too short to fill a block and mixes each trailing byte. | | [`XxBlockSize`](https://rux-lang.dev/docs/api/hash/xx-hash64#xx-block-size) | How many bytes one xxHash64 round consumes: four lanes of eight. | # Hasher A hash being computed, one write at a time. ```rux pub interface Hasher { func Write(self: &var Self, bytes: *byte, length: uint); func Finish(self: &var Self) -> uint64; } ``` Written as an interface so a generic can require it. Borrow an implementation under a bound so mutations apply to the caller's state without copying it. An implementation must give the same answer for the same sequence of bytes, whatever the writes were split into: writing eight bytes at once and writing them one at a time must agree. It must not read anything but the bytes it is given — no address, no counter, no clock. ## Requirements ### `Write` ```rux func Write(self: &var Self, bytes: *byte, length: uint) ``` Adds `length` bytes at `bytes` to what is being hashed. `bytes` is borrowed and read; `length` is read by value. A zero length is legal and changes nothing, and is the one case in which `bytes` may be null. Runs in time proportional to `length` and allocates nothing. `bytes` must be readable for `length` bytes. | Name | Type | Description | | -------- | ------- | ------------------------------------ | | `bytes` | `*byte` | the bytes to absorb | | `length` | `uint` | how many bytes; zero absorbs nothing | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Hash/Src/Hasher.rux#L27){rel=""nofollow""} ### `Finish` ```rux func Finish(self: &var Self) -> uint64 ``` The hash of everything written so far. Returns the answer by value and leaves the hasher usable: asking twice gives the same answer, and writing more afterwards continues from where the writes left off rather than starting over. Cannot fail. Runs in constant time and allocates nothing. **Returns**: the hash of everything written since the last reset [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Hash/Src/Hasher.rux#L35){rel=""nofollow""} ## Implementations | Type | Summary | | ------------------------------------------------------------ | --------------------------------------------------------------------- | | [`Adler32`](https://rux-lang.dev/docs/api/hash/adler32) | The Adler-32 of a message, computed a batch of bytes at a time. | | [`Crc32`](https://rux-lang.dev/docs/api/hash/crc32) | The CRC-32 of a message, computed a byte at a time. | | [`Crc32c`](https://rux-lang.dev/docs/api/hash/crc32c) | The CRC-32C of a message, computed a byte at a time. | | [`Fnv1a32`](https://rux-lang.dev/docs/api/hash/fnv1a32) | FNV-1a over 32 bits, computed one byte at a time. | | [`Fnv1a64`](https://rux-lang.dev/docs/api/hash/fnv1a64) | FNV-1a over 64 bits, computed one byte at a time. | | [`SipHash24`](https://rux-lang.dev/docs/api/hash/sip-hash24) | SipHash-2-4 over a stream of bytes, keyed with 128 bits. | | [`XxHash64`](https://rux-lang.dev/docs/api/hash/xx-hash64) | xxHash64 over a stream of bytes, in as many writes as the caller has. | ## Related ### `HashBytes<H>` ```rux pub func HashBytes<H: Hasher>( hasher: &var H, bytes: *byte, length: uint ) -> uint64 ``` Writes `length` bytes and returns the hash, for a caller with nothing else to add. `hasher` is borrowed mutably and left holding what it hashed; `bytes` is borrowed and read. The type argument must be written out — `HashBytes<Fnv1a64>(hasher, data, length)` — because a generic argument is never inferred. Cannot fail. Runs in time proportional to `length` and allocates nothing. `bytes` must be readable for `length` bytes. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Hash/Src/Hasher.rux#L50){rel=""nofollow""} **Type parameters** | Name | Description | | ----------- | ----------------- | | `H: Hasher` | the hasher's type | **Parameters** | Name | Type | Description | | -------- | -------- | --------------------------------------- | | `hasher` | `&var H` | the hasher to use, which is reset first | | `bytes` | `*byte` | the bytes to hash | | `length` | `uint` | how many bytes | **Returns**: their hash ### `WriteByte<H>` ```rux pub func WriteByte<H: Hasher>(hasher: &var H, value: byte) ``` Writes one byte into `hasher`. `hasher` is borrowed mutably; `value` is read by value. Cannot fail. Runs in constant time and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Hash/Src/Hasher.rux#L62){rel=""nofollow""} **Type parameters** | Name | Description | | ----------- | ----------------- | | `H: Hasher` | the hasher's type | **Parameters** | Name | Type | Description | | -------- | -------- | ---------------------- | | `hasher` | `&var H` | the hasher to write to | | `value` | `byte` | the byte to write | ### `WriteUint32<H>` ```rux pub func WriteUint32<H: Hasher>( hasher: &var H, value: uint32 ) ``` Writes a 32-bit value into `hasher`, least significant byte first. `hasher` is borrowed mutably; `value` is read by value. The byte order is fixed rather than the machine's, so a value hashes the same on every target — which is what makes a hash of a struct mean the same thing everywhere. Cannot fail. Runs in constant time and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Hash/Src/Hasher.rux#L75){rel=""nofollow""} **Type parameters** | Name | Description | | ----------- | ----------------- | | `H: Hasher` | the hasher's type | **Parameters** | Name | Type | Description | | -------- | -------- | ----------------------------------------- | | `hasher` | `&var H` | the hasher to write to | | `value` | `uint32` | the value, written as little-endian bytes | ### `WriteUint64<H>` ```rux pub func WriteUint64<H: Hasher>( hasher: &var H, value: uint64 ) ``` Writes a 64-bit value into `hasher`, least significant byte first. `hasher` is borrowed mutably; `value` is read by value. The byte order is fixed rather than the machine's, for the same reason as [`WriteUint32`](https://rux-lang.dev/docs/api/hash/hasher#write-uint32). Cannot fail. Runs in constant time and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Hash/Src/Hasher.rux#L93){rel=""nofollow""} **Type parameters** | Name | Description | | ----------- | ----------------- | | `H: Hasher` | the hasher's type | **Parameters** | Name | Type | Description | | -------- | -------- | ----------------------------------------- | | `hasher` | `&var H` | the hasher to write to | | `value` | `uint64` | the value, written as little-endian bytes | # Adler32 The Adler-32 of a message, computed a batch of bytes at a time. ```rux pub struct Adler32 { // private fields } ``` `Copy`, holding only the two sums, so passing one by value takes a snapshot of the checksum so far. ## Constructors ### `Adler32` ```rux pub func Adler32() -> Adler32 ``` Constructs a checksum with nothing written into it yet. **Returns**: a hasher with nothing written to it yet [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Hash/Src/Adler.rux#L23){rel=""nofollow""} ## Methods ### `Reset` ```rux pub func Reset(self: &var Adler32) ``` Puts the checksum back to where [`Adler32()`](https://rux-lang.dev/docs/api/hash/adler32) leaves one. Everything written so far is forgotten. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Hash/Src/Adler.rux#L29){rel=""nofollow""} ### `Value` ```rux pub func Value(self: &Adler32) -> uint32 ``` The checksum of everything written so far: the second sum in the high half and the first in the low half. Writing more continues from here rather than starting over. **Returns**: the checksum [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Hash/Src/Adler.rux#L38){rel=""nofollow""} ## Implements Hasher `Adler32` conforms to [`Hasher`](https://rux-lang.dev/docs/api/hash/hasher). ### `Write` ```rux pub func Write( self: &var Adler32, bytes: *byte, length: uint ) ``` Adds `length` bytes at `bytes` to the checksum. A zero length changes nothing and is the one case in which `bytes` may be null. Splitting a message across several writes gives the same answer as one write. Runs in time proportional to `length` and allocates nothing. | Name | Type | Description | | -------- | ------- | ------------------------------------ | | `bytes` | `*byte` | the bytes to absorb | | `length` | `uint` | how many bytes; zero absorbs nothing | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Hash/Src/Adler.rux#L50){rel=""nofollow""} ### `Finish` ```rux pub func Finish(self: &var Adler32) -> uint64 ``` The checksum of everything written so far, widened to 64 bits; the upper half is always zero. **Returns**: the checksum [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Hash/Src/Adler.rux#L73){rel=""nofollow""} # Crc32 The CRC-32 of a message, computed a byte at a time. ```rux pub struct Crc32 { // private fields } ``` Copy, and holding only the register, so passing one by value takes a snapshot of the checksum so far. ## Constructors ### `Crc32` ```rux pub func Crc32() -> Crc32 ``` Constructs a checksum with nothing written into it yet. **Returns**: a hasher with nothing written to it yet [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Hash/Src/Crc.rux#L124){rel=""nofollow""} ## Methods ### `Reset` ```rux pub func Reset(self: &var Crc32) ``` Puts the checksum back to where [`Crc32()`](https://rux-lang.dev/docs/api/hash/crc32) leaves one. `self` is borrowed mutably. Everything written so far is forgotten. Cannot fail. Runs in constant time and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Hash/Src/Crc.rux#L132){rel=""nofollow""} ### `Value` ```rux pub func Value(self: &Crc32) -> uint32 ``` The checksum of everything written so far. `self` is borrowed. This is the register complemented, which is the value every other implementation reports; the register itself stays as it was, so writing more continues rather than starting over. Cannot fail. Runs in constant time and allocates nothing. **Returns**: the checksum of everything written so far [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Hash/Src/Crc.rux#L142){rel=""nofollow""} ## Implements Hasher `Crc32` conforms to [`Hasher`](https://rux-lang.dev/docs/api/hash/hasher). ### `Write` ```rux pub func Write(self: &var Crc32, bytes: *byte, length: uint) ``` Adds `length` bytes at `bytes` to the checksum. `bytes` is borrowed and read; `length` is read by value. A zero length changes nothing and is the one case in which `bytes` may be null. Splitting a message across several writes gives the same answer as one write. Runs in time proportional to `length` and allocates nothing. `bytes` must be readable for `length` bytes. | Name | Type | Description | | -------- | ------- | ------------------------------------ | | `bytes` | `*byte` | the bytes to absorb | | `length` | `uint` | how many bytes; zero absorbs nothing | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Hash/Src/Crc.rux#L156){rel=""nofollow""} ### `Finish` ```rux pub func Finish(self: &var Crc32) -> uint64 ``` The checksum of everything written so far, widened to 64 bits. `self` is borrowed. The upper 32 bits are always zero: a CRC-32 is 32 bits wide however it is reported, and [`Value`](https://rux-lang.dev/docs/api/hash/crc32#value) is the call to make when that width is what is wanted. Cannot fail. Runs in constant time and allocates nothing. **Returns**: the hash of everything written since the last reset [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Hash/Src/Crc.rux#L172){rel=""nofollow""} ## Related ### `Crc32Polynomial` ```rux pub const Crc32Polynomial: uint32 = 0xEDB88320; ``` The reflected IEEE 802.3 generator polynomial, which is what gzip, PNG and zip mean by "CRC-32". [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Hash/Src/Crc.rux#L24){rel=""nofollow""} ### `Crc32Initial` ```rux pub const Crc32Initial: uint32 = 0xFFFFFFFF; ``` The value a CRC register starts at, and the value the finished register is complemented against. Both ends are all ones, which is what makes a message padded with zeroes at either end give a different answer from the message itself. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Hash/Src/Crc.rux#L34){rel=""nofollow""} ### `Crc32Table` ```rux pub const Crc32Table: uint32[N] = …; ``` One byte of division by [`Crc32Polynomial`](https://rux-lang.dev/docs/api/hash/crc32#crc32-polynomial), precomputed for every possible byte. Entry `i` is `i` divided by the generator, so a whole byte of the message advances the register in one indexed lookup and one shift rather than eight conditional shifts. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Hash/Src/Crc.rux#L40){rel=""nofollow""} ### `Crc32Of` ```rux pub func Crc32Of(bytes: *byte, length: uint) -> uint32 ``` The CRC-32 of `length` bytes at `bytes`. `bytes` is borrowed and read; `length` is read by value. A zero length gives zero, the CRC of the empty message, and is the one case in which `bytes` may be null. Cannot fail. Runs in time proportional to `length` and allocates nothing. `bytes` must be readable for `length` bytes. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Hash/Src/Crc.rux#L252){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | ------- | ----------------- | | `bytes` | `*byte` | the bytes to hash | | `length` | `uint` | how many bytes | **Returns**: their CRC-32 checksum # Crc32c The CRC-32C of a message, computed a byte at a time. ```rux pub struct Crc32c { // private fields } ``` The variant to prefer for new work: it detects more of the double-bit errors that appear at storage-record lengths, and it is the one both supported architectures implement in hardware. Choose [`Crc32`](https://rux-lang.dev/docs/api/hash/crc32) only when an existing format requires it. Structural `Copy`; copying takes an independent snapshot of the register. ## Constructors ### `Crc32c` ```rux pub func Crc32c() -> Crc32c ``` Constructs a checksum with nothing written into it yet. **Returns**: a hasher with nothing written to it yet [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Hash/Src/Crc.rux#L192){rel=""nofollow""} ## Methods ### `Reset` ```rux pub func Reset(self: &var Crc32c) ``` Puts the checksum back to where [`Crc32c()`](https://rux-lang.dev/docs/api/hash/crc32c) leaves one. `self` is borrowed mutably. Everything written so far is forgotten. Cannot fail. Runs in constant time and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Hash/Src/Crc.rux#L200){rel=""nofollow""} ### `Value` ```rux pub func Value(self: &Crc32c) -> uint32 ``` The checksum of everything written so far. `self` is borrowed. The register complemented, which is the value every other implementation reports. Cannot fail. Runs in constant time and allocates nothing. **Returns**: the checksum of everything written so far [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Hash/Src/Crc.rux#L209){rel=""nofollow""} ## Implements Hasher `Crc32c` conforms to [`Hasher`](https://rux-lang.dev/docs/api/hash/hasher). ### `Write` ```rux pub func Write( self: &var Crc32c, bytes: *byte, length: uint ) ``` Adds `length` bytes at `bytes` to the checksum. `bytes` is borrowed and read; `length` is read by value. A zero length changes nothing and is the one case in which `bytes` may be null. Splitting a message across several writes gives the same answer as one write. Runs in time proportional to `length` and allocates nothing. `bytes` must be readable for `length` bytes. | Name | Type | Description | | -------- | ------- | ------------------------------------ | | `bytes` | `*byte` | the bytes to absorb | | `length` | `uint` | how many bytes; zero absorbs nothing | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Hash/Src/Crc.rux#L223){rel=""nofollow""} ### `Finish` ```rux pub func Finish(self: &var Crc32c) -> uint64 ``` The checksum of everything written so far, widened to 64 bits. `self` is borrowed. The upper 32 bits are always zero. Cannot fail. Runs in constant time and allocates nothing. **Returns**: the hash of everything written since the last reset [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Hash/Src/Crc.rux#L238){rel=""nofollow""} ## Related ### `Crc32cPolynomial` ```rux pub const Crc32cPolynomial: uint32 = 0x82F63B78; ``` The reflected Castagnoli generator polynomial, which is what iSCSI, ext4, Btrfs and SCTP mean by "CRC-32C". [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Hash/Src/Crc.rux#L28){rel=""nofollow""} ### `Crc32cTable` ```rux pub const Crc32cTable: uint32[N] = …; ``` One byte of division by [`Crc32cPolynomial`](https://rux-lang.dev/docs/api/hash/crc32c#crc32c-polynomial), precomputed for every possible byte. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Hash/Src/Crc.rux#L77){rel=""nofollow""} ### `Crc32cOf` ```rux pub func Crc32cOf(bytes: *byte, length: uint) -> uint32 ``` The CRC-32C of `length` bytes at `bytes`. `bytes` is borrowed and read; `length` is read by value. A zero length gives zero, and is the one case in which `bytes` may be null. Cannot fail. Runs in time proportional to `length` and allocates nothing. `bytes` must be readable for `length` bytes. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Hash/Src/Crc.rux#L267){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | ------- | ----------------- | | `bytes` | `*byte` | the bytes to hash | | `length` | `uint` | how many bytes | **Returns**: their CRC-32C checksum # Fnv1a32 FNV-1a over 32 bits, computed one byte at a time. ```rux pub struct Fnv1a32 { // private fields } ``` Copy, and holding only the accumulator, so passing one by value takes a snapshot of the hash so far — which is occasionally useful and never surprising, since there is nothing else in it. ## Constructors ### `Fnv1a32` ```rux pub func Fnv1a32() -> Fnv1a32 ``` Constructs a hasher with nothing written into it yet. **Returns**: a hasher seeded with the 32-bit offset basis [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Hash/Src/Fnv.rux#L47){rel=""nofollow""} ## Methods ### `Reset` ```rux pub func Reset(self: &var Fnv1a32) ``` Puts the hasher back to where [`Fnv1a32()`](https://rux-lang.dev/docs/api/hash/fnv1a32) leaves one. `self` is borrowed mutably. Everything written so far is forgotten. Cannot fail. Runs in constant time and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Hash/Src/Fnv.rux#L55){rel=""nofollow""} ### `Value` ```rux pub func Value(self: &Fnv1a32) -> uint32 ``` The 32-bit hash of everything written so far. `self` is borrowed. This is the algorithm's own width; [`Finish`](https://rux-lang.dev/docs/api/hash/fnv1a32#finish) widens it to 64 bits for the [`Hasher`](https://rux-lang.dev/docs/api/hash/hasher) contract, which does not make it a 64-bit hash. Cannot fail. Runs in constant time and allocates nothing. **Returns**: the hash of everything written so far [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Hash/Src/Fnv.rux#L65){rel=""nofollow""} ## Implements Hasher `Fnv1a32` conforms to [`Hasher`](https://rux-lang.dev/docs/api/hash/hasher). ### `Write` ```rux pub func Write( self: &var Fnv1a32, bytes: *byte, length: uint ) ``` Adds `length` bytes at `bytes` to the hash. `bytes` is borrowed and read; `length` is read by value. A zero length changes nothing and is the one case in which `bytes` may be null. Splitting the same bytes across several writes gives the same answer as one write, because there is no block to align to. Runs in time proportional to `length` and allocates nothing. `bytes` must be readable for `length` bytes. | Name | Type | Description | | -------- | ------- | ------------------------------------ | | `bytes` | `*byte` | the bytes to absorb | | `length` | `uint` | how many bytes; zero absorbs nothing | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Hash/Src/Fnv.rux#L80){rel=""nofollow""} ### `Finish` ```rux pub func Finish(self: &var Fnv1a32) -> uint64 ``` The hash of everything written so far, widened to 64 bits. `self` is borrowed. The hasher stays usable: asking twice gives the same answer, and writing more continues from here. The upper 32 bits are always zero, which is what a 32-bit hash promoted to the contract looks like — use [`Value`](https://rux-lang.dev/docs/api/hash/fnv1a32#value) when the 32-bit answer is what is wanted. Cannot fail. Runs in constant time and allocates nothing. **Returns**: the hash of everything written since the last reset [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Hash/Src/Fnv.rux#L97){rel=""nofollow""} ## Related ### `FnvOffsetBasis32` ```rux pub const FnvOffsetBasis32: uint32 = 0x811C9DC5; ``` The 32-bit FNV-1a offset basis, which is what an empty input hashes to. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Hash/Src/Fnv.rux#L20){rel=""nofollow""} ### `FnvPrime32` ```rux pub const FnvPrime32: uint32 = 16777619; ``` The 32-bit FNV prime. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Hash/Src/Fnv.rux#L24){rel=""nofollow""} ### `Fnv1a32Of` ```rux pub func Fnv1a32Of(bytes: *byte, length: uint) -> uint32 ``` The 32-bit FNV-1a hash of `length` bytes at `bytes`. `bytes` is borrowed and read; `length` is read by value. A zero length gives the offset basis, and is the one case in which `bytes` may be null. The one-shot form of making a hasher, writing once and finishing. Identical in result and cost. Cannot fail. Runs in time proportional to `length` and allocates nothing. `bytes` must be readable for `length` bytes. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Hash/Src/Fnv.rux#L169){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | ------- | ----------------- | | `bytes` | `*byte` | the bytes to hash | | `length` | `uint` | how many bytes | **Returns**: their 32-bit FNV-1a hash # Fnv1a64 FNV-1a over 64 bits, computed one byte at a time. ```rux pub struct Fnv1a64 { // private fields } ``` The width to prefer: the same cost per byte as the 32-bit form on any 64-bit machine, and far enough from a birthday collision that an ordinary table will never see one by accident. Structural `Copy`; copying takes an independent snapshot of the accumulator. ## Constructors ### `Fnv1a64` ```rux pub func Fnv1a64() -> Fnv1a64 ``` Constructs a hasher with nothing written into it yet. **Returns**: a hasher seeded with the 64-bit offset basis [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Hash/Src/Fnv.rux#L116){rel=""nofollow""} ## Methods ### `Reset` ```rux pub func Reset(self: &var Fnv1a64) ``` Puts the hasher back to where [`Fnv1a64()`](https://rux-lang.dev/docs/api/hash/fnv1a64) leaves one. `self` is borrowed mutably. Everything written so far is forgotten. Cannot fail. Runs in constant time and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Hash/Src/Fnv.rux#L124){rel=""nofollow""} ## Implements Hasher `Fnv1a64` conforms to [`Hasher`](https://rux-lang.dev/docs/api/hash/hasher). ### `Write` ```rux pub func Write( self: &var Fnv1a64, bytes: *byte, length: uint ) ``` Adds `length` bytes at `bytes` to the hash. `bytes` is borrowed and read; `length` is read by value. A zero length changes nothing and is the one case in which `bytes` may be null. Splitting the same bytes across several writes gives the same answer as one write. Runs in time proportional to `length` and allocates nothing. `bytes` must be readable for `length` bytes. | Name | Type | Description | | -------- | ------- | ------------------------------------ | | `bytes` | `*byte` | the bytes to absorb | | `length` | `uint` | how many bytes; zero absorbs nothing | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Hash/Src/Fnv.rux#L138){rel=""nofollow""} ### `Finish` ```rux pub func Finish(self: &var Fnv1a64) -> uint64 ``` The hash of everything written so far. `self` is borrowed. The hasher stays usable: asking twice gives the same answer, and writing more continues from here rather than starting over. Cannot fail. Runs in constant time and allocates nothing. **Returns**: the hash of everything written since the last reset [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Hash/Src/Fnv.rux#L154){rel=""nofollow""} ## Related ### `FnvOffsetBasis64` ```rux pub const FnvOffsetBasis64: uint64 = 0xCBF29CE484222325; ``` The 64-bit FNV-1a offset basis, which is what an empty input hashes to. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Hash/Src/Fnv.rux#L28){rel=""nofollow""} ### `FnvPrime64` ```rux pub const FnvPrime64: uint64 = 0x100000001B3; ``` The 64-bit FNV prime. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Hash/Src/Fnv.rux#L32){rel=""nofollow""} ### `Fnv1a64Of` ```rux pub func Fnv1a64Of(bytes: *byte, length: uint) -> uint64 ``` The 64-bit FNV-1a hash of `length` bytes at `bytes`. `bytes` is borrowed and read; `length` is read by value. A zero length gives the offset basis, and is the one case in which `bytes` may be null. Cannot fail. Runs in time proportional to `length` and allocates nothing. `bytes` must be readable for `length` bytes. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Hash/Src/Fnv.rux#L184){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | ------- | ----------------- | | `bytes` | `*byte` | the bytes to hash | | `length` | `uint` | how many bytes | **Returns**: their 64-bit FNV-1a hash # SipHash24 SipHash-2-4 over a stream of bytes, keyed with 128 bits. ```rux pub struct SipHash24 { // private fields } ``` Copy. Holds up to seven bytes of pending input alongside its state. ## Associated functions ### `WithKey` ```rux pub func WithKey(low: uint64, high: uint64) -> SipHash24 ``` A hasher keyed with `low` and `high`, with nothing written into it yet. Both halves are read by value. The key must be unpredictable to whoever supplies the input — draw it from `Rux/Entropy` at startup and keep it. A fixed key compiled into a program is a published key, and a published key is no key at all. Cannot fail. Runs in constant time and allocates nothing. | Name | Type | Description | | ------ | -------- | -------------------------------------- | | `low` | `uint64` | the key's first eight bytes as a word | | `high` | `uint64` | the key's second eight bytes as a word | **Returns**: a hasher keyed with those two words [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Hash/Src/SipHash.rux#L153){rel=""nofollow""} ### `WithKeyBytes` ```rux pub func WithKeyBytes(key: *byte) -> SipHash24 ``` A hasher keyed with the sixteen bytes at `key`, least significant byte of each half first. `key` is borrowed and read. This is the byte order the specification and every published test vector use, so it is what to reach for when checking against one; [`WithKey`](https://rux-lang.dev/docs/api/hash/sip-hash24#with-key) is what to reach for when the key came from `Rux/Entropy` as two words. Cannot fail. Runs in constant time and allocates nothing. `key` must be readable for sixteen bytes. | Name | Type | Description | | ----- | ------- | -------------------------------------------------- | | `key` | `*byte` | sixteen key bytes, read as two little-endian words | **Returns**: a hasher keyed with them [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Hash/Src/SipHash.rux#L173){rel=""nofollow""} ## Methods ### `Reset` ```rux pub func Reset(self: &var SipHash24) ``` Puts the hasher back to where it started, keeping its key. `self` is borrowed mutably. Everything written so far is forgotten; the key is not. Cannot fail. Runs in constant time and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Hash/Src/SipHash.rux#L189){rel=""nofollow""} ## Implements Hasher `SipHash24` conforms to [`Hasher`](https://rux-lang.dev/docs/api/hash/hasher). ### `Write` ```rux pub func Write( self: &var SipHash24, bytes: *byte, length: uint ) ``` Adds `length` bytes at `bytes` to the hash. `bytes` is borrowed and read; `length` is read by value. A zero length changes nothing and is the one case in which `bytes` may be null. Input that does not fill an eight-byte word is held until the rest arrives, so any division of the same byte stream into writes gives the same answer. Runs in time proportional to `length` and allocates nothing. `bytes` must be readable for `length` bytes. | Name | Type | Description | | -------- | ------- | ------------------------------------ | | `bytes` | `*byte` | the bytes to absorb | | `length` | `uint` | how many bytes; zero absorbs nothing | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Hash/Src/SipHash.rux#L206){rel=""nofollow""} ### `Finish` ```rux pub func Finish(self: &var SipHash24) -> uint64 ``` The hash of everything written so far. `self` is borrowed. Nothing is consumed: the finishing rounds run on a copy of the state, so asking twice gives the same answer and writing more continues from where the writes left off. Cannot fail. Runs in constant time and allocates nothing. **Returns**: the hash of everything written since the last reset [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Hash/Src/SipHash.rux#L251){rel=""nofollow""} ## Related ### `SipInit0` ```rux pub const SipInit0: uint64 = 0x736F6D6570736575; ``` The first initialization constant, mixed with the low half of the key. The four are the ASCII of "somepseudorandomlygeneratedbytes", split into eight-byte pieces — an arbitrary starting point chosen to be visibly arbitrary. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Hash/Src/SipHash.rux#L25){rel=""nofollow""} ### `SipInit1` ```rux pub const SipInit1: uint64 = 0x646F72616E646F6D; ``` The second initialization constant, mixed with the high half of the key. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Hash/Src/SipHash.rux#L29){rel=""nofollow""} ### `SipInit2` ```rux pub const SipInit2: uint64 = 0x6C7967656E657261; ``` The third initialization constant, mixed with the low half of the key. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Hash/Src/SipHash.rux#L33){rel=""nofollow""} ### `SipInit3` ```rux pub const SipInit3: uint64 = 0x7465646279746573; ``` The fourth initialization constant, mixed with the high half of the key. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Hash/Src/SipHash.rux#L37){rel=""nofollow""} ### `SipCompressionRounds` ```rux pub const SipCompressionRounds: uint = 2; ``` How many rounds each eight-byte word of input is mixed with: the 2 of SipHash-2-4. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Hash/Src/SipHash.rux#L41){rel=""nofollow""} ### `SipFinalizationRounds` ```rux pub const SipFinalizationRounds: uint = 4; ``` How many rounds finish the hash after the last word: the 4 of SipHash-2-4. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Hash/Src/SipHash.rux#L45){rel=""nofollow""} ### `SipState` ```rux pub struct SipState { // private fields } ``` The four words SipHash mixes, and the round that mixes them. Copy. Exposed because the round is the whole of the algorithm and worth being able to read, not because a caller has any reason to drive one directly. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Hash/Src/SipHash.rux#L51){rel=""nofollow""} **Associated functions** #### `FromKey` ```rux pub func FromKey(low: uint64, high: uint64) -> SipState ``` The state a key starts from. `low` and `high` are the two halves of the 128-bit key, read by value. Cannot fail. Runs in constant time and allocates nothing. | Name | Type | Description | | ------ | -------- | -------------------------------------- | | `low` | `uint64` | the key's first eight bytes as a word | | `high` | `uint64` | the key's second eight bytes as a word | **Returns**: the four-word state that key starts from [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Hash/Src/SipHash.rux#L66){rel=""nofollow""} **Methods** #### `Round` ```rux pub func Round(self: &var SipState, count: uint) ``` Runs `count` SipHash rounds over the state. `self` is borrowed mutably; `count` is read by value. Each round is four add-rotate-exclusive-or steps arranged so that every word depends on every other after two of them. Cannot fail. Runs in time proportional to `count` and allocates nothing. | Name | Type | Description | | ------- | ------ | ---------------------- | | `count` | `uint` | how many rounds to run | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Hash/Src/SipHash.rux#L81){rel=""nofollow""} ### `SipWord` ```rux pub func SipWord(bytes: *byte) -> uint64 ``` The eight bytes at `bytes` as a 64-bit word, least significant byte first. `bytes` is borrowed and read. Assembled a byte at a time, so the answer is the same at any address on any machine: SipHash is defined on a little-endian byte stream rather than on the machine's own order. Cannot fail. Runs in constant time and allocates nothing. `bytes` must be readable for eight bytes. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Hash/Src/SipHash.rux#L277){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------- | ------- | ------------------- | | `bytes` | `*byte` | eight bytes to read | **Returns**: them as a little-endian word ### `SipHash24Of` ```rux pub func SipHash24Of( bytes: *byte, length: uint, low: uint64, high: uint64 ) -> uint64 ``` The SipHash-2-4 of `length` bytes at `bytes`, keyed with `low` and `high`. `bytes` is borrowed and read; the rest are read by value. A zero length gives the hash of the empty input under that key, and is the one case in which `bytes` may be null. Cannot fail. Runs in time proportional to `length` and allocates nothing. `bytes` must be readable for `length` bytes. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Hash/Src/SipHash.rux#L298){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | -------- | -------------------------------------- | | `bytes` | `*byte` | the bytes to hash | | `length` | `uint` | how many bytes | | `low` | `uint64` | the key's first eight bytes as a word | | `high` | `uint64` | the key's second eight bytes as a word | **Returns**: their keyed hash # XxHash64 xxHash64 over a stream of bytes, in as many writes as the caller has. ```rux pub struct XxHash64 { // private fields } ``` Copy, but large: thirty-two bytes of pending input plus its accumulators. Borrow one by reference unless a snapshot of the hash so far is what is wanted. ## Constructors ### `XxHash64` ```rux pub func XxHash64() -> XxHash64 ``` Constructs an unseeded hasher with nothing written into it yet. **Returns**: a hasher with a seed of zero [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Hash/Src/XxHash.rux#L148){rel=""nofollow""} ## Associated functions ### `WithSeed` ```rux pub func WithSeed(seed: uint64) -> XxHash64 ``` A hasher with nothing written into it yet, using `seed`. `seed` is read by value. Two hashers with different seeds give unrelated answers for the same input, which is enough to keep accidental collisions from following data from one table to another. It is not enough to stop a deliberate collision: an adversary who knows the seed is no worse off than one hashing without it. Cannot fail. Runs in constant time and allocates nothing. | Name | Type | Description | | ------ | -------- | ---------------------- | | `seed` | `uint64` | the seed to start from | **Returns**: a hasher seeded with it [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Hash/Src/XxHash.rux#L160){rel=""nofollow""} ## Methods ### `Reset` ```rux pub func Reset(self: &var XxHash64) ``` Puts the hasher back to where it started, keeping its seed. `self` is borrowed mutably. Everything written so far is forgotten; the seed is not. Cannot fail. Runs in constant time and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Hash/Src/XxHash.rux#L177){rel=""nofollow""} ## Implements Hasher `XxHash64` conforms to [`Hasher`](https://rux-lang.dev/docs/api/hash/hasher). ### `Write` ```rux pub func Write( self: &var XxHash64, bytes: *byte, length: uint ) ``` Adds `length` bytes at `bytes` to the hash. `bytes` is borrowed and read; `length` is read by value. A zero length changes nothing and is the one case in which `bytes` may be null. Input that does not fill a block is held until the rest of it arrives, so any division of the same byte stream into writes gives the same answer. Runs in time proportional to `length` and allocates nothing. `bytes` must be readable for `length` bytes. | Name | Type | Description | | -------- | ------- | ------------------------------------ | | `bytes` | `*byte` | the bytes to absorb | | `length` | `uint` | how many bytes; zero absorbs nothing | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Hash/Src/XxHash.rux#L206){rel=""nofollow""} ### `Finish` ```rux pub func Finish(self: &var XxHash64) -> uint64 ``` The hash of everything written so far. `self` is borrowed. Nothing is consumed: asking twice gives the same answer, and writing more continues from where the writes left off rather than starting over. Cannot fail. Runs in time proportional to what is held pending, which is under one block. Allocates nothing. **Returns**: the hash of everything written since the last reset [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Hash/Src/XxHash.rux#L255){rel=""nofollow""} ## Related ### `XxPrime1` ```rux pub const XxPrime1: uint64 = 0x9E3779B185EBCA87; ``` The first xxHash64 prime, which every round multiplies by. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Hash/Src/XxHash.rux#L22){rel=""nofollow""} ### `XxPrime2` ```rux pub const XxPrime2: uint64 = 0xC2B2AE3D27D4EB4F; ``` The second xxHash64 prime, which scales each input lane before it is rotated in. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Hash/Src/XxHash.rux#L26){rel=""nofollow""} ### `XxPrime3` ```rux pub const XxPrime3: uint64 = 0x165667B19E3779F9; ``` The third xxHash64 prime, used in the four-byte tail step and the avalanche. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Hash/Src/XxHash.rux#L30){rel=""nofollow""} ### `XxPrime4` ```rux pub const XxPrime4: uint64 = 0x85EBCA77C2B2AE63; ``` The fourth xxHash64 prime, added after each merge and after each eight-byte tail step. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Hash/Src/XxHash.rux#L34){rel=""nofollow""} ### `XxPrime5` ```rux pub const XxPrime5: uint64 = 0x27D4EB2F165667C5; ``` The fifth xxHash64 prime, which seeds an input too short to fill a block and mixes each trailing byte. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Hash/Src/XxHash.rux#L38){rel=""nofollow""} ### `XxBlockSize` ```rux pub const XxBlockSize: uint = 32; ``` How many bytes one xxHash64 round consumes: four lanes of eight. An input shorter than this never touches the accumulators at all, which is why the short and long paths give different-looking code for the same algorithm. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Hash/Src/XxHash.rux#L44){rel=""nofollow""} ### `ReadLittleEndian64` ```rux pub func ReadLittleEndian64(bytes: *byte) -> uint64 ``` The eight bytes at `bytes` as a 64-bit value, least significant byte first. `bytes` is borrowed and read. Assembled a byte at a time rather than read as a word, so the answer is the same at any address on any machine — xxHash is defined on a little-endian byte stream, not on whatever the machine happens to hold. Cannot fail. Runs in constant time and allocates nothing. `bytes` must be readable for eight bytes. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Hash/Src/XxHash.rux#L55){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------- | ------- | ------------------- | | `bytes` | `*byte` | eight bytes to read | **Returns**: them as a little-endian word ### `ReadLittleEndian32` ```rux pub func ReadLittleEndian32(bytes: *byte) -> uint32 ``` The four bytes at `bytes` as a 32-bit value, least significant byte first. `bytes` is borrowed and read. Assembled a byte at a time, for the same reason as [`ReadLittleEndian64`](https://rux-lang.dev/docs/api/hash/xx-hash64#read-little-endian64). Cannot fail. Runs in constant time and allocates nothing. `bytes` must be readable for four bytes. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Hash/Src/XxHash.rux#L72){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------- | ------- | ------------------ | | `bytes` | `*byte` | four bytes to read | **Returns**: them as a little-endian half word ### `XxRound` ```rux pub func XxRound( accumulator: uint64, lane: uint64 ) -> uint64 ``` One accumulator round: mix `lane` into `accumulator`. Both are read by value and the new accumulator is returned. This is the whole of xxHash64's inner loop — scale the input, add, rotate, scale again — and it is what the four lanes each run independently. Cannot fail. Runs in constant time and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Hash/Src/XxHash.rux#L90){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------------- | -------- | ------------------------------ | | `accumulator` | `uint64` | the lane's running value | | `lane` | `uint64` | the input word to fold into it | **Returns**: the lane's new value ### `XxMerge` ```rux pub func XxMerge( hash: uint64, accumulator: uint64 ) -> uint64 ``` Folds one finished accumulator into the running hash. Both are read by value and the new hash is returned. The accumulator is passed through a round from zero first, so a lane that happened to end at a convenient value does not stay convenient. Cannot fail. Runs in constant time and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Hash/Src/XxHash.rux#L102){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------------- | -------- | ------------------------- | | `hash` | `uint64` | the running hash | | `accumulator` | `uint64` | the lane to merge into it | **Returns**: the merged hash ### `XxAvalanche` ```rux pub func XxAvalanche(hash: uint64) -> uint64 ``` The final mixing step, which spreads every input bit across the whole result. `hash` is read by value and the finished hash is returned. Without this a one-bit change in the input moves only the bits the round function reached; with it, about half of them move. Cannot fail. Runs in constant time and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Hash/Src/XxHash.rux#L114){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------ | -------- | ---------------- | | `hash` | `uint64` | the value to mix | **Returns**: it with every input bit spread across the output ### `XxHash64SeededOf` ```rux pub func XxHash64SeededOf( bytes: *byte, length: uint, seed: uint64 ) -> uint64 ``` The xxHash64 of `length` bytes at `bytes`, using `seed`. `bytes` is borrowed and read; `length` and `seed` are read by value. A zero length gives the hash of the empty input for that seed, and is the one case in which `bytes` may be null. Cannot fail. Runs in time proportional to `length` and allocates nothing. `bytes` must be readable for `length` bytes. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Hash/Src/XxHash.rux#L304){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | -------- | ---------------------- | | `bytes` | `*byte` | the bytes to hash | | `length` | `uint` | how many bytes | | `seed` | `uint64` | the seed to start from | **Returns**: their seeded hash ### `XxHash64Of` ```rux pub func XxHash64Of(bytes: *byte, length: uint) -> uint64 ``` The xxHash64 of `length` bytes at `bytes`, seeded with zero. `bytes` is borrowed and read; `length` is read by value. This is what every published xxHash64 test vector means by "the hash of" an input. Cannot fail. Runs in time proportional to `length` and allocates nothing. `bytes` must be readable for `length` bytes. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Hash/Src/XxHash.rux#L319){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | ------- | ----------------- | | `bytes` | `*byte` | the bytes to hash | | `length` | `uint` | how many bytes | **Returns**: their hash, seeded with zero # Random Pseudorandom number generators and distributions. ## Installation Add `Random` to the `[Dependencies]` table of your package's `Rux.toml`: ```toml [Dependencies] Random = { Namespace = "Rux", Version = "0.1.0" } ``` Standard packages are declared by hand: the registry does not serve them, so `rux add Rux/Random` cannot add them. ## Dependencies - [`Core`](https://rux-lang.dev/docs/api/core) 0.1.0 - [`Entropy`](https://rux-lang.dev/docs/api/entropy) 0.1.0 - [`Math`](https://rux-lang.dev/docs/api/math) 0.1.0 ## Guide Pseudorandom number generators and distributions. > **Not for keys, tokens or anything an adversary would like to guess.** These generators are fast and > reproducible, which is the opposite of what secrecy needs: anyone who sees enough output can reconstruct the > state and predict the rest. For randomness that must not be guessed, use [`Rux/Entropy`](https://github.com/rux-lang/Rux/blob/main/Packages/Random/../Entropy){rel=""nofollow""}. ### What it provides - **Generators** — [`Xoshiro256`](https://rux-lang.dev/docs/api/random/xoshiro256) and [`Pcg64Dxsm`](https://rux-lang.dev/docs/api/random/pcg64-dxsm), each seedable explicitly so a run is reproducible, or from `Rux/Entropy` when it should not be. - **A generator contract** — [`RandomGenerator`](https://rux-lang.dev/docs/api/random/random-generator), which everything else is written against, so a caller's own generator works with all of it. - **Uniform values** — integers of every width, floats in the unit interval, and bounded draws that are unbiased rather than merely close, using Lemire's method instead of a modulo. - **Distributions** — normal, exponential, gamma, beta, Bernoulli, binomial, Poisson and weighted choice, built on exact reductions rather than on approximations that drift in the tail. - **Sampling** — shuffling, choosing an index, weighted choice, and reservoir sampling for a stream whose length is not known in advance. ## Index ### Interfaces | Name | Summary | | -------------------------------------------------------------------------- | ----------------------------------------------- | | [`RandomGenerator`](https://rux-lang.dev/docs/api/random/random-generator) | A source of uniformly distributed 64-bit words. | ### Types | Name | Summary | | ---------------------------------------------------------------- | --------------------------------------------------------------------------------------------------- | | [`SplitMix64`](https://rux-lang.dev/docs/api/random/split-mix64) | The seeding generator: a fast mixer with a 64-bit state, used to spread one seed over a larger one. | | [`Pcg64Dxsm`](https://rux-lang.dev/docs/api/random/pcg64-dxsm) | A PCG64-DXSM generator. | | [`Reservoir<T>`](https://rux-lang.dev/docs/api/random/reservoir) | A reservoir sample being built. | | [`Xoshiro256`](https://rux-lang.dev/docs/api/random/xoshiro256) | A Xoshiro256\*\* generator. | ### Functions | Name | Summary | | ---------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------- | | [`Binomial<G>`](https://rux-lang.dev/docs/api/random/distributions#binomial) | The number of successes in `trials` independent trials each succeeding with probability `probability`. | | [`Poisson<G>`](https://rux-lang.dev/docs/api/random/distributions#poisson) | The number of events in one interval when they arrive independently at the given mean rate. | | [`Bernoulli<G>`](https://rux-lang.dev/docs/api/random/distributions#bernoulli) | A coin that comes up `true` with probability `probability`. | | [`Exponential<G>`](https://rux-lang.dev/docs/api/random/distributions#exponential) | A value from the exponential distribution with rate one. | | [`ExponentialWithRate<G>`](https://rux-lang.dev/docs/api/random/distributions#exponential-with-rate) | A value from the exponential distribution with the given rate. | | [`NormalPair<G>`](https://rux-lang.dev/docs/api/random/distributions#normal-pair) | A pair of independent standard normal values. | | [`Normal<G>`](https://rux-lang.dev/docs/api/random/distributions#normal) | A single standard normal value: mean zero, standard deviation one. | | [`NormalWith<G>`](https://rux-lang.dev/docs/api/random/distributions#normal-with) | A normal value with the given mean and standard deviation. | | [`FillBytes<G>`](https://rux-lang.dev/docs/api/random/random-generator#fill-bytes) | Fills `into` with random bytes. | | [`NextUint32<G>`](https://rux-lang.dev/docs/api/random/random-generator#next-uint32) | The next 32-bit word: the low half of a 64-bit one. | | [`NextUint16<G>`](https://rux-lang.dev/docs/api/random/random-generator#next-uint16) | The next 16-bit word. | | [`NextUint8<G>`](https://rux-lang.dev/docs/api/random/random-generator#next-uint8) | The next 8-bit word. | | [`NextUint128<G>`](https://rux-lang.dev/docs/api/random/random-generator#next-uint128) | The next 128-bit word, high half drawn first. | | [`NextFloat64<G>`](https://rux-lang.dev/docs/api/random/random-generator#next-float64) | A `float64` uniformly distributed in `[0, 1)`. | | [`NextFloat32<G>`](https://rux-lang.dev/docs/api/random/random-generator#next-float32) | A `float32` uniformly distributed in `[0, 1)`, from the top 24 bits. | | [`Gamma<G>`](https://rux-lang.dev/docs/api/random/distributions#gamma) | A value from the gamma distribution with the given shape and unit scale. | | [`GammaWithScale<G>`](https://rux-lang.dev/docs/api/random/distributions#gamma-with-scale) | A value from the gamma distribution with the given shape and scale. | | [`Beta<G>`](https://rux-lang.dev/docs/api/random/distributions#beta) | A value from the beta distribution with the two given shapes, in `[0, 1]`. | | [`Offer<G, T>`](https://rux-lang.dev/docs/api/random/reservoir#offer) | Offers `item` to `reservoir`. | | [`Shuffle<G, T>`](https://rux-lang.dev/docs/api/random/sampling#shuffle) | Shuffles `items` into a uniformly random order. | | [`ChooseIndex<G>`](https://rux-lang.dev/docs/api/random/sampling#choose-index) | A uniformly chosen index below `count`, or `count` itself when there is nothing to choose from. | | [`WeightedIndex<G>`](https://rux-lang.dev/docs/api/random/sampling#weighted-index) | An index chosen in proportion to `weights`. | | [`XoshiroFromEntropy`](https://rux-lang.dev/docs/api/random/xoshiro256#xoshiro-from-entropy) | A [`Xoshiro256`](https://rux-lang.dev/docs/api/random/xoshiro256) seeded from the operating system's entropy. | | [`PcgFromEntropy`](https://rux-lang.dev/docs/api/random/pcg64-dxsm#pcg-from-entropy) | A [`Pcg64Dxsm`](https://rux-lang.dev/docs/api/random/pcg64-dxsm) seeded from the operating system's entropy, on the default stream. | | [`PcgFromEntropyWithStream`](https://rux-lang.dev/docs/api/random/pcg64-dxsm#pcg-from-entropy-with-stream) | A [`Pcg64Dxsm`](https://rux-lang.dev/docs/api/random/pcg64-dxsm) seeded from entropy on the stream `stream` selects. | | [`UniformBelow<G>`](https://rux-lang.dev/docs/api/random/uniform#uniform-below) | A uniform value in `[0, bound)`. | | [`UniformInRange<G>`](https://rux-lang.dev/docs/api/random/uniform#uniform-in-range) | A uniform value in `[low, high]`, both ends included. | | [`UniformInSignedRange<G>`](https://rux-lang.dev/docs/api/random/uniform#uniform-in-signed-range) | A uniform signed value in `[low, high]`, both ends included. | | [`UniformFloatInRange<G>`](https://rux-lang.dev/docs/api/random/uniform#uniform-float-in-range) | A uniform `float64` in `[low, high)`. | ### Constants | Name | Summary | | --------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------ | | [`DirectMethodLimit`](https://rux-lang.dev/docs/api/random/distributions#direct-method-limit) | Below this the direct methods are cheaper than the reductions, and above it they stop being practical. | | [`PcgMultiplier`](https://rux-lang.dev/docs/api/random/pcg64-dxsm#pcg-multiplier) | The multiplier used by both the state step and the output function. | # RandomGenerator A source of uniformly distributed 64-bit words. ```rux pub interface RandomGenerator { func NextUint64(self: &var Self) -> uint64; } ``` The single operation every generator supplies. Implementations must advance their own state, so the receiver is a mutable reference. Borrowed interface views and generic bounds both keep it the caller's state that advances. ## Requirements ### `NextUint64` ```rux func NextUint64(self: &var Self) -> uint64 ``` The next 64-bit word, and the state advanced past it. **Returns**: the next 64 bits [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Random/Src/Generator.rux#L22){rel=""nofollow""} ## Implementations | Type | Summary | | ---------------------------------------------------------------- | --------------------------------------------------------------------------------------------------- | | [`SplitMix64`](https://rux-lang.dev/docs/api/random/split-mix64) | The seeding generator: a fast mixer with a 64-bit state, used to spread one seed over a larger one. | | [`Pcg64Dxsm`](https://rux-lang.dev/docs/api/random/pcg64-dxsm) | A PCG64-DXSM generator. | | [`Xoshiro256`](https://rux-lang.dev/docs/api/random/xoshiro256) | A Xoshiro256\*\* generator. | ## Related ### `FillBytes<G>` ```rux pub func FillBytes<G: RandomGenerator>( generator: &var G, into: var char8[..] ) ``` Fills `into` with random bytes. The words are consumed least significant byte first, and a partial final word contributes its low bytes and discards the rest — so the same `into.length` always consumes the same number of words, and two runs that fill buffers of the same size stay in step. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Random/Src/Extract.rux#L15){rel=""nofollow""} **Type parameters** | Name | Description | | -------------------- | -------------------- | | `G: RandomGenerator` | the generator's type | **Parameters** | Name | Type | Description | | ----------- | --------------- | ------------------------ | | `generator` | `&var G` | where the bits come from | | `into` | `var char8[..]` | receives the bytes | ### `NextUint32<G>` ```rux pub func NextUint32<G: RandomGenerator>(generator: &var G) -> uint32 ``` The next 32-bit word: the low half of a 64-bit one. A whole word is consumed and half of it discarded, which costs nothing and keeps the word stream aligned -- a generator that handed out the halves in turn would produce different sequences depending on how many narrow draws happened to precede a wide one. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Random/Src/Extract.rux#L37){rel=""nofollow""} **Type parameters** | Name | Description | | -------------------- | -------------------- | | `G: RandomGenerator` | the generator's type | **Parameters** | Name | Type | Description | | ----------- | -------- | ------------------------ | | `generator` | `&var G` | where the bits come from | **Returns**: the next 32 bits ### `NextUint16<G>` ```rux pub func NextUint16<G: RandomGenerator>(generator: &var G) -> uint16 ``` The next 16-bit word. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Random/Src/Extract.rux#L46){rel=""nofollow""} **Type parameters** | Name | Description | | -------------------- | -------------------- | | `G: RandomGenerator` | the generator's type | **Parameters** | Name | Type | Description | | ----------- | -------- | ------------------------ | | `generator` | `&var G` | where the bits come from | **Returns**: the next 16 bits ### `NextUint8<G>` ```rux pub func NextUint8<G: RandomGenerator>(generator: &var G) -> uint8 ``` The next 8-bit word. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Random/Src/Extract.rux#L55){rel=""nofollow""} **Type parameters** | Name | Description | | -------------------- | -------------------- | | `G: RandomGenerator` | the generator's type | **Parameters** | Name | Type | Description | | ----------- | -------- | ------------------------ | | `generator` | `&var G` | where the bits come from | **Returns**: the next 8 bits ### `NextUint128<G>` ```rux pub func NextUint128<G: RandomGenerator>(generator: &var G) -> uint128 ``` The next 128-bit word, high half drawn first. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Random/Src/Extract.rux#L64){rel=""nofollow""} **Type parameters** | Name | Description | | -------------------- | -------------------- | | `G: RandomGenerator` | the generator's type | **Parameters** | Name | Type | Description | | ----------- | -------- | ------------------------ | | `generator` | `&var G` | where the bits come from | **Returns**: the next 128 bits ### `NextFloat64<G>` ```rux pub func NextFloat64<G: RandomGenerator>(generator: &var G) -> float64 ``` A `float64` uniformly distributed in `[0, 1)`. Built from the top 53 bits of a word, which is exactly the number a `float64` can hold without rounding: every value produced is a multiple of 2^-53, each equally likely, and none is ever exactly one. Dividing a whole word by 2^64 instead would round — and rounding upward at the top would produce exactly one, which callers scaling into an array index do not expect. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Random/Src/Extract.rux#L79){rel=""nofollow""} **Type parameters** | Name | Description | | -------------------- | -------------------- | | `G: RandomGenerator` | the generator's type | **Parameters** | Name | Type | Description | | ----------- | -------- | ------------------------ | | `generator` | `&var G` | where the bits come from | **Returns**: a value in `[0, 1)`, with 53 bits of significance ### `NextFloat32<G>` ```rux pub func NextFloat32<G: RandomGenerator>(generator: &var G) -> float32 ``` A `float32` uniformly distributed in `[0, 1)`, from the top 24 bits. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Random/Src/Extract.rux#L89){rel=""nofollow""} **Type parameters** | Name | Description | | -------------------- | -------------------- | | `G: RandomGenerator` | the generator's type | **Parameters** | Name | Type | Description | | ----------- | -------- | ------------------------ | | `generator` | `&var G` | where the bits come from | **Returns**: a value in `[0, 1)`, with 24 bits of significance # Pcg64Dxsm A PCG64-DXSM generator. ```rux pub struct Pcg64Dxsm { // private fields } ``` ## Constructors ### `Pcg64Dxsm` ```rux pub func Pcg64Dxsm(seed: uint64) -> Pcg64Dxsm ``` A generator seeded by spreading `seed` through [`SplitMix64`](https://rux-lang.dev/docs/api/random/split-mix64), on the default stream. | Name | Type | Description | | ------ | -------- | ----------------------------------- | | `seed` | `uint64` | the value the generator starts from | **Returns**: a generator seeded with that value, on the default stream [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Random/Src/Pcg64.rux#L32){rel=""nofollow""} ## Associated functions ### `WithStream` ```rux pub func WithStream( seed: uint64, stream: uint64 ) -> Pcg64Dxsm ``` A generator on the stream `stream` selects. Two generators with the same seed and different streams produce unrelated sequences of the same period, which is how independent parallel streams are made without the workers having to agree on anything but their own index. | Name | Type | Description | | -------- | -------- | ----------------------------------------------------------- | | `seed` | `uint64` | the value the generator starts from | | `stream` | `uint64` | which of the generator's independent sequences to draw from | **Returns**: a generator seeded with that value, on the given stream [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Random/Src/Pcg64.rux#L44){rel=""nofollow""} ## Implements RandomGenerator `Pcg64Dxsm` conforms to [`RandomGenerator`](https://rux-lang.dev/docs/api/random/random-generator). ### `NextUint64` ```rux pub func NextUint64(self: &var Pcg64Dxsm) -> uint64 ``` The next word. The output is computed from the state before it advances. The high half is folded twice and then multiplied by the low half forced odd — an odd multiplier is invertible, so that last step permutes the value rather than collapsing any of it. **Returns**: the next 64 bits [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Random/Src/Pcg64.rux#L78){rel=""nofollow""} ## Related ### `PcgMultiplier` ```rux pub const PcgMultiplier: uint64 = 0xDA942042E4DD58B5; ``` The multiplier used by both the state step and the output function. PCG's "cheap" 64-bit multiplier, which the DXSM variant uses in the 128-bit step as well. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Random/Src/Pcg64.rux#L16){rel=""nofollow""} ### `PcgFromEntropy` ```rux pub func PcgFromEntropy() -> Pcg64Dxsm ! EntropyError ``` A [`Pcg64Dxsm`](https://rux-lang.dev/docs/api/random/pcg64-dxsm) seeded from the operating system's entropy, on the default stream. Fails and recovers exactly as [`XoshiroFromEntropy`](https://rux-lang.dev/docs/api/random/xoshiro256#xoshiro-from-entropy) does. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Random/Src/Seeding.rux#L26){rel=""nofollow""} **Returns**: a generator seeded from the system, or why it could not be seeded ### `PcgFromEntropyWithStream` ```rux pub func PcgFromEntropyWithStream(stream: uint64) -> Pcg64Dxsm ! EntropyError ``` A [`Pcg64Dxsm`](https://rux-lang.dev/docs/api/random/pcg64-dxsm) seeded from entropy on the stream `stream` selects. The intended shape for parallel work: every worker calls this with its own index, so the streams are independent by construction and the whole run is reproducible from the one seed if it is recorded. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Random/Src/Seeding.rux#L36){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | -------- | ----------------------------------------------------------- | | `stream` | `uint64` | which of the generator's independent sequences to draw from | **Returns**: a generator on that stream seeded from the system, or why it could not be seeded # Reservoir\<T> A reservoir sample being built. ```rux pub struct Reservoir<T> { // private fields } ``` Offer every item of the stream in turn and the reservoir ends holding a uniformly chosen subset of whatever arrived, each subset of that size equally likely. The caller owns the storage, and its length is the sample size. ## Type parameters | Name | Description | | ---- | ------------- | | `T` | the item type | ## Constructors ### `Reservoir` ```rux pub func Reservoir(room: var T[..]) -> Reservoir<T> ``` A reservoir that will fill `room`. | Name | Type | Description | | ------ | ----------- | ---------------------------------- | | `room` | `var T[..]` | how many items the reservoir keeps | **Returns**: an empty reservoir that will keep `room` items [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Random/Src/Reservoir.rux#L25){rel=""nofollow""} ## Methods ### `Length` ```rux pub func Length(self: &Reservoir<T>) -> uint ``` How many items the reservoir currently holds, which is the smaller of the sample size and the number offered. **Returns**: how many items it currently holds [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Random/Src/Reservoir.rux#L33){rel=""nofollow""} ### `Seen` ```rux pub func Seen(self: &Reservoir<T>) -> uint ``` How many items have been offered. **Returns**: how many items have been offered to it in total [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Random/Src/Reservoir.rux#L40){rel=""nofollow""} ## Related ### `Offer<G, T>` ```rux pub func Offer<G: RandomGenerator, T>( generator: &var G, reservoir: &var Reservoir<T>, item: T ) ``` Offers `item` to `reservoir`. Algorithm R: while the reservoir has room the item is kept outright, and afterwards the item replaces a uniformly chosen existing entry with probability equal to the sample size over the number seen. That is what keeps every subset equally likely at every moment, not merely at the end — so a stream can be cut short and the sample is still uniform over what arrived. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Random/Src/Reservoir.rux#L56){rel=""nofollow""} **Type parameters** | Name | Description | | -------------------- | -------------------- | | `G: RandomGenerator` | the generator's type | | `T` | the item type | **Parameters** | Name | Type | Description | | ----------- | ------------------- | ---------------------------------- | | `generator` | `&var G` | where the bits come from | | `reservoir` | `&var Reservoir<T>` | the reservoir to offer the item to | | `item` | `T` | the item being offered | # SplitMix64 The seeding generator: a fast mixer with a 64-bit state, used to spread one seed over a larger one. ```rux pub struct SplitMix64 { // private fields } ``` Not for general use — its period is only 2^64 and it fails statistical tests a real generator passes. Its job is the one thing it is very good at: turning a seed a human chose, which is very likely to be zero or one or a timestamp, into a full-entropy state for a generator that deserves better input than that. Seeding a 256-bit generator by copying a small integer into one word and leaving the rest zero is a classic way to get correlated streams out of an excellent algorithm. ## Constructors ### `SplitMix64` ```rux pub func SplitMix64(seed: uint64) -> SplitMix64 ``` A mixer starting from `seed`. Every seed is acceptable, including zero. | Name | Type | Description | | ------ | -------- | ----------------------------------- | | `seed` | `uint64` | the value the generator starts from | **Returns**: a generator seeded with that value [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Random/Src/Generator.rux#L42){rel=""nofollow""} ## Implements RandomGenerator `SplitMix64` conforms to [`RandomGenerator`](https://rux-lang.dev/docs/api/random/random-generator). ### `NextUint64` ```rux pub func NextUint64(self: &var SplitMix64) -> uint64 ``` The next word: the state advanced by an odd constant, then avalanched. The additive step guarantees the full period of 2^64 whatever the seed, and the mixing afterwards is what turns a counter into something that looks random. Both constants are Steele, Lea and Flood's. **Returns**: the next 64 bits [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Random/Src/Generator.rux#L54){rel=""nofollow""} # Xoshiro256 A Xoshiro256\*\* generator. ```rux pub struct Xoshiro256 { // private fields } ``` ## Constructors ### `Xoshiro256` ```rux pub func Xoshiro256(seed: uint64) -> Xoshiro256 ``` A generator seeded by spreading `seed` through [`SplitMix64`](https://rux-lang.dev/docs/api/random/split-mix64). Every seed is acceptable, zero included: the mixer's output is what fills the state, and it cannot produce four zero words from any seed. Seeding by copying the seed into one word and leaving the rest zero — which is what a caller does by hand — gives a state so close to the fixed point that the first several outputs are visibly poor, which is the whole reason this goes through the mixer. | Name | Type | Description | | ------ | -------- | ----------------------------------- | | `seed` | `uint64` | the value the generator starts from | **Returns**: a generator seeded with that value [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Random/Src/Xoshiro.rux#L31){rel=""nofollow""} ## Associated functions ### `FromState` ```rux pub func FromState(words: uint64[N]) -> Xoshiro256 ``` A generator from four words of state given directly, for reproducing a stream recorded elsewhere. An all-zero state is the one state with no future, so it is replaced by the mixer's output for a zero seed rather than accepted into a generator that would return zero forever. | Name | Type | Description | | ------- | ----------- | ---------------------------------------------- | | `words` | `uint64[N]` | the generator's state words, taken as they are | **Returns**: a generator with exactly those state words [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Random/Src/Xoshiro.rux#L48){rel=""nofollow""} ## Implements RandomGenerator `Xoshiro256` conforms to [`RandomGenerator`](https://rux-lang.dev/docs/api/random/random-generator). ### `NextUint64` ```rux pub func NextUint64(self: &var Xoshiro256) -> uint64 ``` The next word. The result is computed from the state *before* it advances, which is the published order and the reason two implementations agree on the first word rather than being one step apart forever. **Returns**: the next 64 bits [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Random/Src/Xoshiro.rux#L60){rel=""nofollow""} ## Related ### `XoshiroFromEntropy` ```rux pub func XoshiroFromEntropy() -> Xoshiro256 ! EntropyError ``` A [`Xoshiro256`](https://rux-lang.dev/docs/api/random/xoshiro256) seeded from the operating system's entropy. Fails with why the entropy could not be obtained. A caller that is content with a predictable generator when the system has no entropy recovers explicitly, as in `XoshiroFromEntropy() catch { else => Xoshiro256(0u64) }`. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Random/Src/Seeding.rux#L18){rel=""nofollow""} **Returns**: a generator seeded from the system, or why it could not be seeded # Distributions Values from the Bernoulli, exponential, normal, binomial, Poisson, gamma and beta distributions. ## `Binomial<G>` ```rux pub func Binomial<G: RandomGenerator>( generator: &var G, trials: uint64, probability: float64 ) -> uint64 ``` The number of successes in `trials` independent trials each succeeding with probability `probability`. A probability at or below zero gives zero successes and one at or above one gives every trial, matching [`Bernoulli`](https://rux-lang.dev/docs/api/random/distributions#bernoulli)'s treatment of the same edges. Zero trials give zero. Small counts are summed directly, which is the definition. Large ones are split by a beta draw: the median trial's success probability has a beta distribution, and comparing it to `probability` says which side the answer falls on and leaves a strictly smaller problem. That halves the count each step, so a binomial over a billion trials costs about thirty draws rather than a billion. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Random/Src/Counting.rux#L21){rel=""nofollow""} **Type parameters** | Name | Description | | -------------------- | -------------------- | | `G: RandomGenerator` | the generator's type | **Parameters** | Name | Type | Description | | ------------- | --------- | ---------------------------------- | | `generator` | `&var G` | where the bits come from | | `trials` | `uint64` | how many independent trials | | `probability` | `float64` | the chance of success, in `[0, 1]` | **Returns**: how many of `trials` succeeded ## `Poisson<G>` ```rux pub func Poisson<G: RandomGenerator>( generator: &var G, mean: float64 ) -> uint64 ``` The number of events in one interval when they arrive independently at the given mean rate. A mean at or below zero gives zero. A small mean uses Knuth's method — multiply uniforms until the product falls below `exp(-mean)` — which costs about `mean` draws and is exact. A large mean would cost too many draws that way, and the product would underflow to zero before the loop ended, so the mean is consumed in chunks: a gamma draw of integer shape is the waiting time for that many events, and either it overshoots the interval, in which case the count is a binomial of what is left, or it fits and the remainder carries on. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Random/Src/Counting.rux#L54){rel=""nofollow""} **Type parameters** | Name | Description | | -------------------- | -------------------- | | `G: RandomGenerator` | the generator's type | **Parameters** | Name | Type | Description | | ----------- | --------- | ------------------------ | | `generator` | `&var G` | where the bits come from | | `mean` | `float64` | the distribution's mean | **Returns**: a draw from the Poisson distribution with that mean ## `Bernoulli<G>` ```rux pub func Bernoulli<G: RandomGenerator>( generator: &var G, probability: float64 ) -> bool ``` A coin that comes up `true` with probability `probability`. A probability at or below zero never comes up true and one at or above one always does, so a caller computing a probability that drifts slightly out of range gets the sensible answer rather than an occasional inversion. The comparison is against a draw in `[0, 1)`, so a probability of exactly zero is impossible rather than merely rare — which is what makes the two ends behave. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Random/Src/Distribution.rux#L19){rel=""nofollow""} **Type parameters** | Name | Description | | -------------------- | -------------------- | | `G: RandomGenerator` | the generator's type | **Parameters** | Name | Type | Description | | ------------- | --------- | ---------------------------------- | | `generator` | `&var G` | where the bits come from | | `probability` | `float64` | the chance of success, in `[0, 1]` | **Returns**: true with the given probability ## `Exponential<G>` ```rux pub func Exponential<G: RandomGenerator>(generator: &var G) -> float64 ``` A value from the exponential distribution with rate one. The inverse-transform method: the negated logarithm of a uniform draw. Written on `1 - u` rather than on `u` because [`NextFloat64`](https://rux-lang.dev/docs/api/random/random-generator#next-float64) can return exactly zero, whose logarithm is an infinity — so the draw that would produce an infinite sample is instead the one that produces zero, which the distribution does allow. Multiply the result by a mean, or divide by a rate, to scale it. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Random/Src/Distribution.rux#L34){rel=""nofollow""} **Type parameters** | Name | Description | | -------------------- | -------------------- | | `G: RandomGenerator` | the generator's type | **Parameters** | Name | Type | Description | | ----------- | -------- | ------------------------ | | `generator` | `&var G` | where the bits come from | **Returns**: a draw from the exponential distribution with rate one ## `ExponentialWithRate<G>` ```rux pub func ExponentialWithRate<G: RandomGenerator>( generator: &var G, rate: float64 ) -> float64 ``` A value from the exponential distribution with the given rate. A rate at or below zero has no distribution and gives zero. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Random/Src/Distribution.rux#L45){rel=""nofollow""} **Type parameters** | Name | Description | | -------------------- | -------------------- | | `G: RandomGenerator` | the generator's type | **Parameters** | Name | Type | Description | | ----------- | --------- | ------------------------------------------------------------ | | `generator` | `&var G` | where the bits come from | | `rate` | `float64` | the distribution's rate, which is the reciprocal of its mean | **Returns**: a draw from the exponential distribution with that rate ## `NormalPair<G>` ```rux pub func NormalPair<G: RandomGenerator>( generator: &var G, first: *var float64, second: *var float64 ) ``` A pair of independent standard normal values. The Box-Muller transform, which produces two at a time from two uniform draws — so this returns both rather than throwing one away. The radial draw is taken on `1 - u` for the same reason as the exponential: the logarithm of an exact zero is an infinity, and the generator will produce an exact zero eventually. The polar form of the transform avoids the trigonometric functions at the cost of rejecting about a fifth of its draws; this uses the direct form, which consumes a fixed two words and is therefore reproducible in a way a rejection loop is not. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Random/Src/Distribution.rux#L62){rel=""nofollow""} **Type parameters** | Name | Description | | -------------------- | -------------------- | | `G: RandomGenerator` | the generator's type | **Parameters** | Name | Type | Description | | ----------- | -------------- | ------------------------------------ | | `generator` | `&var G` | where the bits come from | | `first` | `*var float64` | receives the first of the two draws | | `second` | `*var float64` | receives the second of the two draws | ## `Normal<G>` ```rux pub func Normal<G: RandomGenerator>(generator: &var G) -> float64 ``` A single standard normal value: mean zero, standard deviation one. Discards the second value of the pair. A caller drawing many should use [`NormalPair`](https://rux-lang.dev/docs/api/random/distributions#normal-pair) and keep both, which halves the work. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Random/Src/Distribution.rux#L76){rel=""nofollow""} **Type parameters** | Name | Description | | -------------------- | -------------------- | | `G: RandomGenerator` | the generator's type | **Parameters** | Name | Type | Description | | ----------- | -------- | ------------------------ | | `generator` | `&var G` | where the bits come from | **Returns**: a draw from the standard normal distribution ## `NormalWith<G>` ```rux pub func NormalWith<G: RandomGenerator>( generator: &var G, mean: float64, deviation: float64 ) -> float64 ``` A normal value with the given mean and standard deviation. A negative standard deviation is reflected rather than refused, since the distribution it describes is the same one; a zero gives the mean exactly. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Random/Src/Distribution.rux#L92){rel=""nofollow""} **Type parameters** | Name | Description | | -------------------- | -------------------- | | `G: RandomGenerator` | the generator's type | **Parameters** | Name | Type | Description | | ----------- | --------- | ------------------------------------- | | `generator` | `&var G` | where the bits come from | | `mean` | `float64` | the distribution's mean | | `deviation` | `float64` | the distribution's standard deviation | **Returns**: a draw from the normal distribution with that mean and deviation ## `DirectMethodLimit` ```rux pub const DirectMethodLimit: float64 = 30.0; ``` Below this the direct methods are cheaper than the reductions, and above it they stop being practical. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Random/Src/Gamma.rux#L16){rel=""nofollow""} ## `Gamma<G>` ```rux pub func Gamma<G: RandomGenerator>( generator: &var G, shape: float64 ) -> float64 ``` A value from the gamma distribution with the given shape and unit scale. Marsaglia and Tsang's method: a normal draw squeezed through a cube, which accepts on the first attempt more than ninety-five percent of the time for any shape at or above one. A shape below one is generated from a shape one larger and scaled down, since the density is unbounded at zero there and the squeeze does not hold. A shape at or below zero has no distribution and gives zero. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Random/Src/Gamma.rux#L28){rel=""nofollow""} **Type parameters** | Name | Description | | -------------------- | -------------------- | | `G: RandomGenerator` | the generator's type | **Parameters** | Name | Type | Description | | ----------- | --------- | ---------------------------------- | | `generator` | `&var G` | where the bits come from | | `shape` | `float64` | the distribution's shape parameter | **Returns**: a draw from the gamma distribution with that shape and scale one ## `GammaWithScale<G>` ```rux pub func GammaWithScale<G: RandomGenerator>( generator: &var G, shape: float64, scale: float64 ) -> float64 ``` A value from the gamma distribution with the given shape and scale. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Random/Src/Gamma.rux#L73){rel=""nofollow""} **Type parameters** | Name | Description | | -------------------- | -------------------- | | `G: RandomGenerator` | the generator's type | **Parameters** | Name | Type | Description | | ----------- | --------- | ---------------------------------- | | `generator` | `&var G` | where the bits come from | | `shape` | `float64` | the distribution's shape parameter | | `scale` | `float64` | the distribution's scale parameter | **Returns**: a draw from the gamma distribution with that shape and scale ## `Beta<G>` ```rux pub func Beta<G: RandomGenerator>( generator: &var G, first: float64, second: float64 ) -> float64 ``` A value from the beta distribution with the two given shapes, in `[0, 1]`. Built from two gamma draws, which is the definition rather than an approximation of it. Two shapes that are both zero leave nothing to divide and give a half. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Random/Src/Gamma.rux#L87){rel=""nofollow""} **Type parameters** | Name | Description | | -------------------- | -------------------- | | `G: RandomGenerator` | the generator's type | **Parameters** | Name | Type | Description | | ----------- | --------- | -------------------------- | | `generator` | `&var G` | where the bits come from | | `first` | `float64` | the first shape parameter | | `second` | `float64` | the second shape parameter | **Returns**: a draw from the beta distribution with those two shape parameters # Sampling and shuffling Shuffling a slice and choosing indices, uniformly or by weight. ## `Shuffle<G, T>` ```rux pub func Shuffle<G: RandomGenerator, T>( generator: &var G, items: var T[..] ) ``` Shuffles `items` into a uniformly random order. Fisher and Yates' method, walking from the end and swapping each position with one at or below it. The bound is what makes it uniform: swapping with a position anywhere in the collection is the version that is subtly biased, and it is the version almost everyone writes first. Runs in time proportional to the length and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Random/Src/Sample.rux#L20){rel=""nofollow""} **Type parameters** | Name | Description | | -------------------- | -------------------- | | `G: RandomGenerator` | the generator's type | | `T` | the item type | **Parameters** | Name | Type | Description | | ----------- | ----------- | -------------------------------- | | `generator` | `&var G` | where the bits come from | | `items` | `var T[..]` | the sequence to shuffle in place | ## `ChooseIndex<G>` ```rux pub func ChooseIndex<G: RandomGenerator>( generator: &var G, count: uint ) -> uint ``` A uniformly chosen index below `count`, or `count` itself when there is nothing to choose from. Returning the count for an empty collection gives the caller a value that cannot be mistaken for a valid index, which a zero would be. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Random/Src/Sample.rux#L43){rel=""nofollow""} **Type parameters** | Name | Description | | -------------------- | -------------------- | | `G: RandomGenerator` | the generator's type | **Parameters** | Name | Type | Description | | ----------- | -------- | ---------------------------------- | | `generator` | `&var G` | where the bits come from | | `count` | `uint` | how many there are to choose among | **Returns**: an index in `[0, count)`, each equally likely ## `WeightedIndex<G>` ```rux pub func WeightedIndex<G: RandomGenerator>( generator: &var G, weights: float64[..] ) -> uint ``` An index chosen in proportion to `weights`. A weight of zero is never chosen; negative weights are treated as zero rather than subtracting from the total, since a negative probability has no meaning and silently reversing a comparison is worse than ignoring the entry. Weights that are all zero, or an empty slice, give the length — the same out-of-range answer [`ChooseIndex`](https://rux-lang.dev/docs/api/random/sampling#choose-index) gives for an empty collection. Runs in time proportional to the length, reading the weights twice: once to total them and once to select. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Random/Src/Sample.rux#L59){rel=""nofollow""} **Type parameters** | Name | Description | | -------------------- | -------------------- | | `G: RandomGenerator` | the generator's type | **Parameters** | Name | Type | Description | | ----------- | ------------- | ----------------------------------------------------------- | | `generator` | `&var G` | where the bits come from | | `weights` | `float64[..]` | the relative weight of each index; they need not sum to one | **Returns**: an index chosen in proportion to its weight # Uniform ranges Uniform integers and floats in a bounded range. ## `UniformBelow<G>` ```rux pub func UniformBelow<G: RandomGenerator>( generator: &var G, bound: uint64 ) -> uint64 ``` A uniform value in `[0, bound)`. A bound of zero has no values to choose from and gives zero, which is the only answer that is not a lie. Runs in constant expected time; the loop below runs more than once with probability under `bound / 2^64`. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Random/Src/Uniform.rux#L22){rel=""nofollow""} **Type parameters** | Name | Description | | -------------------- | -------------------- | | `G: RandomGenerator` | the generator's type | **Parameters** | Name | Type | Description | | ----------- | -------- | ------------------------- | | `generator` | `&var G` | where the bits come from | | `bound` | `uint64` | the exclusive upper bound | **Returns**: a value in `[0, bound)`, each equally likely and with no modulo bias ## `UniformInRange<G>` ```rux pub func UniformInRange<G: RandomGenerator>( generator: &var G, low: uint64, high: uint64 ) -> uint64 ``` A uniform value in `[low, high]`, both ends included. Inclusive because that is what a caller asking for a die roll or a random index into a known last element means. `low` above `high` is an empty range and gives `low`. The full range of the type is representable: a span of every value is a bound of 2^64, which does not fit in a `uint64`, and is handled as its own case rather than by an arithmetic accident. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Random/Src/Uniform.rux#L49){rel=""nofollow""} **Type parameters** | Name | Description | | -------------------- | -------------------- | | `G: RandomGenerator` | the generator's type | **Parameters** | Name | Type | Description | | ----------- | -------- | ------------------------- | | `generator` | `&var G` | where the bits come from | | `low` | `uint64` | the inclusive lower bound | | `high` | `uint64` | the exclusive upper bound | **Returns**: a value in `[low, high)`, each equally likely ## `UniformInSignedRange<G>` ```rux pub func UniformInSignedRange<G: RandomGenerator>( generator: &var G, low: int64, high: int64 ) -> int64 ``` A uniform signed value in `[low, high]`, both ends included. The span is computed in unsigned arithmetic, so a range crossing zero — or spanning the whole width, where the difference of the ends overflows a signed type — is ordinary rather than a special case. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Random/Src/Uniform.rux#L68){rel=""nofollow""} **Type parameters** | Name | Description | | -------------------- | -------------------- | | `G: RandomGenerator` | the generator's type | **Parameters** | Name | Type | Description | | ----------- | -------- | ------------------------- | | `generator` | `&var G` | where the bits come from | | `low` | `int64` | the inclusive lower bound | | `high` | `int64` | the exclusive upper bound | **Returns**: a value in `[low, high)`, each equally likely ## `UniformFloatInRange<G>` ```rux pub func UniformFloatInRange<G: RandomGenerator>( generator: &var G, low: float64, high: float64 ) -> float64 ``` A uniform `float64` in `[low, high)`. The interval is half-open at the top, matching [`NextFloat64`](https://rux-lang.dev/docs/api/random/random-generator#next-float64). A reversed pair gives `low`, and an interval so wide that its span overflows to an infinity gives values across the whole of it rather than a NaN. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Random/Src/Uniform.rux#L84){rel=""nofollow""} **Type parameters** | Name | Description | | -------------------- | -------------------- | | `G: RandomGenerator` | the generator's type | **Parameters** | Name | Type | Description | | ----------- | --------- | ------------------------- | | `generator` | `&var G` | where the bits come from | | `low` | `float64` | the inclusive lower bound | | `high` | `float64` | the exclusive upper bound | **Returns**: a value in `[low, high)` # Io Streams, console I/O, readers and writers. ## Installation Add `Io` to the `[Dependencies]` table of your package's `Rux.toml`: ```toml [Dependencies] Io = { Namespace = "Rux", Version = "0.1.0" } ``` Standard packages are declared by hand: the registry does not serve them, so `rux add Rux/Io` cannot add them. ## Dependencies - [`Allocator`](https://rux-lang.dev/docs/api/allocator) 0.1.0 - [`Core`](https://rux-lang.dev/docs/api/core) 0.1.0 - [`Format`](https://rux-lang.dev/docs/api/format) 0.1.0 - [`FreeBSD`](https://rux-lang.dev/docs/api/freebsd) 0.1.0 (FreeBSD only) - [`Linux`](https://rux-lang.dev/docs/api/linux) 0.1.0 (Linux only) - [`macOS`](https://rux-lang.dev/docs/api/macos) 0.1.0 (macOS only) - [`Memory`](https://rux-lang.dev/docs/api/memory) 0.1.0 - [`Text`](https://rux-lang.dev/docs/api/text) 0.1.0 - [`Windows`](https://rux-lang.dev/docs/api/windows) 0.1.0 (Windows only) ## Guide Streams, console I/O, readers and writers. Console access is written directly against each platform's own primitives, selected at compile time: the `write`/`read` syscalls on Linux, macOS, and the BSDs, and `WriteFile`/`ReadFile` on Windows. There is no C runtime in the path. ### What it provides | Function | Purpose | | --------------------------------------------------------------------------- | ------------------------------------------------ | | [`Print`](https://rux-lang.dev/docs/api/io/print) | Write a value to standard output | | [`PrintLine`](https://rux-lang.dev/docs/api/io/print-line) | Write a value followed by a newline | | [`ReadLine`](https://rux-lang.dev/docs/api/io/read-line) | Append one line from standard input | | [`ReadLineFrom`](https://rux-lang.dev/docs/api/io/read-line#read-line-from) | Append one line from any reader, byte by byte | | [`ReadExact`](https://rux-lang.dev/docs/api/io/reader#read-exact) | Fill a byte slice from any reader | | [`WriteAll`](https://rux-lang.dev/docs/api/io/writer#write-all) | Send a byte slice to any writer | | [`ReadTextLine`](https://rux-lang.dev/docs/api/io/read-line#read-text-line) | Append one validated line from a buffered reader | [`Print`](https://rux-lang.dev/docs/api/io/print) and [`PrintLine`](https://rux-lang.dev/docs/api/io/print-line) accept values implementing `Display` from [`Rux/Text`](https://github.com/rux-lang/Rux/blob/main/Packages/Io/../Text){rel=""nofollow""}, along with their primitive and text overloads. The primitive overloads cover every boolean width from `bool8` to `bool512`, the floats `float8`, `float16`, `float32` and `float64`, the integers up to 64 bits with `int` and `uint`, and every character width from `char8` to `char512`. `float80` and wider have no overload, because their text allocates: render one through [`Rux/Format`](https://github.com/rux-lang/Rux/blob/main/Packages/Io/../Format){rel=""nofollow""}'s `Float80` to `Float512` values with `FromValue` and `FormatWith`, passing the allocator. They return the failure of the write as an `IoError?` — `none` when everything was written — rather than a fallible, so a bare `PrintLine("ready");` statement needs no handling while a caller who cares writes `if PrintLine(report) is IoError { ... }`. Given arguments after it, the first text is a pattern: `PrintLine("{} of {}", done, total)` fills each `{}` or `{:spec}` placeholder from the next argument, and `{{` and `}}` write a literal brace. The pattern parameter is marked `#Format()`, so when it is a string literal the compiler counts its placeholders against the arguments, and `PrintLine("{} {}", 1)` is a compile error rather than a silent failure at run time. A pattern known only at run time that does not match reports `InvalidInput` through the returned `IoError?` and prints nothing. With no arguments the text is not a pattern at all: `PrintLine("{{}}")` writes `{{}}` verbatim, braces and all. Both line readers hold the same contract: a line feed ends a line, a carriage return immediately before it belongs to the ending, the last line needs no ending, and the line must be UTF-8. A line that is not is `InvalidText`, reported once the line has been consumed through its ending, so the next call starts on the next line. [`ReadLine`](https://rux-lang.dev/docs/api/io/read-line) and [`ReadLineFrom`](https://rux-lang.dev/docs/api/io/read-line#read-line-from) read one byte at a time and never take a byte past the line, which is right for standard input or any stream shared with whatever reads next; [`ReadTextLine`](https://rux-lang.dev/docs/api/io/read-line#read-text-line) reads through a [`BufferedReader`](https://rux-lang.dev/docs/api/io/buffered-reader) and also bounds the line's length. Every stream operation that can fail returns a native fallible with an [`IoError`](https://rux-lang.dev/docs/api/io/io-error) failure: `Read` succeeds with the number of bytes read, `Write` with the number taken, `Seek` with the new position, and `Flush`, [`ReadExact`](https://rux-lang.dev/docs/api/io/reader#read-exact), [`WriteAll`](https://rux-lang.dev/docs/api/io/writer#write-all), and the line readers with `()`. The end of a stream is the `EndOfStream` failure, which [`IsEnd`](https://rux-lang.dev/docs/api/io/io-error#is-end) recognizes, and [`IsTransient`](https://rux-lang.dev/docs/api/io/io-error#is-transient) names the interruptions worth retrying. An [`IoError`](https://rux-lang.dev/docs/api/io/io-error) renders through `{}` as its kind's words and the platform's code, as `not found (os error 2)`. ### Streams in memory [`ByteReader`](https://rux-lang.dev/docs/api/io/memory-stream#byte-reader) reads a slice of bytes the caller holds and [`ByteWriter`](https://rux-lang.dev/docs/api/io/memory-stream#byte-writer) gathers what is written into a block that grows as needed, so code written against [`Reader`](https://rux-lang.dev/docs/api/io/reader) and [`Writer`](https://rux-lang.dev/docs/api/io/writer) can run without a file or a socket. Both seek within what they hold: a seek back in a [`ByteWriter`](https://rux-lang.dev/docs/api/io/memory-stream#byte-writer) overwrites in place, and a seek past the end is refused with `InvalidInput`. A [`ByteReader`](https://rux-lang.dev/docs/api/io/memory-stream#byte-reader) ends with `EndOfStream` like any other stream. ### Text and streams `Display` writes into a `TextWriter` and a stream takes bytes, so something has to stand between them. [`ConsoleWriter`](https://rux-lang.dev/docs/api/io/console-writer) is that adapter over standard output and [`StreamWriter`](https://rux-lang.dev/docs/api/io/stream-writer) is it over any [`Writer`](https://rux-lang.dev/docs/api/io/writer) — a file, a buffered writer, a pipe — which is what lets a value describe itself anywhere other than standard output or memory: ```rux import Core::Failed; import Io::{ IoError, StandardOut, StreamWriter, WriteValueLine }; import Text::TextWriter; func Main() -> int { var out = StandardOut::Acquire(); let measurement: int32 = 42; // The adapter turns a stream into a text writer. It cannot return an I/O error through the text protocol, so // it keeps the first one it saw in `failure` — which is why that is checked afterwards rather than at the call. var failure: IoError? = none; var adapter = StreamWriter(out, @failure); let text: &var TextWriter = adapter; // The type argument is required: the function is generic over the value so that it can borrow it rather than // take ownership, and a generic bound is not inferred from an interface value. let written = WriteValueLine<int32>(text, measurement); if failure is IoError || Failed(written) { return 1; } return 0; } ``` Neither error type can hold the other's failures, so the crossing is made explicitly in both directions. [`FromIoError`](https://rux-lang.dev/docs/api/io/io-error#from-io-error) turns what a stream reported into what a formatter understands: success stays success and every failure becomes `WriterFailure`, which is all `FormatError` can say about a destination. That is lossy on purpose, and the adapter makes the loss good by recording the original [`IoError`](https://rux-lang.dev/docs/api/io/io-error) in an optional slot the caller holds, `none` until something fails — the formatter learns the one thing it can act on, and the caller learns exactly what happened. Once a failure is recorded the stream is not touched again, so a value part-way through rendering stops rather than writing into a destination that has already refused. [`ToIoError`](https://rux-lang.dev/docs/api/io/io-error#to-io-error) comes back the other way, and the distinction it preserves is the one that decides what to do next: a request that was wrong is `InvalidInput` and will be wrong again, while a destination that failed came back as an [`IoError`](https://rux-lang.dev/docs/api/io/io-error) in the first place. Bytes that were not text are `InvalidText`; a bounded destination that filled is `LimitExceeded`. Nothing is stuffed into [`IoError`](https://rux-lang.dev/docs/api/io/io-error)'s `raw`, which is `errno` or the Win32 code and is meant to be looked up; a caller who needs to know which formatting failure it was builds a writer and calls `Text::WriteValue` themselves. [`WriteValueLine`](https://rux-lang.dev/docs/api/io/print-line#write-value-line) and [`WriteFormatLine`](https://rux-lang.dev/docs/api/io/print-line#write-format-line) write a value or a pattern followed by a newline, and write the newline **only if** what came before it went out whole. A line is a value and its terminator together, so a value that could not be written must not be followed by one. Every [`PrintLine`](https://rux-lang.dev/docs/api/io/print-line) overload follows the same rule. [`WriteValueLine`](https://rux-lang.dev/docs/api/io/print-line#write-value-line) takes its value by bound rather than as an interface value, so the value is borrowed rather than given up: binding a move-only value to a `Display` transfers ownership of it, which would let such a value be written exactly once. Stream helpers borrow concrete implementations directly as `&var Reader` or `&var Writer` interface views, and a named stream passed straight into one of them borrows without any binding: `WriteAll(file, contents)?`. The borrow neither copies nor consumes the stream, and it ends at the call. [`BufferedReader`](https://rux-lang.dev/docs/api/io/buffered-reader) and [`BufferedWriter`](https://rux-lang.dev/docs/api/io/buffered-writer) must keep their streams after construction, so they store ordinary interface handles; a stream that cannot be stored that way — because binding it would move it — supplies a stored adapter of its own, such as `FileSystem::FileStream`, whose representation is private and whose lifetime contract is documented where it lives. [`BufferedReader::New`](https://rux-lang.dev/docs/api/io/buffered-reader#new) and [`BufferedWriter::New`](https://rux-lang.dev/docs/api/io/buffered-writer#new) fail with `Other` when their buffer cannot be allocated. Both buffered types prohibit copying, move with `<-`, and release their owned buffers through [`~BufferedReader`](https://rux-lang.dev/docs/api/io/buffered-reader#destructor) and [`~BufferedWriter`](https://rux-lang.dev/docs/api/io/buffered-writer#destructor). ### Example ```rux import Allocator::{ Allocator, SystemAllocator }; import Io::{ PrintLine, ReadLine }; import Text::StringBuilder; func Main() -> int { var system = SystemAllocator(); let allocator: Allocator = system; var name = StringBuilder(allocator); PrintLine("What is your name?"); ReadLine(name) catch { else => return 1 }; let text = name.IntoString(); PrintLine(text); return 0; } ``` ## Index ### Interfaces | Name | Summary | | --------------------------------------------------- | ------------------------------------- | | [`Reader`](https://rux-lang.dev/docs/api/io/reader) | Somewhere bytes come from. | | [`Writer`](https://rux-lang.dev/docs/api/io/writer) | Somewhere bytes go. | | [`Seeker`](https://rux-lang.dev/docs/api/io/seeker) | A stream whose position can be moved. | ### Types | Name | Summary | | -------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------ | | [`Endian`](https://rux-lang.dev/docs/api/io/binary#endian) | A byte order: which end of a multi-byte value comes first. | | [`BufferedReader`](https://rux-lang.dev/docs/api/io/buffered-reader) | A reader that fills a buffer in large reads and serves small ones from it. | | [`BufferedWriter`](https://rux-lang.dev/docs/api/io/buffered-writer) | A writer that gathers small writes into a buffer and sends it in one piece. | | [`IoErrorKind`](https://rux-lang.dev/docs/api/io/io-error#io-error-kind) | What an I/O operation reported. | | [`IoError`](https://rux-lang.dev/docs/api/io/io-error) | A structured I/O failure: the shared meaning, and the platform's own code beside it. | | [`ByteReader`](https://rux-lang.dev/docs/api/io/memory-stream#byte-reader) | A reader of a slice of bytes, from its start. | | [`ByteWriter`](https://rux-lang.dev/docs/api/io/memory-stream#byte-writer) | A writer that keeps what is written in a growing block of memory. | | [`StandardIn`](https://rux-lang.dev/docs/api/io/standard-in) | Standard input, with the console-versus-redirection question answered at acquisition. | | [`StandardOut`](https://rux-lang.dev/docs/api/io/standard-out) | Standard output: a byte [`Writer`](https://rux-lang.dev/docs/api/io/writer) whose encoding matches where the bytes land. | | [`StandardError`](https://rux-lang.dev/docs/api/io/standard-error) | Standard error: the same contract as standard output, on the stream reports belong to. | | [`SeekFrom`](https://rux-lang.dev/docs/api/io/seeker#seek-from) | Where a seek starts counting from. | | [`ConsoleWriter`](https://rux-lang.dev/docs/api/io/console-writer) | A `TextWriter` over standard output that records the stream's failure where the caller can see it. | | [`StreamWriter`](https://rux-lang.dev/docs/api/io/stream-writer) | A `TextWriter` over any stream, recording the stream's failure where the caller can see it. | ### Functions | Name | Summary | | ----------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------- | | [`ReadWord`](https://rux-lang.dev/docs/api/io/binary#read-word) | Reads a `width`-byte unsigned word in the given order, into the low bytes of the result. | | [`WriteWord`](https://rux-lang.dev/docs/api/io/binary#write-word) | Writes the low `width` bytes of `value` in the given order. | | [`ReadUint8`](https://rux-lang.dev/docs/api/io/binary#read-uint8) | Reads a `uint8` in the given order. | | [`WriteUint8`](https://rux-lang.dev/docs/api/io/binary#write-uint8) | Writes a `uint8` in the given order. | | [`ReadInt8`](https://rux-lang.dev/docs/api/io/binary#read-int8) | Reads an `int8`: the unsigned bytes, reinterpreted in two's complement. | | [`WriteInt8`](https://rux-lang.dev/docs/api/io/binary#write-int8) | Writes an `int8`: its two's-complement bytes, unchanged. | | [`ReadUint16`](https://rux-lang.dev/docs/api/io/binary#read-uint16) | Reads a `uint16` in the given order. | | [`WriteUint16`](https://rux-lang.dev/docs/api/io/binary#write-uint16) | Writes a `uint16` in the given order. | | [`ReadInt16`](https://rux-lang.dev/docs/api/io/binary#read-int16) | Reads an `int16`: the unsigned bytes, reinterpreted in two's complement. | | [`WriteInt16`](https://rux-lang.dev/docs/api/io/binary#write-int16) | Writes an `int16`: its two's-complement bytes, unchanged. | | [`ReadUint32`](https://rux-lang.dev/docs/api/io/binary#read-uint32) | Reads a `uint32` in the given order. | | [`WriteUint32`](https://rux-lang.dev/docs/api/io/binary#write-uint32) | Writes a `uint32` in the given order. | | [`ReadInt32`](https://rux-lang.dev/docs/api/io/binary#read-int32) | Reads an `int32`: the unsigned bytes, reinterpreted in two's complement. | | [`WriteInt32`](https://rux-lang.dev/docs/api/io/binary#write-int32) | Writes an `int32`: its two's-complement bytes, unchanged. | | [`ReadUint64`](https://rux-lang.dev/docs/api/io/binary#read-uint64) | Reads a `uint64` in the given order. | | [`WriteUint64`](https://rux-lang.dev/docs/api/io/binary#write-uint64) | Writes a `uint64` in the given order. | | [`ReadInt64`](https://rux-lang.dev/docs/api/io/binary#read-int64) | Reads an `int64`: the unsigned bytes, reinterpreted in two's complement. | | [`WriteInt64`](https://rux-lang.dev/docs/api/io/binary#write-int64) | Writes an `int64`: its two's-complement bytes, unchanged. | | [`ReadUint128`](https://rux-lang.dev/docs/api/io/binary#read-uint128) | Reads a `uint128` in the given order. | | [`WriteUint128`](https://rux-lang.dev/docs/api/io/binary#write-uint128) | Writes a `uint128` in the given order. | | [`ReadInt128`](https://rux-lang.dev/docs/api/io/binary#read-int128) | Reads an `int128`: the unsigned bytes, reinterpreted in two's complement. | | [`WriteInt128`](https://rux-lang.dev/docs/api/io/binary#write-int128) | Writes an `int128`: its two's-complement bytes, unchanged. | | [`ReadUint256`](https://rux-lang.dev/docs/api/io/binary#read-uint256) | Reads a `uint256` in the given order. | | [`WriteUint256`](https://rux-lang.dev/docs/api/io/binary#write-uint256) | Writes a `uint256` in the given order. | | [`ReadInt256`](https://rux-lang.dev/docs/api/io/binary#read-int256) | Reads an `int256`: the unsigned bytes, reinterpreted in two's complement. | | [`WriteInt256`](https://rux-lang.dev/docs/api/io/binary#write-int256) | Writes an `int256`: its two's-complement bytes, unchanged. | | [`ReadUint512`](https://rux-lang.dev/docs/api/io/binary#read-uint512) | Reads a `uint512` in the given order. | | [`WriteUint512`](https://rux-lang.dev/docs/api/io/binary#write-uint512) | Writes a `uint512` in the given order. | | [`ReadInt512`](https://rux-lang.dev/docs/api/io/binary#read-int512) | Reads an `int512`: the unsigned bytes, reinterpreted in two's complement. | | [`WriteInt512`](https://rux-lang.dev/docs/api/io/binary#write-int512) | Writes an `int512`: its two's-complement bytes, unchanged. | | [`ReadFloat32`](https://rux-lang.dev/docs/api/io/binary#read-float32) | Reads a `float32` as the IEEE 754 bit pattern of its width. | | [`WriteFloat32`](https://rux-lang.dev/docs/api/io/binary#write-float32) | Writes a `float32` as the IEEE 754 bit pattern of its width. | | [`ReadFloat64`](https://rux-lang.dev/docs/api/io/binary#read-float64) | Reads a `float64` as the IEEE 754 bit pattern of its width. | | [`WriteFloat64`](https://rux-lang.dev/docs/api/io/binary#write-float64) | Writes a `float64` as the IEEE 754 bit pattern of its width. | | [`PrintValue`](https://rux-lang.dev/docs/api/io/print#print-value) | Writes a value's text to standard output. | | [`PrintValueLine`](https://rux-lang.dev/docs/api/io/print-line#print-value-line) | Writes a value's text to standard output, then a newline. | | [`Print`](https://rux-lang.dev/docs/api/io/print) | Writes a value's text to standard output. | | [`PrintLine`](https://rux-lang.dev/docs/api/io/print-line) | Writes a value's text to standard output, then a newline. | | [`ReadLine`](https://rux-lang.dev/docs/api/io/read-line) | Appends the next line of standard input to `builder`, without its ending. | | [`ReadLineFrom`](https://rux-lang.dev/docs/api/io/read-line#read-line-from) | Appends the next line of `reader` to `builder`, without its ending, reading one byte at a time. | | [`ReadExact`](https://rux-lang.dev/docs/api/io/reader#read-exact) | Fills all of `into`, looping over partial reads, or says why it could not. | | [`WriteAll`](https://rux-lang.dev/docs/api/io/writer#write-all) | Writes all of `bytes`, looping over partial writes, or says why it could not. | | [`FromIoError`](https://rux-lang.dev/docs/api/io/io-error#from-io-error) | Turns what a stream reported into what a formatter understands. | | [`ToIoError`](https://rux-lang.dev/docs/api/io/io-error#to-io-error) | Turns a formatting failure into something a stream's caller can act on. | | [`WriteValueLine<T>`](https://rux-lang.dev/docs/api/io/print-line#write-value-line) | Writes a value's text, then a newline, and writes the newline only if the value went out whole. | | [`WriteFormatLine`](https://rux-lang.dev/docs/api/io/print-line#write-format-line) | Writes `format` with each `{}` replaced by the next argument, then a newline, on the same rule. | | [`ReadTextLine`](https://rux-lang.dev/docs/api/io/read-line#read-text-line) | Appends the next line of `reader` to `builder`, without its ending. | ### Constants | Name | Summary | | --------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------- | | [`DefaultBufferCapacity`](https://rux-lang.dev/docs/api/io/buffered-reader#default-buffer-capacity) | The room a buffered stream takes when the caller expresses no preference. | | [`ZeroProgressLimit`](https://rux-lang.dev/docs/api/io/reader#zero-progress-limit) | How many consecutive zero-progress rounds the looping helpers tolerate before refusing. | # Reader Somewhere bytes come from. ```rux pub interface Reader { func Read( self: &var Self, into: var char8[..] ) -> uint ! IoError; } ``` ## Requirements ### `Read` ```rux func Read( self: &var Self, into: var char8[..] ) -> uint ! IoError ``` Fills what it can of `into` and succeeds with how much. A success of zero does not happen for a non-empty buffer: the end of the stream is the `EndOfStream` failure, so a caller never mistakes silence for data. | Name | Type | Description | | ------ | --------------- | ------------------ | | `into` | `var char8[..]` | receives the bytes | **Returns**: how many bytes were read, which may be fewer than `into` holds; [`IsEnd`](https://rux-lang.dev/docs/api/io/io-error#is-end) at the end of the stream [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Io/Src/Stream.rux#L22){rel=""nofollow""} ## Implementations | Type | Summary | | -------------------------------------------------------------------------- | ------------------------------------------------------------------------------------- | | [`ByteReader`](https://rux-lang.dev/docs/api/io/memory-stream#byte-reader) | A reader of a slice of bytes, from its start. | | [`StandardIn`](https://rux-lang.dev/docs/api/io/standard-in) | Standard input, with the console-versus-redirection question answered at acquisition. | ## Related ### `ZeroProgressLimit` ```rux pub const ZeroProgressLimit: uint = 3; ``` How many consecutive zero-progress rounds the looping helpers tolerate before refusing. A transient report is retried without counting; this counts only rounds where the stream reported success and moved nothing, which is a stream that will never finish the job. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Io/Src/Stream.rux#L66){rel=""nofollow""} ### `ReadExact` ```rux pub func ReadExact( reader: &var Reader, into: var char8[..] ) -> ! IoError ``` Fills all of `into`, looping over partial reads, or says why it could not. Transient reports are retried; the end of the stream before the buffer fills is `EndOfStream` with the buffer partly written — how much is not reported, because a caller who needs the count reads incrementally. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Io/Src/Stream.rux#L75){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | --------------- | ------------------------- | | `reader` | `&var Reader` | where the bytes come from | | `into` | `var char8[..]` | receives the bytes | **Returns**: success only when `into` was filled completely; [`IsEnd`](https://rux-lang.dev/docs/api/io/io-error#is-end) when the stream ran out first # Seeker A stream whose position can be moved. ```rux pub interface Seeker { func Seek( self: &var Self, origin: SeekFrom, offset: int64 ) -> uint64 ! IoError; } ``` ## Requirements ### `Seek` ```rux func Seek( self: &var Self, origin: SeekFrom, offset: int64 ) -> uint64 ! IoError ``` Moves the position `offset` bytes from `origin` and succeeds with where it landed. | Name | Type | Description | | -------- | ---------- | -------------------------------------- | | `origin` | `SeekFrom` | where the offset is measured from | | `offset` | `int64` | how far to move, which may be negative | **Returns**: the resulting offset from the start [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Io/Src/Stream.rux#L59){rel=""nofollow""} ## Implementations | Type | Summary | | -------------------------------------------------------------------------- | ----------------------------------------------------------------- | | [`ByteReader`](https://rux-lang.dev/docs/api/io/memory-stream#byte-reader) | A reader of a slice of bytes, from its start. | | [`ByteWriter`](https://rux-lang.dev/docs/api/io/memory-stream#byte-writer) | A writer that keeps what is written in a growing block of memory. | ## Related ### `SeekFrom` ```rux pub enum SeekFrom: int32 { Start = 0, Current = 1, End = 2 } ``` Where a seek starts counting from. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Io/Src/Stream.rux#L42){rel=""nofollow""} **Cases** | Name | Value | Description | | --------- | ----- | --------------------------------------------------------- | | `Start` | `0` | The start of the stream; the offset must not be negative. | | `Current` | `1` | The current position. | | `End` | `2` | The end of the stream. | # Writer Somewhere bytes go. ```rux pub interface Writer { func Write( self: &var Self, bytes: char8[..] ) -> uint ! IoError; func Flush(self: &var Self) -> ! IoError; } ``` ## Requirements ### `Write` ```rux func Write( self: &var Self, bytes: char8[..] ) -> uint ! IoError ``` Takes what it can of `bytes` and succeeds with how much. | Name | Type | Description | | ------- | ----------- | ------------------ | | `bytes` | `char8[..]` | the bytes to write | **Returns**: how many bytes were taken, which may be fewer than offered [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Io/Src/Stream.rux#L32){rel=""nofollow""} ### `Flush` ```rux func Flush(self: &var Self) -> ! IoError ``` Pushes whatever is held toward the destination. **Returns**: success when everything held reached the destination [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Io/Src/Stream.rux#L37){rel=""nofollow""} ## Implementations | Type | Summary | | -------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------ | | [`ByteWriter`](https://rux-lang.dev/docs/api/io/memory-stream#byte-writer) | A writer that keeps what is written in a growing block of memory. | | [`StandardOut`](https://rux-lang.dev/docs/api/io/standard-out) | Standard output: a byte [`Writer`](https://rux-lang.dev/docs/api/io/writer) whose encoding matches where the bytes land. | | [`StandardError`](https://rux-lang.dev/docs/api/io/standard-error) | Standard error: the same contract as standard output, on the stream reports belong to. | ## Related ### `WriteAll` ```rux pub func WriteAll( writer: &var Writer, bytes: char8[..] ) -> ! IoError ``` Writes all of `bytes`, looping over partial writes, or says why it could not. A writer that accepts nothing while reporting success is refused with `WriteZero` after a few rounds: a loop that spins on it would hang the caller on a stream that will never take the rest. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Io/Src/Stream.rux#L98){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | ------------- | ------------------ | | `writer` | `&var Writer` | the destination | | `bytes` | `char8[..]` | the bytes to write | **Returns**: success only when every byte was written, looping over short writes # BufferedReader A reader that fills a buffer in large reads and serves small ones from it. ```rux pub struct BufferedReader { // private fields } ``` Move-only: it owns its buffer. The reader it wraps is borrowed through the interface value and must outlive it. ## Associated functions ### `New` ```rux pub func New( allocator: Allocator, source: Reader, capacity: uint ) -> BufferedReader ! IoError ``` A buffered reader over `source` with `capacity` bytes of buffer. | Name | Type | Description | | ----------- | ----------- | ------------------------------- | | `allocator` | `Allocator` | where the storage comes from | | `source` | `Reader` | where the bytes come from | | `capacity` | `uint` | how many bytes the buffer holds | **Returns**: the buffered stream; `Other` when the allocator refused the buffer [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Io/Src/Buffered.rux#L49){rel=""nofollow""} ## Methods ### `Available` ```rux pub func Available(self: &BufferedReader) -> uint ``` How many buffered bytes wait unread. **Returns**: how many bytes are already buffered and can be taken without a read [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Io/Src/Buffered.rux#L70){rel=""nofollow""} ### `Buffered` ```rux pub func Buffered(self: &BufferedReader) -> char8[..] ``` The unread bytes, borrowed, without consuming them. What line reading is built from: look, decide, then [`Consume`](https://rux-lang.dev/docs/api/io/buffered-reader#consume) what was used. **Returns**: the buffered bytes, borrowed and valid until the next fill [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Io/Src/Buffered.rux#L78){rel=""nofollow""} ### `Consume` ```rux pub func Consume(self: &var BufferedReader, count: uint) ``` Marks `count` buffered bytes as read. | Name | Type | Description | | ------- | ------ | ------------------------- | | `count` | `uint` | how many bytes to consume | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Io/Src/Buffered.rux#L85){rel=""nofollow""} ### `Fill` ```rux pub func Fill(self: &var BufferedReader) -> ! IoError ``` Refills an empty buffer from the source, retrying interruptions. Reports what the source reported; `EndOfStream` when the source is done. A source that reports success while handing over nothing breaks the [`Reader`](https://rux-lang.dev/docs/api/io/reader) contract, and is reported as the end rather than looped on. **Returns**: success when at least one byte is buffered; [`IsEnd`](https://rux-lang.dev/docs/api/io/io-error#is-end) at the end of the source [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Io/Src/Buffered.rux#L94){rel=""nofollow""} ### `Read` ```rux pub func Read( self: &var BufferedReader, into: var char8[..] ) -> uint ! IoError ``` Fills what it can of `into`: from the buffer while it has bytes, straight from the source for a request already larger than the whole buffer. | Name | Type | Description | | ------ | --------------- | ------------------ | | `into` | `var char8[..]` | receives the bytes | **Returns**: how many bytes were read; [`IsEnd`](https://rux-lang.dev/docs/api/io/io-error#is-end) at the end of input [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Io/Src/Buffered.rux#L115){rel=""nofollow""} ### `Release` ```rux pub func Release(self: &var BufferedReader) ``` Gives the buffer back. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Io/Src/Buffered.rux#L140){rel=""nofollow""} ## Destructor ```rux func ~BufferedReader(self: &var BufferedReader) ``` Gives the buffer back. Unread buffered bytes are abandoned, which loses nothing anybody asked for. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Io/Src/Buffered.rux#L154){rel=""nofollow""} ## Related ### `DefaultBufferCapacity` ```rux pub const DefaultBufferCapacity: uint = 8192; ``` The room a buffered stream takes when the caller expresses no preference. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Io/Src/Buffered.rux#L19){rel=""nofollow""} # BufferedWriter A writer that gathers small writes into a buffer and sends it in one piece. ```rux pub struct BufferedWriter { // private fields } ``` Move-only: it owns its buffer. Its destructor flushes as a safety net and discards the outcome, because a destructor has nowhere to report; the explicit [`Flush`](https://rux-lang.dev/docs/api/io/buffered-writer#flush) is where errors are seen, and the caller who cares calls it before letting go. ## Associated functions ### `New` ```rux pub func New( allocator: Allocator, sink: Writer, capacity: uint ) -> BufferedWriter ! IoError ``` A buffered writer over `sink` with `capacity` bytes of buffer. | Name | Type | Description | | ----------- | ----------- | ------------------------------- | | `allocator` | `Allocator` | where the storage comes from | | `sink` | `Writer` | where the bytes go | | `capacity` | `uint` | how many bytes the buffer holds | **Returns**: the buffered stream; `Other` when the allocator refused the buffer [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Io/Src/Buffered.rux#L187){rel=""nofollow""} ## Methods ### `Pending` ```rux pub func Pending(self: &BufferedWriter) -> uint ``` How many bytes wait unsent. **Returns**: how many bytes are written but not yet flushed [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Io/Src/Buffered.rux#L201){rel=""nofollow""} ### `Flush` ```rux pub func Flush(self: &var BufferedWriter) -> ! IoError ``` Sends everything gathered, then asks the sink to flush too. **Returns**: success when everything buffered reached the sink [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Io/Src/Buffered.rux#L208){rel=""nofollow""} ### `Write` ```rux pub func Write( self: &var BufferedWriter, bytes: char8[..] ) -> uint ! IoError ``` Takes `bytes`: into the buffer while they fit, around it in one piece when they never would. | Name | Type | Description | | ------- | ----------- | ------------------ | | `bytes` | `char8[..]` | the bytes to write | **Returns**: how many bytes were taken, which is all of them [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Io/Src/Buffered.rux#L225){rel=""nofollow""} ### `Abandon` ```rux pub func Abandon(self: &var BufferedWriter) ``` Gives the buffer back without sending what it holds. For the caller who has decided the bytes must not go — the one case where losing them is the point. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Io/Src/Buffered.rux#L244){rel=""nofollow""} ## Destructor ```rux func ~BufferedWriter(self: &var BufferedWriter) ``` Flushes as a safety net — the outcome has nowhere to go, so a caller who cares flushed already — then gives the buffer back. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Io/Src/Buffered.rux#L259){rel=""nofollow""} # ConsoleWriter A `TextWriter` over standard output that records the stream's failure where the caller can see it. ```rux pub struct ConsoleWriter { // private fields } ``` The protocol has one case for a destination failing, `WriterFailure`, and deliberately no room for the details: Text has no vocabulary for a broken pipe and does not pretend to. So this adapter keeps both halves. It reports `WriterFailure` to the formatter, which stops the write, and records the original [`IoError`](https://rux-lang.dev/docs/api/io/io-error) in the slot it was built over, which is what the caller reads afterwards. Nothing about the stream failure is lost, and nothing about it leaks into a package that could not interpret it. The slot starts as `none`, and holds the failure once there is one. The slot must outlive the writer. It is a stored address, so nothing here tracks that. ## Constructors ### `ConsoleWriter` ```rux pub func ConsoleWriter(failure: *var IoError?) -> ConsoleWriter ``` A writer over standard output, recording into `failure`. The slot is read before every write as well as written on failure, so a writer built over a slot that already holds a failure writes nothing at all. | Name | Type | Description | | --------- | --------------- | --------------------------------------------------------------------- | | `failure` | `*var IoError?` | where the first stream failure is recorded, `none` until there is one | **Returns**: a writer over standard output [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Io/Src/TextBoundary.rux#L92){rel=""nofollow""} ## Implements TextWriter `ConsoleWriter` conforms to `TextWriter`. ### `Write` ```rux pub func Write( self: &var ConsoleWriter, bytes: char8[..] ) -> ! FormatError ``` Writes `bytes` to standard output. Reports `WriterFailure` when the stream refuses, having recorded the original [`IoError`](https://rux-lang.dev/docs/api/io/io-error) in the slot. Once a failure has been recorded every later write is refused without touching the stream, so a value that is part-way through rendering does not go on writing into a handle that has already failed, and a trailing newline is not emitted after a failed line. This is the only case this writer can produce: the bytes are not revalidated, and standard output is not a bounded destination. | Name | Type | Description | | ------- | ----------- | ---------------------- | | `bytes` | `char8[..]` | the UTF-8 run to write | **Returns**: success when the stream accepted the whole run [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Io/Src/TextBoundary.rux#L107){rel=""nofollow""} # IoError A structured I/O failure: the shared meaning, and the platform's own code beside it. ```rux pub struct IoError { pub kind: IoErrorKind; pub raw: int32; } ``` `Copy`. The `raw` field is `errno` on the Unix systems and the Win32 error code on Windows, kept because translation loses detail and the detail is sometimes the diagnosis. ## Fields | Name | Type | Description | | ------ | ------------- | ------------------------------------------------- | | `kind` | `IoErrorKind` | The meaning every platform shares. | | `raw` | `int32` | The platform's own code, zero where none applies. | ## Associated functions ### `Of` ```rux pub func Of(kind: IoErrorKind) -> IoError ``` A failure of `kind` with no platform code. | Name | Type | Description | | ------ | ------------- | ----------------------------- | | `kind` | `IoErrorKind` | which kind of failure this is | **Returns**: an error of that kind, carrying no platform value [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Io/Src/IoError.rux#L81){rel=""nofollow""} ## Methods ### `IsEnd` ```rux pub func IsEnd(self: &IoError) -> bool ``` Whether the stream ended, which is the one report that is not a failure. **Returns**: whether the stream ended, which is not a failure [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Io/Src/IoError.rux#L88){rel=""nofollow""} ### `IsTransient` ```rux pub func IsTransient(self: &IoError) -> bool ``` Whether going again is the right response: an interruption or a would-block. **Returns**: whether trying again could succeed [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Io/Src/IoError.rux#L95){rel=""nofollow""} ## Implements Display `IoError` conforms to `Display`. ### `WriteDisplay` ```rux pub func WriteDisplay( self: &IoError, writer: &var TextWriter, spec: FormatSpec ) -> ! FormatError ``` Writes the kind as lower-case words, and the platform's code after them when there is one, as `not found (os error 2)`, under the placeholder's width, fill and alignment. No style is understood. Reports whatever the writer reported, and `UnsupportedRequest` for a style. | Name | Type | Description | | -------- | ----------------- | ------------------------------ | | `writer` | `&var TextWriter` | the destination | | `spec` | `FormatSpec` | what the placeholder asked for | **Returns**: success when the whole text was accepted [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Io/Src/IoError.rux#L151){rel=""nofollow""} ## Related ### `IoErrorKind` ```rux pub enum IoErrorKind: int32 { EndOfStream = 1, NotFound = 2, PermissionDenied = 3, AlreadyExists = 4, IsDirectory = 5, NotDirectory = 6, StorageFull = 7, Interrupted = 8, WouldBlock = 9, InvalidHandle = 10, InvalidInput = 11, TimedOut = 12, WriteZero = 13, InvalidText = 15, LimitExceeded = 16, ConnectionRefused = 17, ConnectionReset = 18, ConnectionAborted = 19, NotConnected = 20, AddressInUse = 21, AddressUnavailable = 22, Unreachable = 23, BrokenPipe = 24, Other = 14 } ``` What an I/O operation reported. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Io/Src/IoError.rux#L14){rel=""nofollow""} **Cases** | Name | Value | Description | | -------------------- | ----- | --------------------------------------------------------------------------------------- | | `EndOfStream` | `1` | The stream ended: not a failure, but it arrives where failures do. | | `NotFound` | `2` | The named thing does not exist. | | `PermissionDenied` | `3` | The system refused on rights. | | `AlreadyExists` | `4` | The named thing exists where something new was to be made. | | `IsDirectory` | `5` | A directory stood where a file was expected. | | `NotDirectory` | `6` | A file stood where a directory was expected. | | `StorageFull` | `7` | The device has no room left. | | `Interrupted` | `8` | The operation was interrupted and may simply be retried. | | `WouldBlock` | `9` | The operation would block a stream opened not to. | | `InvalidHandle` | `10` | A handle that is not open, or not open for this. | | `InvalidInput` | `11` | An argument the system rejected. | | `TimedOut` | `12` | The operation ran out of time. | | `WriteZero` | `13` | A write reported fewer bytes than asked and cannot continue. | | `InvalidText` | `15` | Bytes that were required to be UTF-8 text and are not. | | `LimitExceeded` | `16` | A bounded operation met its bound before its end. | | `ConnectionRefused` | `17` | The other end refused the connection: nothing listens there. | | `ConnectionReset` | `18` | The other end reset the connection. | | `ConnectionAborted` | `19` | The connection was aborted on this side. | | `NotConnected` | `20` | The socket is not connected. | | `AddressInUse` | `21` | The local address is already in use. | | `AddressUnavailable` | `22` | The address is not one this machine has, or cannot be reached from it. | | `Unreachable` | `23` | No route leads to the network or host. | | `BrokenPipe` | `24` | The other end closed the connection, so nothing more can be written to it. | | `Other` | `14` | Something the platform reported that has no shared meaning; the raw code is the detail. | **Implements Display** `IoErrorKind` conforms to `Display`. #### `WriteDisplay` ```rux pub func WriteDisplay( self: &IoErrorKind, writer: &var TextWriter, spec: FormatSpec ) -> ! FormatError ``` Writes the kind as lower-case words, such as `not found`, under the placeholder's width, fill and alignment. No style is understood. Reports whatever the writer reported, and `UnsupportedRequest` for a style. | Name | Type | Description | | -------- | ----------------- | ------------------------------ | | `writer` | `&var TextWriter` | the destination | | `spec` | `FormatSpec` | what the placeholder asked for | **Returns**: success when the whole text was accepted [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Io/Src/IoError.rux#L137){rel=""nofollow""} ### `FromIoError` ```rux pub func FromIoError(outcome: ! IoError) -> ! FormatError ``` Turns what a stream reported into what a formatter understands. Success becomes the formatter's success value; every failure becomes `WriterFailure`, which is the only thing `FormatError` can say about a destination. The details do not travel this way — an adapter records the original [`IoError`](https://rux-lang.dev/docs/api/io/io-error) where its caller can read it, which is what keeps the loss from being a loss. The end of a stream is a failure here. Nothing is being read, so a write that reports it is a destination that cannot take the bytes, whatever it calls that. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Io/Src/TextBoundary.rux#L36){rel=""nofollow""} **Parameters** | Name | Type | Description | | --------- | ----------- | ------------------------ | | `outcome` | `! IoError` | what the stream reported | **Returns**: success for a success, and `WriterFailure` for any failure ### `ToIoError` ```rux pub func ToIoError(error: &FormatError) -> IoError ``` Turns a formatting failure into something a stream's caller can act on. The distinction that survives is the one worth having: a request that was wrong is `InvalidInput` and will be wrong again, while a destination that failed came back as an [`IoError`](https://rux-lang.dev/docs/api/io/io-error) in the first place and never reaches here. Bytes that were not text are `InvalidText`; a bounded destination that filled is `LimitExceeded`. `WriterFailure` should not arrive: an adapter records the stream's own error and its caller reports that instead. It maps to `Other` rather than being ignored, so an adapter that forgets to keep the original is visibly wrong rather than quietly reporting success. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Io/Src/TextBoundary.rux#L50){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------- | -------------- | ----------------------------------- | | `error` | `&FormatError` | the formatting failure to translate | **Returns**: the closest I/O meaning, with no platform code, since none applies # Memory streams A reader and a writer over bytes in memory, with seeking. ## `ByteReader` ```rux pub struct ByteReader { // private fields } ``` A reader of a slice of bytes, from its start. `Copy`. Borrows the bytes, which must outlive it. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Io/Src/MemoryStream.rux#L12){rel=""nofollow""} **Associated functions** ### `New` ```rux pub func New(bytes: char8[..]) -> ByteReader ``` A reader of `bytes`, at their start. | Name | Type | Description | | ------- | ----------- | ------------------------------------------------ | | `bytes` | `char8[..]` | the bytes to read, which must outlive the reader | **Returns**: the reader [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Io/Src/MemoryStream.rux#L22){rel=""nofollow""} **Methods** ### `Position` ```rux pub func Position(self: &ByteReader) -> uint ``` How many bytes have been read or skipped. **Returns**: the position [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Io/Src/MemoryStream.rux#L29){rel=""nofollow""} ### `Remaining` ```rux pub func Remaining(self: &ByteReader) -> char8[..] ``` The bytes not yet read. **Returns**: them [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Io/Src/MemoryStream.rux#L36){rel=""nofollow""} **Implements Reader** `ByteReader` conforms to [`Reader`](https://rux-lang.dev/docs/api/io/reader). ### `Read` ```rux pub func Read( self: &var ByteReader, into: var char8[..] ) -> uint ! IoError ``` Copies the next bytes into `into`, as many as fit. | Name | Type | Description | | ------ | --------------- | ------------------ | | `into` | `var char8[..]` | where the bytes go | **Returns**: how many were copied, or fails with `EndOfStream` once every byte has been read [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Io/Src/MemoryStream.rux#L46){rel=""nofollow""} **Implements Seeker** `ByteReader` conforms to [`Seeker`](https://rux-lang.dev/docs/api/io/seeker). ### `Seek` ```rux pub func Seek( self: &var ByteReader, origin: SeekFrom, offset: int64 ) -> uint64 ! IoError ``` Moves the position, anywhere from the start to the end of the bytes. | Name | Type | Description | | -------- | ---------- | ------------------------------ | | `origin` | `SeekFrom` | what `offset` counts from | | `offset` | `int64` | how far, which may be negative | **Returns**: the new position, or fails with `InvalidInput` for one before the start or past the end [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Io/Src/MemoryStream.rux#L77){rel=""nofollow""} ## `ByteWriter` ```rux pub struct ByteWriter { // private fields } ``` A writer that keeps what is written in a growing block of memory. Not copied. Writing at a position before the end, after a seek, overwrites what is there and extends past it. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Io/Src/MemoryStream.rux#L88){rel=""nofollow""} **Associated functions** ### `New` ```rux pub func New(allocator: Allocator) -> ByteWriter ``` An empty writer that takes its storage from `allocator` as it grows. | Name | Type | Description | | ----------- | ----------- | ---------------------------- | | `allocator` | `Allocator` | where the storage comes from | **Returns**: the writer [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Io/Src/MemoryStream.rux#L103){rel=""nofollow""} **Methods** ### `Bytes` ```rux pub func Bytes(self: &ByteWriter) -> char8[..] ``` Everything written so far. The view lasts until the next write, [`Clear`](https://rux-lang.dev/docs/api/io/memory-stream#byte-writer-clear) or [`Release`](https://rux-lang.dev/docs/api/io/memory-stream#byte-writer-release). **Returns**: the bytes [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Io/Src/MemoryStream.rux#L110){rel=""nofollow""} ### `Length` ```rux pub func Length(self: &ByteWriter) -> uint ``` How many bytes have been written. **Returns**: the length [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Io/Src/MemoryStream.rux#L118){rel=""nofollow""} ### `Clear` ```rux pub func Clear(self: &var ByteWriter) ``` Forgets what was written, keeping the storage for what comes next. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Io/Src/MemoryStream.rux#L124){rel=""nofollow""} ### `Release` ```rux pub func Release(self: &var ByteWriter) ``` Gives the storage back and empties the writer. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Io/Src/MemoryStream.rux#L131){rel=""nofollow""} **Implements Writer** `ByteWriter` conforms to [`Writer`](https://rux-lang.dev/docs/api/io/writer). ### `Write` ```rux pub func Write( self: &var ByteWriter, bytes: char8[..] ) -> uint ! IoError ``` Writes all of `bytes` at the position, growing the storage as needed. | Name | Type | Description | | ------- | ----------- | ------------------ | | `bytes` | `char8[..]` | the bytes to write | **Returns**: how many were written, which is all of them, or fails with `LimitExceeded` when storage runs out [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Io/Src/MemoryStream.rux#L176){rel=""nofollow""} ### `Flush` ```rux pub func Flush(self: &var ByteWriter) -> ! IoError ``` Does nothing: the bytes are already where they go. **Returns**: nothing [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Io/Src/MemoryStream.rux#L189){rel=""nofollow""} **Implements Seeker** `ByteWriter` conforms to [`Seeker`](https://rux-lang.dev/docs/api/io/seeker). ### `Seek` ```rux pub func Seek( self: &var ByteWriter, origin: SeekFrom, offset: int64 ) -> uint64 ! IoError ``` Moves the position at which the next write lands, anywhere from the start to the end of what was written. | Name | Type | Description | | -------- | ---------- | ------------------------------ | | `origin` | `SeekFrom` | what `offset` counts from | | `offset` | `int64` | how far, which may be negative | **Returns**: the new position, or fails with `InvalidInput` for one before the start or past the end [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Io/Src/MemoryStream.rux#L198){rel=""nofollow""} **Destructor** ### `~ByteWriter` ```rux func ~ByteWriter(self: &var ByteWriter) ``` [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Io/Src/MemoryStream.rux#L166){rel=""nofollow""} # StandardError Standard error: the same contract as standard output, on the stream reports belong to. ```rux pub struct StandardError { // private fields } ``` ## Associated functions ### `Acquire` ```rux pub func Acquire() -> StandardError ``` The process's standard error. **Returns**: the stream, which the process owns for its whole life [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Io/Src/Standard.rux#L322){rel=""nofollow""} ## Implements Writer `StandardError` conforms to [`Writer`](https://rux-lang.dev/docs/api/io/writer). ### `Write` ```rux pub func Write( self: &var StandardError, bytes: char8[..] ) -> uint ! IoError ``` Writes what it can of `bytes` to standard error. | Name | Type | Description | | ------- | ----------- | ------------------ | | `bytes` | `char8[..]` | the bytes to write | **Returns**: how many bytes were taken [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Io/Src/Standard.rux#L340){rel=""nofollow""} ### `Flush` ```rux pub func Flush(self: &var StandardError) -> ! IoError ``` Nothing: these writes hold nothing back. **Returns**: success, since everything written already reached the system [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Io/Src/Standard.rux#L347){rel=""nofollow""} # StandardIn Standard input, with the console-versus-redirection question answered at acquisition. ```rux pub struct StandardIn { pub pendingCount: uint; // private fields } ``` On Windows a console delivers UTF-16, which arrives here converted to UTF-8 so a program reads the same bytes whether its input is typed or piped; a redirected stream is read as the bytes it is. The value carries the few bytes of a converted character that did not fit the caller's buffer, and a surrogate half waiting for the other, so no reading pattern can tear a character. ## Fields | Name | Type | Description | | -------------- | ------ | --------------------------- | | `pendingCount` | `uint` | How many of them there are. | ## Associated functions ### `Acquire` ```rux pub func Acquire() -> StandardIn ``` The process's standard input. Asks the platform once whether the stream is a console; nothing is opened, and nothing needs closing. **Returns**: the stream, which the process owns for its whole life [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Io/Src/Standard.rux#L140){rel=""nofollow""} ## Implements Reader `StandardIn` conforms to [`Reader`](https://rux-lang.dev/docs/api/io/reader). ### `Read` ```rux pub func Read( self: &var StandardIn, into: var char8[..] ) -> uint ! IoError ``` Fills what it can of `into` from standard input. | Name | Type | Description | | ------ | --------------- | ------------------ | | `into` | `var char8[..]` | receives the bytes | **Returns**: how many bytes were read; [`IsEnd`](https://rux-lang.dev/docs/api/io/io-error#is-end) at the end of input [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Io/Src/Standard.rux#L162){rel=""nofollow""} # StandardOut Standard output: a byte [`Writer`](https://rux-lang.dev/docs/api/io/writer) whose encoding matches where the bytes land. ```rux pub struct StandardOut { // private fields } ``` ## Associated functions ### `Acquire` ```rux pub func Acquire() -> StandardOut ``` The process's standard output. **Returns**: the stream, which the process owns for its whole life [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Io/Src/Standard.rux#L280){rel=""nofollow""} ## Implements Writer `StandardOut` conforms to [`Writer`](https://rux-lang.dev/docs/api/io/writer). ### `Write` ```rux pub func Write( self: &var StandardOut, bytes: char8[..] ) -> uint ! IoError ``` Writes what it can of `bytes` to standard output. | Name | Type | Description | | ------- | ----------- | ------------------ | | `bytes` | `char8[..]` | the bytes to write | **Returns**: how many bytes were taken [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Io/Src/Standard.rux#L298){rel=""nofollow""} ### `Flush` ```rux pub func Flush(self: &var StandardOut) -> ! IoError ``` Nothing: these writes hold nothing back. **Returns**: success, since everything written already reached the system [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Io/Src/Standard.rux#L305){rel=""nofollow""} # StreamWriter A `TextWriter` over any stream, recording the stream's failure where the caller can see it. ```rux pub struct StreamWriter { // private fields } ``` The same two halves as [`ConsoleWriter`](https://rux-lang.dev/docs/api/io/console-writer), over a destination the caller chose: a file, a buffered writer, a pipe. It is what lets a value describe itself into a stream at all — `Display` writes into a `TextWriter` and a stream takes bytes, and until something stands between them a value can only be rendered to standard output or into memory. Whole runs go out through [`WriteAll`](https://rux-lang.dev/docs/api/io/writer#write-all), so a stream that takes a partial write is looped over rather than losing the rest of a value's text. The slot must outlive the writer. It is a stored address, so nothing here tracks that. ## Constructors ### `StreamWriter` ```rux pub func StreamWriter( sink: Writer, failure: *var IoError? ) -> StreamWriter ``` A text writer over `sink`, recording into `failure`. `sink` is borrowed for the call and kept. The slot is read before every write as well as written on failure, so a writer built over a slot that already holds a failure writes nothing at all. | Name | Type | Description | | --------- | --------------- | --------------------------------------------------------------------- | | `sink` | `Writer` | where the bytes go | | `failure` | `*var IoError?` | where the first stream failure is recorded, `none` until there is one | **Returns**: a text writer over that stream [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Io/Src/TextBoundary.rux#L142){rel=""nofollow""} ## Implements TextWriter `StreamWriter` conforms to `TextWriter`. ### `Write` ```rux pub func Write( self: &var StreamWriter, bytes: char8[..] ) -> ! FormatError ``` Writes `bytes` to the stream. Reports `WriterFailure` when the stream refuses, having recorded the original [`IoError`](https://rux-lang.dev/docs/api/io/io-error) in the slot. Once a failure has been recorded every later write is refused without touching the stream, so a value part-way through rendering does not go on writing into a destination that has already failed. | Name | Type | Description | | ------- | ----------- | ---------------------- | | `bytes` | `char8[..]` | the UTF-8 run to write | **Returns**: success when the stream accepted the whole run [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Io/Src/TextBoundary.rux#L155){rel=""nofollow""} # Binary encoding Fixed-width integers and floats read from a reader and written to a writer in a chosen byte order. ## `Endian` ```rux pub enum Endian: int32 { Little = 0, Big = 1 } ``` A byte order: which end of a multi-byte value comes first. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Io/Src/Binary.rux#L16){rel=""nofollow""} **Cases** | Name | Value | Description | | -------- | ----- | --------------------------------------------------------------------------------- | | `Little` | `0` | The least significant byte first: x86-64, AArch64, and most formats born on them. | | `Big` | `1` | The most significant byte first: network order, and the older big machines. | ## `ReadWord` ```rux pub func ReadWord( reader: &var Reader, endian: Endian, width: uint ) -> uint512 ! IoError ``` Reads a `width`-byte unsigned word in the given order, into the low bytes of the result. The word functions are the one implementation the typed surface below stands on; call those unless the width itself is a runtime quantity. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Io/Src/Binary.rux#L31){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | ------------- | --------------------------------------- | | `reader` | `&var Reader` | where the bytes come from | | `endian` | `Endian` | which byte order the value is stored in | | `width` | `uint` | how many bytes the value occupies | **Returns**: the value read, in the low bytes; [`IsEnd`](https://rux-lang.dev/docs/api/io/io-error#is-end) when the stream ended first ## `WriteWord` ```rux pub func WriteWord( writer: &var Writer, endian: Endian, width: uint, value: uint512 ) -> ! IoError ``` Writes the low `width` bytes of `value` in the given order. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Io/Src/Binary.rux#L53){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | ------------- | --------------------------------------- | | `writer` | `&var Writer` | the destination | | `endian` | `Endian` | which byte order the value is stored in | | `width` | `uint` | how many bytes the value occupies | | `value` | `uint512` | the value to write | **Returns**: success when the whole value was written ## `ReadUint8` ```rux pub func ReadUint8( reader: &var Reader, endian: Endian ) -> uint8 ! IoError ``` Reads a `uint8` in the given order. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Io/Src/Binary.rux#L72){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | ------------- | --------------------------------------- | | `reader` | `&var Reader` | where the bytes come from | | `endian` | `Endian` | which byte order the value is stored in | **Returns**: the value read; [`IsEnd`](https://rux-lang.dev/docs/api/io/io-error#is-end) when the stream ended first ## `WriteUint8` ```rux pub func WriteUint8( writer: &var Writer, endian: Endian, value: uint8 ) -> ! IoError ``` Writes a `uint8` in the given order. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Io/Src/Binary.rux#L83){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | ------------- | --------------------------------------- | | `writer` | `&var Writer` | the destination | | `endian` | `Endian` | which byte order the value is stored in | | `value` | `uint8` | the value to write | **Returns**: success when the whole value was written ## `ReadInt8` ```rux pub func ReadInt8( reader: &var Reader, endian: Endian ) -> int8 ! IoError ``` Reads an `int8`: the unsigned bytes, reinterpreted in two's complement. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Io/Src/Binary.rux#L92){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | ------------- | --------------------------------------- | | `reader` | `&var Reader` | where the bytes come from | | `endian` | `Endian` | which byte order the value is stored in | **Returns**: the value read; [`IsEnd`](https://rux-lang.dev/docs/api/io/io-error#is-end) when the stream ended first ## `WriteInt8` ```rux pub func WriteInt8( writer: &var Writer, endian: Endian, value: int8 ) -> ! IoError ``` Writes an `int8`: its two's-complement bytes, unchanged. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Io/Src/Binary.rux#L103){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | ------------- | --------------------------------------- | | `writer` | `&var Writer` | the destination | | `endian` | `Endian` | which byte order the value is stored in | | `value` | `int8` | the value to write | **Returns**: success when the whole value was written ## `ReadUint16` ```rux pub func ReadUint16( reader: &var Reader, endian: Endian ) -> uint16 ! IoError ``` Reads a `uint16` in the given order. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Io/Src/Binary.rux#L112){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | ------------- | --------------------------------------- | | `reader` | `&var Reader` | where the bytes come from | | `endian` | `Endian` | which byte order the value is stored in | **Returns**: the value read; [`IsEnd`](https://rux-lang.dev/docs/api/io/io-error#is-end) when the stream ended first ## `WriteUint16` ```rux pub func WriteUint16( writer: &var Writer, endian: Endian, value: uint16 ) -> ! IoError ``` Writes a `uint16` in the given order. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Io/Src/Binary.rux#L123){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | ------------- | --------------------------------------- | | `writer` | `&var Writer` | the destination | | `endian` | `Endian` | which byte order the value is stored in | | `value` | `uint16` | the value to write | **Returns**: success when the whole value was written ## `ReadInt16` ```rux pub func ReadInt16( reader: &var Reader, endian: Endian ) -> int16 ! IoError ``` Reads an `int16`: the unsigned bytes, reinterpreted in two's complement. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Io/Src/Binary.rux#L132){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | ------------- | --------------------------------------- | | `reader` | `&var Reader` | where the bytes come from | | `endian` | `Endian` | which byte order the value is stored in | **Returns**: the value read; [`IsEnd`](https://rux-lang.dev/docs/api/io/io-error#is-end) when the stream ended first ## `WriteInt16` ```rux pub func WriteInt16( writer: &var Writer, endian: Endian, value: int16 ) -> ! IoError ``` Writes an `int16`: its two's-complement bytes, unchanged. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Io/Src/Binary.rux#L143){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | ------------- | --------------------------------------- | | `writer` | `&var Writer` | the destination | | `endian` | `Endian` | which byte order the value is stored in | | `value` | `int16` | the value to write | **Returns**: success when the whole value was written ## `ReadUint32` ```rux pub func ReadUint32( reader: &var Reader, endian: Endian ) -> uint32 ! IoError ``` Reads a `uint32` in the given order. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Io/Src/Binary.rux#L152){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | ------------- | --------------------------------------- | | `reader` | `&var Reader` | where the bytes come from | | `endian` | `Endian` | which byte order the value is stored in | **Returns**: the value read; [`IsEnd`](https://rux-lang.dev/docs/api/io/io-error#is-end) when the stream ended first ## `WriteUint32` ```rux pub func WriteUint32( writer: &var Writer, endian: Endian, value: uint32 ) -> ! IoError ``` Writes a `uint32` in the given order. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Io/Src/Binary.rux#L163){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | ------------- | --------------------------------------- | | `writer` | `&var Writer` | the destination | | `endian` | `Endian` | which byte order the value is stored in | | `value` | `uint32` | the value to write | **Returns**: success when the whole value was written ## `ReadInt32` ```rux pub func ReadInt32( reader: &var Reader, endian: Endian ) -> int32 ! IoError ``` Reads an `int32`: the unsigned bytes, reinterpreted in two's complement. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Io/Src/Binary.rux#L172){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | ------------- | --------------------------------------- | | `reader` | `&var Reader` | where the bytes come from | | `endian` | `Endian` | which byte order the value is stored in | **Returns**: the value read; [`IsEnd`](https://rux-lang.dev/docs/api/io/io-error#is-end) when the stream ended first ## `WriteInt32` ```rux pub func WriteInt32( writer: &var Writer, endian: Endian, value: int32 ) -> ! IoError ``` Writes an `int32`: its two's-complement bytes, unchanged. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Io/Src/Binary.rux#L183){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | ------------- | --------------------------------------- | | `writer` | `&var Writer` | the destination | | `endian` | `Endian` | which byte order the value is stored in | | `value` | `int32` | the value to write | **Returns**: success when the whole value was written ## `ReadUint64` ```rux pub func ReadUint64( reader: &var Reader, endian: Endian ) -> uint64 ! IoError ``` Reads a `uint64` in the given order. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Io/Src/Binary.rux#L192){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | ------------- | --------------------------------------- | | `reader` | `&var Reader` | where the bytes come from | | `endian` | `Endian` | which byte order the value is stored in | **Returns**: the value read; [`IsEnd`](https://rux-lang.dev/docs/api/io/io-error#is-end) when the stream ended first ## `WriteUint64` ```rux pub func WriteUint64( writer: &var Writer, endian: Endian, value: uint64 ) -> ! IoError ``` Writes a `uint64` in the given order. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Io/Src/Binary.rux#L203){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | ------------- | --------------------------------------- | | `writer` | `&var Writer` | the destination | | `endian` | `Endian` | which byte order the value is stored in | | `value` | `uint64` | the value to write | **Returns**: success when the whole value was written ## `ReadInt64` ```rux pub func ReadInt64( reader: &var Reader, endian: Endian ) -> int64 ! IoError ``` Reads an `int64`: the unsigned bytes, reinterpreted in two's complement. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Io/Src/Binary.rux#L212){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | ------------- | --------------------------------------- | | `reader` | `&var Reader` | where the bytes come from | | `endian` | `Endian` | which byte order the value is stored in | **Returns**: the value read; [`IsEnd`](https://rux-lang.dev/docs/api/io/io-error#is-end) when the stream ended first ## `WriteInt64` ```rux pub func WriteInt64( writer: &var Writer, endian: Endian, value: int64 ) -> ! IoError ``` Writes an `int64`: its two's-complement bytes, unchanged. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Io/Src/Binary.rux#L223){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | ------------- | --------------------------------------- | | `writer` | `&var Writer` | the destination | | `endian` | `Endian` | which byte order the value is stored in | | `value` | `int64` | the value to write | **Returns**: success when the whole value was written ## `ReadUint128` ```rux pub func ReadUint128( reader: &var Reader, endian: Endian ) -> uint128 ! IoError ``` Reads a `uint128` in the given order. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Io/Src/Binary.rux#L232){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | ------------- | --------------------------------------- | | `reader` | `&var Reader` | where the bytes come from | | `endian` | `Endian` | which byte order the value is stored in | **Returns**: the value read; [`IsEnd`](https://rux-lang.dev/docs/api/io/io-error#is-end) when the stream ended first ## `WriteUint128` ```rux pub func WriteUint128( writer: &var Writer, endian: Endian, value: uint128 ) -> ! IoError ``` Writes a `uint128` in the given order. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Io/Src/Binary.rux#L243){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | ------------- | --------------------------------------- | | `writer` | `&var Writer` | the destination | | `endian` | `Endian` | which byte order the value is stored in | | `value` | `uint128` | the value to write | **Returns**: success when the whole value was written ## `ReadInt128` ```rux pub func ReadInt128( reader: &var Reader, endian: Endian ) -> int128 ! IoError ``` Reads an `int128`: the unsigned bytes, reinterpreted in two's complement. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Io/Src/Binary.rux#L252){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | ------------- | --------------------------------------- | | `reader` | `&var Reader` | where the bytes come from | | `endian` | `Endian` | which byte order the value is stored in | **Returns**: the value read; [`IsEnd`](https://rux-lang.dev/docs/api/io/io-error#is-end) when the stream ended first ## `WriteInt128` ```rux pub func WriteInt128( writer: &var Writer, endian: Endian, value: int128 ) -> ! IoError ``` Writes an `int128`: its two's-complement bytes, unchanged. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Io/Src/Binary.rux#L263){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | ------------- | --------------------------------------- | | `writer` | `&var Writer` | the destination | | `endian` | `Endian` | which byte order the value is stored in | | `value` | `int128` | the value to write | **Returns**: success when the whole value was written ## `ReadUint256` ```rux pub func ReadUint256( reader: &var Reader, endian: Endian ) -> uint256 ! IoError ``` Reads a `uint256` in the given order. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Io/Src/Binary.rux#L272){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | ------------- | --------------------------------------- | | `reader` | `&var Reader` | where the bytes come from | | `endian` | `Endian` | which byte order the value is stored in | **Returns**: the value read; [`IsEnd`](https://rux-lang.dev/docs/api/io/io-error#is-end) when the stream ended first ## `WriteUint256` ```rux pub func WriteUint256( writer: &var Writer, endian: Endian, value: uint256 ) -> ! IoError ``` Writes a `uint256` in the given order. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Io/Src/Binary.rux#L283){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | ------------- | --------------------------------------- | | `writer` | `&var Writer` | the destination | | `endian` | `Endian` | which byte order the value is stored in | | `value` | `uint256` | the value to write | **Returns**: success when the whole value was written ## `ReadInt256` ```rux pub func ReadInt256( reader: &var Reader, endian: Endian ) -> int256 ! IoError ``` Reads an `int256`: the unsigned bytes, reinterpreted in two's complement. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Io/Src/Binary.rux#L292){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | ------------- | --------------------------------------- | | `reader` | `&var Reader` | where the bytes come from | | `endian` | `Endian` | which byte order the value is stored in | **Returns**: the value read; [`IsEnd`](https://rux-lang.dev/docs/api/io/io-error#is-end) when the stream ended first ## `WriteInt256` ```rux pub func WriteInt256( writer: &var Writer, endian: Endian, value: int256 ) -> ! IoError ``` Writes an `int256`: its two's-complement bytes, unchanged. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Io/Src/Binary.rux#L303){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | ------------- | --------------------------------------- | | `writer` | `&var Writer` | the destination | | `endian` | `Endian` | which byte order the value is stored in | | `value` | `int256` | the value to write | **Returns**: success when the whole value was written ## `ReadUint512` ```rux pub func ReadUint512( reader: &var Reader, endian: Endian ) -> uint512 ! IoError ``` Reads a `uint512` in the given order. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Io/Src/Binary.rux#L312){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | ------------- | --------------------------------------- | | `reader` | `&var Reader` | where the bytes come from | | `endian` | `Endian` | which byte order the value is stored in | **Returns**: the value read; [`IsEnd`](https://rux-lang.dev/docs/api/io/io-error#is-end) when the stream ended first ## `WriteUint512` ```rux pub func WriteUint512( writer: &var Writer, endian: Endian, value: uint512 ) -> ! IoError ``` Writes a `uint512` in the given order. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Io/Src/Binary.rux#L323){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | ------------- | --------------------------------------- | | `writer` | `&var Writer` | the destination | | `endian` | `Endian` | which byte order the value is stored in | | `value` | `uint512` | the value to write | **Returns**: success when the whole value was written ## `ReadInt512` ```rux pub func ReadInt512( reader: &var Reader, endian: Endian ) -> int512 ! IoError ``` Reads an `int512`: the unsigned bytes, reinterpreted in two's complement. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Io/Src/Binary.rux#L332){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | ------------- | --------------------------------------- | | `reader` | `&var Reader` | where the bytes come from | | `endian` | `Endian` | which byte order the value is stored in | **Returns**: the value read; [`IsEnd`](https://rux-lang.dev/docs/api/io/io-error#is-end) when the stream ended first ## `WriteInt512` ```rux pub func WriteInt512( writer: &var Writer, endian: Endian, value: int512 ) -> ! IoError ``` Writes an `int512`: its two's-complement bytes, unchanged. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Io/Src/Binary.rux#L343){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | ------------- | --------------------------------------- | | `writer` | `&var Writer` | the destination | | `endian` | `Endian` | which byte order the value is stored in | | `value` | `int512` | the value to write | **Returns**: success when the whole value was written ## `ReadFloat32` ```rux pub func ReadFloat32( reader: &var Reader, endian: Endian ) -> float32 ! IoError ``` Reads a `float32` as the IEEE 754 bit pattern of its width. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Io/Src/Binary.rux#L352){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | ------------- | --------------------------------------- | | `reader` | `&var Reader` | where the bytes come from | | `endian` | `Endian` | which byte order the value is stored in | **Returns**: the value read; [`IsEnd`](https://rux-lang.dev/docs/api/io/io-error#is-end) when the stream ended first ## `WriteFloat32` ```rux pub func WriteFloat32( writer: &var Writer, endian: Endian, value: float32 ) -> ! IoError ``` Writes a `float32` as the IEEE 754 bit pattern of its width. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Io/Src/Binary.rux#L365){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | ------------- | --------------------------------------- | | `writer` | `&var Writer` | the destination | | `endian` | `Endian` | which byte order the value is stored in | | `value` | `float32` | the value to write | **Returns**: success when the whole value was written ## `ReadFloat64` ```rux pub func ReadFloat64( reader: &var Reader, endian: Endian ) -> float64 ! IoError ``` Reads a `float64` as the IEEE 754 bit pattern of its width. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Io/Src/Binary.rux#L377){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | ------------- | --------------------------------------- | | `reader` | `&var Reader` | where the bytes come from | | `endian` | `Endian` | which byte order the value is stored in | **Returns**: the value read; [`IsEnd`](https://rux-lang.dev/docs/api/io/io-error#is-end) when the stream ended first ## `WriteFloat64` ```rux pub func WriteFloat64( writer: &var Writer, endian: Endian, value: float64 ) -> ! IoError ``` Writes a `float64` as the IEEE 754 bit pattern of its width. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Io/Src/Binary.rux#L390){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | ------------- | --------------------------------------- | | `writer` | `&var Writer` | the destination | | `endian` | `Endian` | which byte order the value is stored in | | `value` | `float64` | the value to write | **Returns**: success when the whole value was written # Print Writes a value's text to standard output. ```rux pub func Print(value: String) -> IoError? pub func Print(value: StringView) -> IoError? pub func Print(value: char8[..]) -> IoError? pub func Print(#Format() format: char8[..], ...) -> IoError? pub func Print(value: bool8) -> IoError? pub func Print(value: bool16) -> IoError? pub func Print(value: bool32) -> IoError? pub func Print(value: bool64) -> IoError? pub func Print(value: bool128) -> IoError? pub func Print(value: bool256) -> IoError? pub func Print(value: bool512) -> IoError? pub func Print(value: char8) -> IoError? pub func Print(value: char16) -> IoError? pub func Print(value: char32) -> IoError? pub func Print(value: char64) -> IoError? pub func Print(value: char128) -> IoError? pub func Print(value: char256) -> IoError? pub func Print(value: char512) -> IoError? pub func Print(value: int8) -> IoError? pub func Print(value: int16) -> IoError? pub func Print(value: int32) -> IoError? pub func Print(value: int64) -> IoError? pub func Print(value: uint8) -> IoError? pub func Print(value: uint16) -> IoError? pub func Print(value: uint32) -> IoError? pub func Print(value: uint64) -> IoError? pub func Print(value: int) -> IoError? pub func Print(value: uint) -> IoError? pub func Print(value: float8) -> IoError? pub func Print(value: float16) -> IoError? pub func Print(value: float32) -> IoError? pub func Print(value: float64) -> IoError? ``` A `String`, a `StringView` or a `char8[..]` is written as the UTF-8 bytes it holds, unchanged: nothing is substituted and no brace is special, so `Print("{{}}")` writes `{{}}`. Each primitive overload writes its value as [`PrintValue`](https://rux-lang.dev/docs/api/io/print#print-value) does, through the type's `Display` conformance, and any other value goes through [`PrintValue`](https://rux-lang.dev/docs/api/io/print#print-value) itself. Given arguments after it, the first text is a pattern instead: each `{}` or `{:spec}` takes the next argument in order, and `{{` and `}}` write a literal brace. Every overload returns the failure its write met as an [`IoError`](https://rux-lang.dev/docs/api/io/io-error), or `none`. A program logging to a terminal loses nothing by ignoring it; one whose output feeds a pipe that may close has something to look at. | Overload | Summary | | -------------------------------------------------------------- | -------------------------------------------------------------------------------- | | `pub func Print(value: String) -> IoError?` | Writes a value's text to standard output. | | `pub func Print(value: StringView) -> IoError?` | Writes the text a `StringView` borrows to standard output. | | `pub func Print(value: char8[..]) -> IoError?` | Writes text to standard output. | | `pub func Print(#Format() format: char8[..], ...) -> IoError?` | Writes `format` to standard output with each `{}` replaced by the next argument. | | `pub func Print(value: bool8) -> IoError?` | Writes a `bool8` to standard output. | | `pub func Print(value: bool16) -> IoError?` | Writes a `bool16` to standard output. | | `pub func Print(value: bool32) -> IoError?` | Writes a `bool32` to standard output. | | `pub func Print(value: bool64) -> IoError?` | Writes a `bool64` to standard output. | | `pub func Print(value: bool128) -> IoError?` | Writes a `bool128` to standard output. | | `pub func Print(value: bool256) -> IoError?` | Writes a `bool256` to standard output. | | `pub func Print(value: bool512) -> IoError?` | Writes a `bool512` to standard output. | | `pub func Print(value: char8) -> IoError?` | Writes a `char8` to standard output. | | `pub func Print(value: char16) -> IoError?` | Writes a `char16` to standard output. | | `pub func Print(value: char32) -> IoError?` | Writes a `char32` to standard output. | | `pub func Print(value: char64) -> IoError?` | Writes a `char64` to standard output. | | `pub func Print(value: char128) -> IoError?` | Writes a `char128` to standard output. | | `pub func Print(value: char256) -> IoError?` | Writes a `char256` to standard output. | | `pub func Print(value: char512) -> IoError?` | Writes a `char512` to standard output. | | `pub func Print(value: int8) -> IoError?` | Writes a `int8` to standard output. | | `pub func Print(value: int16) -> IoError?` | Writes a `int16` to standard output. | | `pub func Print(value: int32) -> IoError?` | Writes a `int32` to standard output. | | `pub func Print(value: int64) -> IoError?` | Writes a `int64` to standard output. | | `pub func Print(value: uint8) -> IoError?` | Writes a `uint8` to standard output. | | `pub func Print(value: uint16) -> IoError?` | Writes a `uint16` to standard output. | | `pub func Print(value: uint32) -> IoError?` | Writes a `uint32` to standard output. | | `pub func Print(value: uint64) -> IoError?` | Writes a `uint64` to standard output. | | `pub func Print(value: int) -> IoError?` | Writes a `int` to standard output. | | `pub func Print(value: uint) -> IoError?` | Writes a `uint` to standard output. | | `pub func Print(value: float8) -> IoError?` | Writes a `float8` to standard output. | | `pub func Print(value: float16) -> IoError?` | Writes a `float16` to standard output. | | `pub func Print(value: float32) -> IoError?` | Writes a `float32` to standard output. | | `pub func Print(value: float64) -> IoError?` | Writes a `float64` to standard output. | ## Parameters | Name | Type | Description | | ------------------ | ------------ | ------------------ | | `value` | `String` | the value to write | | `value` | `StringView` | the value to write | | `value` | `char8[..]` | the value to write | | `#Format() format` | `char8[..]` | | | `...` | | | | `value` | `bool8` | the value to write | | `value` | `bool16` | the value to write | | `value` | `bool32` | the value to write | | `value` | `bool64` | the value to write | | `value` | `bool128` | the value to write | | `value` | `bool256` | the value to write | | `value` | `bool512` | the value to write | | `value` | `char8` | the value to write | | `value` | `char16` | the value to write | | `value` | `char32` | the value to write | | `value` | `char64` | the value to write | | `value` | `char128` | the value to write | | `value` | `char256` | the value to write | | `value` | `char512` | the value to write | | `value` | `int8` | the value to write | | `value` | `int16` | the value to write | | `value` | `int32` | the value to write | | `value` | `int64` | the value to write | | `value` | `uint8` | the value to write | | `value` | `uint16` | the value to write | | `value` | `uint32` | the value to write | | `value` | `uint64` | the value to write | | `value` | `int` | the value to write | | `value` | `uint` | the value to write | | `value` | `float8` | the value to write | | `value` | `float16` | the value to write | | `value` | `float32` | the value to write | | `value` | `float64` | the value to write | **Returns**: the failure, or `none` when the whole value was written ## Related ### `PrintValue` ```rux pub func PrintValue(value: Display) -> IoError? ``` Writes a value's text to standard output. Nothing is allocated: the value writes itself straight to the stream. The value arrives as an interface value, which copies it — or takes it, for a type that prohibits copying. [`WriteValueLine`](https://rux-lang.dev/docs/api/io/print-line#write-value-line) is the borrowing form, and takes any destination, so a value that must not be given up goes through a [`ConsoleWriter`](https://rux-lang.dev/docs/api/io/console-writer) and that instead. A stream failure is returned as the stream reported it. A formatting failure on a healthy stream is translated by [`ToIoError`](https://rux-lang.dev/docs/api/io/io-error#to-io-error), so a request that was wrong arrives as `InvalidInput` and stays distinguishable from anything the destination did. Which formatting failure it was does not survive that translation, since [`IoError`](https://rux-lang.dev/docs/api/io/io-error) has no room for one; a caller who needs it builds a [`ConsoleWriter`](https://rux-lang.dev/docs/api/io/console-writer) and calls `Text::WriteValue` themselves. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Io/Src/Print.rux#L47){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------- | --------- | ------------------ | | `value` | `Display` | the value to write | **Returns**: what the stream reported, or the translated formatting failure on a healthy stream, or `none` # PrintLine Writes a value's text to standard output, then a newline. ```rux pub func PrintLine() -> IoError? pub func PrintLine(value: String) -> IoError? pub func PrintLine(value: char8[..]) -> IoError? pub func PrintLine(value: StringView) -> IoError? pub func PrintLine( #Format() format: char8[..], ... ) -> IoError? pub func PrintLine(value: bool8) -> IoError? pub func PrintLine(value: bool16) -> IoError? pub func PrintLine(value: bool32) -> IoError? pub func PrintLine(value: bool64) -> IoError? pub func PrintLine(value: bool128) -> IoError? pub func PrintLine(value: bool256) -> IoError? pub func PrintLine(value: bool512) -> IoError? pub func PrintLine(value: char8) -> IoError? pub func PrintLine(value: char16) -> IoError? pub func PrintLine(value: char32) -> IoError? pub func PrintLine(value: char64) -> IoError? pub func PrintLine(value: char128) -> IoError? pub func PrintLine(value: char256) -> IoError? pub func PrintLine(value: char512) -> IoError? pub func PrintLine(value: int8) -> IoError? pub func PrintLine(value: int16) -> IoError? pub func PrintLine(value: int32) -> IoError? pub func PrintLine(value: int64) -> IoError? pub func PrintLine(value: uint8) -> IoError? pub func PrintLine(value: uint16) -> IoError? pub func PrintLine(value: uint32) -> IoError? pub func PrintLine(value: uint64) -> IoError? pub func PrintLine(value: int) -> IoError? pub func PrintLine(value: uint) -> IoError? pub func PrintLine(value: float8) -> IoError? pub func PrintLine(value: float16) -> IoError? pub func PrintLine(value: float32) -> IoError? pub func PrintLine(value: float64) -> IoError? ``` Each overload writes exactly what the matching [`Print`](https://rux-lang.dev/docs/api/io/print) overload writes, then `\n`, and writes the newline only when the value's own write succeeded: a line is the value and its terminator together, so a failed write leaves no empty line behind and returns its own failure. `PrintLine()` writes the newline alone. Text with no arguments after it is written verbatim, braces and all. Given arguments, it is a pattern whose `{}` and `{:spec}` placeholders take them in order, and `{{` and `}}` write a literal brace. | Overload | Summary | | ------------------------------------------------------------------ | ------------------------------------------------------------------------------------ | | `pub func PrintLine() -> IoError?` | Writes a newline to standard output. | | `pub func PrintLine(value: String) -> IoError?` | Writes a value's text to standard output, then a newline. | | `pub func PrintLine(value: char8[..]) -> IoError?` | Writes text to standard output verbatim, then a newline. | | `pub func PrintLine(value: StringView) -> IoError?` | Writes the text a `StringView` borrows to standard output, then a newline. | | `pub func PrintLine(#Format() format: char8[..], ...) -> IoError?` | Writes `format` with each placeholder replaced by the next argument, then a newline. | | `pub func PrintLine(value: bool8) -> IoError?` | Writes a `bool8` to standard output, then a newline. | | `pub func PrintLine(value: bool16) -> IoError?` | Writes a `bool16` to standard output, then a newline. | | `pub func PrintLine(value: bool32) -> IoError?` | Writes a `bool32` to standard output, then a newline. | | `pub func PrintLine(value: bool64) -> IoError?` | Writes a `bool64` to standard output, then a newline. | | `pub func PrintLine(value: bool128) -> IoError?` | Writes a `bool128` to standard output, then a newline. | | `pub func PrintLine(value: bool256) -> IoError?` | Writes a `bool256` to standard output, then a newline. | | `pub func PrintLine(value: bool512) -> IoError?` | Writes a `bool512` to standard output, then a newline. | | `pub func PrintLine(value: char8) -> IoError?` | Writes a `char8` to standard output, then a newline. | | `pub func PrintLine(value: char16) -> IoError?` | Writes a `char16` to standard output, then a newline. | | `pub func PrintLine(value: char32) -> IoError?` | Writes a `char32` to standard output, then a newline. | | `pub func PrintLine(value: char64) -> IoError?` | Writes a `char64` to standard output, then a newline. | | `pub func PrintLine(value: char128) -> IoError?` | Writes a `char128` to standard output, then a newline. | | `pub func PrintLine(value: char256) -> IoError?` | Writes a `char256` to standard output, then a newline. | | `pub func PrintLine(value: char512) -> IoError?` | Writes a `char512` to standard output, then a newline. | | `pub func PrintLine(value: int8) -> IoError?` | Writes a `int8` to standard output, then a newline. | | `pub func PrintLine(value: int16) -> IoError?` | Writes a `int16` to standard output, then a newline. | | `pub func PrintLine(value: int32) -> IoError?` | Writes a `int32` to standard output, then a newline. | | `pub func PrintLine(value: int64) -> IoError?` | Writes a `int64` to standard output, then a newline. | | `pub func PrintLine(value: uint8) -> IoError?` | Writes a `uint8` to standard output, then a newline. | | `pub func PrintLine(value: uint16) -> IoError?` | Writes a `uint16` to standard output, then a newline. | | `pub func PrintLine(value: uint32) -> IoError?` | Writes a `uint32` to standard output, then a newline. | | `pub func PrintLine(value: uint64) -> IoError?` | Writes a `uint64` to standard output, then a newline. | | `pub func PrintLine(value: int) -> IoError?` | Writes a `int` to standard output, then a newline. | | `pub func PrintLine(value: uint) -> IoError?` | Writes a `uint` to standard output, then a newline. | | `pub func PrintLine(value: float8) -> IoError?` | Writes a `float8` to standard output, then a newline. | | `pub func PrintLine(value: float16) -> IoError?` | Writes a `float16` to standard output, then a newline. | | `pub func PrintLine(value: float32) -> IoError?` | Writes a `float32` to standard output, then a newline. | | `pub func PrintLine(value: float64) -> IoError?` | Writes a `float64` to standard output, then a newline. | ## Parameters | Name | Type | Description | | ------------------ | ------------ | ------------------ | | `value` | `String` | the value to write | | `value` | `char8[..]` | the value to write | | `value` | `StringView` | the value to write | | `#Format() format` | `char8[..]` | | | `...` | | | | `value` | `bool8` | the value to write | | `value` | `bool16` | the value to write | | `value` | `bool32` | the value to write | | `value` | `bool64` | the value to write | | `value` | `bool128` | the value to write | | `value` | `bool256` | the value to write | | `value` | `bool512` | the value to write | | `value` | `char8` | the value to write | | `value` | `char16` | the value to write | | `value` | `char32` | the value to write | | `value` | `char64` | the value to write | | `value` | `char128` | the value to write | | `value` | `char256` | the value to write | | `value` | `char512` | the value to write | | `value` | `int8` | the value to write | | `value` | `int16` | the value to write | | `value` | `int32` | the value to write | | `value` | `int64` | the value to write | | `value` | `uint8` | the value to write | | `value` | `uint16` | the value to write | | `value` | `uint32` | the value to write | | `value` | `uint64` | the value to write | | `value` | `int` | the value to write | | `value` | `uint` | the value to write | | `value` | `float8` | the value to write | | `value` | `float16` | the value to write | | `value` | `float32` | the value to write | | `value` | `float64` | the value to write | **Returns**: the failure, or `none` when the whole value was written ## Related ### `PrintValueLine` ```rux pub func PrintValueLine(value: Display) -> IoError? ``` Writes a value's text to standard output, then a newline. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Io/Src/Print.rux#L59){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------- | --------- | ------------------ | | `value` | `Display` | the value to write | **Returns**: the failure, or `none` when the whole value was written ### `WriteValueLine<T>` ```rux pub func WriteValueLine<T: Display>( writer: &var TextWriter, value: &T ) -> ! FormatError ``` Writes a value's text, then a newline, and writes the newline only if the value went out whole. The rule is the whole point. A line is a value and its terminator together, so a value that could not be written must not be followed by a terminator: a destination that refused halfway would otherwise get a line break marking the end of something that is not there, and a caller reading the output back would see a blank line where a value should be. This is what every [`PrintLine`](https://rux-lang.dev/docs/api/io/print-line) overload does over standard output, written once for any destination. The value is taken by bound rather than as an interface value, and that is the difference between writing a value and taking it: binding a move-only value to a `Display` transfers ownership of it, so a surface that accepted one could write such a value exactly once and the caller would not have it afterwards. Here it is borrowed, so it may be written as often as wanted and is still the caller's. Reports the value's own failure when it has one, without attempting the newline. Otherwise reports whatever the newline's write reported. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Io/Src/TextBoundary.rux#L183){rel=""nofollow""} **Type parameters** | Name | Description | | ------------ | ---------------------------------------------------- | | `T: Display` | the value's type, which must know how to show itself | **Parameters** | Name | Type | Description | | -------- | ----------------- | ----------------------------------------- | | `writer` | `&var TextWriter` | the destination | | `value` | `&T` | the value to write, borrowed for the call | **Returns**: success when both the value and the newline were accepted ### `WriteFormatLine` ```rux pub func WriteFormatLine( writer: &var TextWriter, #Format() format: char8[..], ... ) -> ! FormatError ``` Writes `format` with each `{}` replaced by the next argument, then a newline, on the same rule. The newline goes out only if the whole pattern did, so a pattern that does not parse, an argument count that does not match and a destination that refused all leave no terminator behind. Nothing is allocated: the arguments write themselves as they are reached. They arrive as interface values, which is what a variadic can carry, so a move-only argument goes through [`WriteValueLine`](https://rux-lang.dev/docs/api/io/print-line#write-value-line) instead of through a placeholder. A literal `format` has its placeholders counted against the arguments while compiling, since it is marked `#Format()`. Reports the formatting failure when there is one, without attempting the newline. Otherwise reports whatever the newline's write reported. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Io/Src/TextBoundary.rux#L200){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------------------ | ----------------- | --------------- | | `writer` | `&var TextWriter` | the destination | | `#Format() format` | `char8[..]` | | | `...` | | | **Returns**: success when the whole line was accepted # ReadLine Appends the next line of standard input to `builder`, without its ending. ```rux pub func ReadLine(builder: &var StringBuilder) -> ! IoError ``` `EndOfStream` is reported only when the input ends with nothing before it; a stream failure is returned as itself, with whatever was read so far left in the builder. The line must be UTF-8: a byte that does not belong to a well-formed character, or a character cut short by the end of the input, is `InvalidText`, reported once the rest of the line has been read through its ending so that the next call starts on the next line; the text before the fault stays in the builder. Reads one byte at a time on purpose: standard input may be shared with whatever runs next, and a buffer here would take bytes that were never this line's. ## Parameters | Name | Type | Description | | --------- | -------------------- | -------------------------------------------------------- | | `builder` | `&var StringBuilder` | receives the line, appended to whatever it already holds | **Returns**: success when a line was read; [`IsEnd`](https://rux-lang.dev/docs/api/io/io-error#is-end) at the end of input with nothing appended ## Related ### `ReadLineFrom` ```rux pub func ReadLineFrom( reader: &var Reader, builder: &var StringBuilder ) -> ! IoError ``` Appends the next line of `reader` to `builder`, without its ending, reading one byte at a time. This is [`ReadLine`](https://rux-lang.dev/docs/api/io/read-line) over any source: a line feed ends the line, a carriage return immediately before it belongs to the ending, and `EndOfStream` is reported only when the source ends with nothing before it. A stream failure is returned as itself, with whatever was read so far left in the builder. The line must be UTF-8: a byte that does not belong to a well-formed character, or a character cut short by the end of the source, is `InvalidText`, reported once the rest of the line has been read through its ending; the text before the fault stays in the builder. No byte past the line's ending is read, which is what makes it safe on a shared stream; a source that is not shared reads faster through [`ReadTextLine`](https://rux-lang.dev/docs/api/io/read-line#read-text-line) over a [`BufferedReader`](https://rux-lang.dev/docs/api/io/buffered-reader). [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Io/Src/ReadLine.rux#L38){rel=""nofollow""} **Parameters** | Name | Type | Description | | --------- | -------------------- | -------------------------------------------------------- | | `reader` | `&var Reader` | where the bytes come from, borrowed for the call | | `builder` | `&var StringBuilder` | receives the line, appended to whatever it already holds | **Returns**: success when a line was read; [`IsEnd`](https://rux-lang.dev/docs/api/io/io-error#is-end) at the end of input with nothing appended ### `ReadTextLine` ```rux pub func ReadTextLine( reader: &var BufferedReader, builder: &var StringBuilder, limit: uint ) -> ! IoError ``` Appends the next line of `reader` to `builder`, without its ending. A line ends at a line feed; a carriage return immediately before it is part of the ending. The last line of a stream needs no ending: what stands before the end is a line, and `EndOfStream` is reported only when the stream ends with nothing before it, so a caller loops until exactly that. The line must be UTF-8 — `InvalidText` otherwise, including a sequence cut short by the end of the stream -- and at most `limit` bytes, `LimitExceeded` otherwise. Only validated bytes ever reach the builder, and on either failure it is cleared and the offending line consumed through its ending, so the caller can report the line and read on. A scalar value split across the buffer's edge is completed from the next refill, not condemned: where the buffer happens to end is not a property of the text. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Io/Src/TextRead.rux#L27){rel=""nofollow""} **Parameters** | Name | Type | Description | | --------- | --------------------- | ----------------------------------------------------------- | | `reader` | `&var BufferedReader` | where the bytes come from | | `builder` | `&var StringBuilder` | receives the line, appended to whatever it already holds | | `limit` | `uint` | the most bytes to accept before reporting the line too long | **Returns**: success when a line was read; [`IsEnd`](https://rux-lang.dev/docs/api/io/io-error#is-end) at the end of input with nothing appended # FileSystem Files, directories and filesystem operations. ## Installation Add `FileSystem` to the `[Dependencies]` table of your package's `Rux.toml`: ```toml [Dependencies] FileSystem = { Namespace = "Rux", Version = "0.1.0" } ``` Standard packages are declared by hand: the registry does not serve them, so `rux add Rux/FileSystem` cannot add them. ## Dependencies - [`Allocator`](https://rux-lang.dev/docs/api/allocator) 0.1.0 - [`Core`](https://rux-lang.dev/docs/api/core) 0.1.0 - [`Entropy`](https://rux-lang.dev/docs/api/entropy) 0.1.0 - [`FreeBSD`](https://rux-lang.dev/docs/api/freebsd) 0.1.0 (FreeBSD only) - [`Io`](https://rux-lang.dev/docs/api/io) 0.1.0 - [`Linux`](https://rux-lang.dev/docs/api/linux) 0.1.0 (Linux only) - [`macOS`](https://rux-lang.dev/docs/api/macos) 0.1.0 (macOS only) - [`Path`](https://rux-lang.dev/docs/api/path) 0.1.0 - [`Text`](https://rux-lang.dev/docs/api/text) 0.1.0 - [`Time`](https://rux-lang.dev/docs/api/time) 0.1.0 - [`Windows`](https://rux-lang.dev/docs/api/windows) 0.1.0 (Windows only) ## Guide ### What it provides - **[`File`](https://rux-lang.dev/docs/api/filesystem/file) and [`OpenOptions`](https://rux-lang.dev/docs/api/filesystem/file#open-options)** — a move-only owned handle the type system closes exactly once and copyable options created with [`OpenOptions()`](https://rux-lang.dev/docs/api/filesystem/file#open-options). Safe operations borrow the handle through `&File` or `&var File`; only stored platform handles and explicit output slots remain raw pointers. - **Deterministic owners** — directory iterators, temporary files and directories, and atomic writes prohibit copying, transfer with `<-`, and clean up through `~Type` destructors. Fallible operations such as [`Open`](https://rux-lang.dev/docs/api/filesystem/file#open), `Create`, and [`Begin`](https://rux-lang.dev/docs/api/filesystem/atomic-write#begin) keep their descriptive names. - **A file is a stream, and a stream is usually a borrow** — [`File`](https://rux-lang.dev/docs/api/filesystem/file) implements `Reader`, `Writer` and `Seeker`, so anything wanting a stream for the length of a call takes the file: ```rux WriteAll(file, contents)?; ``` :brThe borrow is checked and ends at the call, which means the compiler also refuses reading the file through while a borrow of it is still live. [`FileStream`](https://rux-lang.dev/docs/api/filesystem/file-stream) is the stored form, for a value such as a `BufferedReader` that keeps its source past the call that made it — binding the file itself into an interface value there would move it, and there would be nothing left to close. Its representation is private and [`File::Stream`](https://rux-lang.dev/docs/api/filesystem/file#stream) is the only way to obtain one; it must not outlive the file or survive a move of it, and nothing tracks either. A stream over a *closed* file is not unsafe: the file checks its own handle, so every operation refuses with `InvalidHandle`. [`AtomicWrite`](https://rux-lang.dev/docs/api/filesystem/atomic-write) is itself a `Writer`, so replacing a file needs no adapter at all. - **Native error translation** — every operation that can fail returns a native fallible whose failure is an `Io::IoError`: the kind a caller acts on, with the platform's raw code preserved beside it, translated by one table per platform rather than ad hoc at each call site. [`File::Open`](https://rux-lang.dev/docs/api/filesystem/file#open), [`ReadDirectory`](https://rux-lang.dev/docs/api/filesystem/directories#read-directory), [`MetadataOf`](https://rux-lang.dev/docs/api/filesystem/metadata#metadata-of), and the other constructors and queries succeed with their value, and the rest succeed with `()`; a directory iterator's [`Next`](https://rux-lang.dev/docs/api/filesystem/directories#directory-iterator-next) succeeds with `none` at the end. ## Index ### Types | Name | Summary | | ------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------- | | [`AtomicWrite`](https://rux-lang.dev/docs/api/filesystem/atomic-write) | A file being written to replace `target`, which appears under that name only when it is complete. | | [`DirectoryIterator`](https://rux-lang.dev/docs/api/filesystem/directories#directory-iterator) | A directory read one entry at a time. | | [`OpenOptions`](https://rux-lang.dev/docs/api/filesystem/file#open-options) | What an open may do, and what it does about existence. | | [`File`](https://rux-lang.dev/docs/api/filesystem/file) | An owned, open file. | | [`FileStream`](https://rux-lang.dev/docs/api/filesystem/file-stream) | A stored borrow of an open file that speaks the stream interfaces. | | [`FileKind`](https://rux-lang.dev/docs/api/filesystem/metadata#file-kind) | What kind of thing a name refers to. | | [`Permissions`](https://rux-lang.dev/docs/api/filesystem/permissions) | Who may do what to a file, in both spellings the supported systems use. | | [`Metadata`](https://rux-lang.dev/docs/api/filesystem/metadata) | Everything a single query can say about a file. | | [`Capabilities`](https://rux-lang.dev/docs/api/filesystem/capabilities) | What the running system can actually answer, so a caller can ask before it assumes. | | [`TemporaryFile`](https://rux-lang.dev/docs/api/filesystem/temporary-file) | A temporary file that owns both its contents and its name. | | [`TemporaryDirectoryHandle`](https://rux-lang.dev/docs/api/filesystem/temporary-directory-handle) | A temporary directory that owns its name. | ### Functions | Name | Summary | | ------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------- | | [`WriteAtomically`](https://rux-lang.dev/docs/api/filesystem/atomic-write#write-atomically) | Replaces `target` with `contents`, atomically. | | [`MakeDirectory`](https://rux-lang.dev/docs/api/filesystem/directories#make-directory) | Creates the directory `path` names. | | [`DeleteDirectory`](https://rux-lang.dev/docs/api/filesystem/directories#delete-directory) | Deletes the empty directory `path` names; a directory with anything still in it is refused. | | [`DeleteFile`](https://rux-lang.dev/docs/api/filesystem/file-operations#delete-file) | Deletes the file `path` names. | | [`ReadDirectory`](https://rux-lang.dev/docs/api/filesystem/directories#read-directory) | Begins enumerating the directory `path` names. | | [`CurrentDirectory`](https://rux-lang.dev/docs/api/filesystem/location#current-directory) | The process's working directory, as an absolute path. | | [`SetCurrentDirectory`](https://rux-lang.dev/docs/api/filesystem/location#set-current-directory) | Makes `path` the process's working directory. | | [`Absolute`](https://rux-lang.dev/docs/api/filesystem/location#absolute) | `path` made absolute against the working directory and simplified lexically. | | [`Canonicalize`](https://rux-lang.dev/docs/api/filesystem/location#canonicalize) | The one true name of the existing file `path` refers to. | | [`CapabilitiesOfSystem`](https://rux-lang.dev/docs/api/filesystem/capabilities#capabilities-of-system) | What this system can answer. | | [`MetadataOf`](https://rux-lang.dev/docs/api/filesystem/metadata#metadata-of) | Describes the file `path` names. | | [`SetPermissions`](https://rux-lang.dev/docs/api/filesystem/permissions#set-permissions) | Sets who may do what to the file `path` names. | | [`SetTimes`](https://rux-lang.dev/docs/api/filesystem/metadata#set-times) | Sets the access and modification times of the file `path` names. | | [`TemporaryDirectory`](https://rux-lang.dev/docs/api/filesystem/temporary-file#temporary-directory) | The directory the system sets aside for temporary files. | | [`Rename`](https://rux-lang.dev/docs/api/filesystem/file-operations#rename) | Renames `from` to `to`, moving it between directories if the paths differ there. | | [`CreateHardLink`](https://rux-lang.dev/docs/api/filesystem/file-operations#create-hard-link) | Creates `link` as a hard link: a second name for the file `existing` names. | | [`CreateSymbolicLink`](https://rux-lang.dev/docs/api/filesystem/file-operations#create-symbolic-link) | Creates `link` as a symbolic link holding `target` as its text. | | [`CopyFile`](https://rux-lang.dev/docs/api/filesystem/file-operations#copy-file) | Copies the file `from` names to `to`, following a symbolic link to the bytes it points at. | | [`NativeKind`](https://rux-lang.dev/docs/api/filesystem/native-errors#native-kind) | The meaning of a platform error code on the platform this program was compiled for. | | [`TranslateNative`](https://rux-lang.dev/docs/api/filesystem/native-errors#translate-native) | A platform error code as the structured error everything here reports. | ### Constants | Name | Summary | | ---------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------- | | [`SymbolicLinkLimit`](https://rux-lang.dev/docs/api/filesystem/location#symbolic-link-limit) | How many symbolic links one canonicalization will follow before giving up. | | [`TemporaryNameAttempts`](https://rux-lang.dev/docs/api/filesystem/temporary-file#temporary-name-attempts) | How many names are tried before a temporary file gives up. | # AtomicWrite A file being written to replace `target`, which appears under that name only when it is complete. ```rux pub struct AtomicWrite { // private fields } ``` Move-only. [`Commit`](https://rux-lang.dev/docs/api/filesystem/atomic-write#commit) syncs the contents and moves them onto the target; [`Abandon`](https://rux-lang.dev/docs/api/filesystem/atomic-write#abandon), or destroying the value, deletes the partial file and leaves the target as it was. An early return therefore leaves the old contents in place, which is the behavior that makes this worth using. ## Associated functions ### `Begin` ```rux pub func Begin( allocator: Allocator, target: Path ) -> AtomicWrite ! IoError ``` Begins replacing `target`. The temporary is created in the target's own directory, which is what keeps the final rename atomic. The target need not exist; if it does, it is untouched until [`Commit`](https://rux-lang.dev/docs/api/filesystem/atomic-write#commit). | Name | Type | Description | | ----------- | ----------- | ---------------------------------------- | | `allocator` | `Allocator` | where the storage comes from | | `target` | `Path` | the path the finished contents will take | **Returns**: a write in progress against a temporary file [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FileSystem/Src/Atomic.rux#L51){rel=""nofollow""} ## Methods ### `Stream` ```rux pub func Stream(self: &var AtomicWrite) -> FileStream ``` A stored writer over the partial file. Only for a value that must keep the stream, such as a buffered writer. Writing to the replacement for the duration of a call borrows the [`AtomicWrite`](https://rux-lang.dev/docs/api/filesystem/atomic-write) itself, which is a `Writer`. The [`AtomicWrite`](https://rux-lang.dev/docs/api/filesystem/atomic-write) must outlive the result and must not be moved while it exists. See [`FileStream`](https://rux-lang.dev/docs/api/filesystem/file-stream). **Returns**: a stream over the partial file, held by address [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FileSystem/Src/Atomic.rux#L72){rel=""nofollow""} ### `Target` ```rux pub func Target(self: &AtomicWrite) -> Path ``` The name the finished file will take. **Returns**: the path the contents will take when committed [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FileSystem/Src/Atomic.rux#L79){rel=""nofollow""} ### `Commit` ```rux pub func Commit( self: &var AtomicWrite, allocator: Allocator ) -> ! IoError ``` Forces the contents to the device and moves them onto the target. The sync happens **before** the rename, so the final name can never point at contents that never arrived. Afterwards the target holds the new file and the temporary is gone; a reader that opened the name at any moment saw the old file or the new one. What this does not promise is that the directory entry survives a crash: that needs the containing directory synced too, which Windows does not offer, so the guarantee stops at atomicity on every system rather than being durable on some and pretending on the rest. | Name | Type | Description | | ----------- | ----------- | ---------------------------- | | `allocator` | `Allocator` | where the storage comes from | **Returns**: success when the target now holds the contents; on failure it still holds the old ones [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FileSystem/Src/Atomic.rux#L93){rel=""nofollow""} ### `Abandon` ```rux pub func Abandon( self: &var AtomicWrite, allocator: Allocator ) -> ! IoError ``` Throws the partial file away and leaves the target as it was. | Name | Type | Description | | ----------- | ----------- | ---------------------------- | | `allocator` | `Allocator` | where the storage comes from | **Returns**: success when the temporary file was removed and the target left alone [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FileSystem/Src/Atomic.rux#L110){rel=""nofollow""} ### `Release` ```rux pub func Release(self: &var AtomicWrite) ``` Gives the buffers back. The temporary's own destructor removes any partial file. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FileSystem/Src/Atomic.rux#L118){rel=""nofollow""} ## Implements Writer `AtomicWrite` conforms to `Writer`. ### `Write` ```rux pub func Write( self: &var AtomicWrite, bytes: char8[..] ) -> uint ! IoError ``` Writes into the partial file. Writing to a replacement is what the type is for, so it is a `Writer` itself rather than something a caller reaches a stream out of: `let sink: &var Writer = replacement;` borrows it, and nothing has to be kept alive beside it. One attempt, partial on purpose, exactly as the underlying file's is; `WriteAll` does the looping. | Name | Type | Description | | ------- | ----------- | ---------------- | | `bytes` | `char8[..]` | the run to write | **Returns**: how much of it the file took [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FileSystem/Src/Atomic.rux#L141){rel=""nofollow""} ### `Flush` ```rux pub func Flush(self: &var AtomicWrite) -> ! IoError ``` Flushes the partial file, which holds nothing back. [`Commit`](https://rux-lang.dev/docs/api/filesystem/atomic-write#commit) is what makes the contents durable, and it syncs before it renames. **Returns**: what the file reported [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FileSystem/Src/Atomic.rux#L149){rel=""nofollow""} ## Destructor ```rux func ~AtomicWrite(self: &var AtomicWrite) ``` Discards an uncommitted replacement, leaving the target untouched. This is the property that makes the type worth using: an early return or a failure part-way through writing leaves the old contents exactly where they were, with no partial file left behind. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FileSystem/Src/Atomic.rux#L126){rel=""nofollow""} ## Related ### `WriteAtomically` ```rux pub func WriteAtomically( allocator: Allocator, target: Path, contents: char8[..] ) -> ! IoError ``` Replaces `target` with `contents`, atomically. The one-shot form of the type above, for the common case where the whole file is already in hand. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FileSystem/Src/Atomic.rux#L161){rel=""nofollow""} **Parameters** | Name | Type | Description | | ----------- | ----------- | ---------------------------------------- | | `allocator` | `Allocator` | where the storage comes from | | `target` | `Path` | the path the finished contents will take | | `contents` | `char8[..]` | the bytes the file should end up holding | **Returns**: success when the target now holds exactly `contents` # Capabilities What the running system can actually answer, so a caller can ask before it assumes. ```rux pub struct Capabilities { pub unixPermissions: bool; pub creationTime: bool; // private fields } ``` ## Fields | Name | Type | Description | | ----------------- | ------ | ----------------------------------------------------------------------------------------------- | | `unixPermissions` | `bool` | Whether `Permissions::mode` is the system's own answer rather than one synthesized from a flag. | | `creationTime` | `bool` | Whether the system records a creation time. | ## Related ### `CapabilitiesOfSystem` ```rux pub func CapabilitiesOfSystem() -> Capabilities ``` What this system can answer. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FileSystem/Src/Metadata.rux#L117){rel=""nofollow""} **Returns**: what this system's metadata actually carries, so a caller can tell an absent value from a false one # File An owned, open file. ```rux pub struct File { // private fields } ``` Move-only: the handle closes exactly once, through [`Close`](https://rux-lang.dev/docs/api/filesystem/file#close) or through its destructor. [`Close`](https://rux-lang.dev/docs/api/filesystem/file#close) is the error-visible path; destruction discards the outcome, which is fine for a file that was read and a silent loss for one that was written. ## Associated functions ### `Open` ```rux pub func Open( allocator: Allocator, path: Path, options: OpenOptions ) -> File ! IoError ``` Opens `path` under `options`. The allocator is borrowed for the platform form of the path and holds nothing afterward. A failure says why in the platform's own terms, translated. | Name | Type | Description | | ----------- | ------------- | -------------------------------------------------------------- | | `allocator` | `Allocator` | where the storage comes from | | `path` | `Path` | the path to act on | | `options` | `OpenOptions` | what may be done with the file, and what to do about existence | **Returns**: the open file [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FileSystem/Src/File.rux#L165){rel=""nofollow""} ## Methods ### `IsOpen` ```rux pub func IsOpen(self: &File) -> bool ``` Whether the handle is still open. **Returns**: whether the file is open [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FileSystem/Src/File.rux#L234){rel=""nofollow""} ### `Close` ```rux pub func Close(self: &var File) -> ! IoError ``` Closes the handle and reports what the platform said. Closing twice is not an error here: the second call is a no-op reporting success, because the first already gave the handle back. This is the error-visible path; a written file deserves it. **Returns**: success when the descriptor was released; closing twice is not an error [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FileSystem/Src/File.rux#L243){rel=""nofollow""} ### `Sync` ```rux pub func Sync(self: &var File) -> ! IoError ``` Forces everything written through to the storage device. Not "handed to the kernel" but "acknowledged by the device": the promise that holds through a power failure, and the one a caller who just wrote something they cannot lose actually wants. **Returns**: success when the system reported the data durable [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FileSystem/Src/File.rux#L125){rel=""nofollow""} ### `Size` ```rux pub func Size(self: &var File) -> uint64 ! IoError ``` The file's length in bytes. On the Unix systems this is measured by seeking to the end and back, which moves the shared kernel position for a moment; a reader racing this on the same open file may see it. The stat-based answer arrives with the metadata work. **Returns**: the file's size in bytes [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FileSystem/Src/File.rux#L142){rel=""nofollow""} ### `SetLength` ```rux pub func SetLength( self: &var File, length: uint64 ) -> ! IoError ``` Sets the file's length: shrinking discards what was past the new end, growing leaves a hole. The position does not move. A position past the new end stays where it was, and the next write there grows the file again — the same rule as seeking past the end. | Name | Type | Description | | -------- | -------- | ---------------------------------------- | | `length` | `uint64` | the size the file should have afterwards | **Returns**: success when the file is that size; extending reads back as zeros [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FileSystem/Src/File.rux#L166){rel=""nofollow""} ### `Stream` ```rux pub func Stream(self: *var File) -> FileStream ``` A stored borrow of this file, for a value that must keep a stream beyond one call. For anything that only needs a stream for the duration of a call, borrow the file directly as `let sink: &var Writer = file;` instead: that is checked, and this is not. The file must outlive the result and must not be moved while it exists. See [`FileStream`](https://rux-lang.dev/docs/api/filesystem/file-stream). **Returns**: a stream over this file, holding its address, which is what makes it storable [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FileSystem/Src/File.rux#L195){rel=""nofollow""} ### `Metadata` ```rux pub func Metadata(self: &File) -> Metadata ! IoError ``` Describes this open file. Answers about the file the handle holds, so nothing can rename or replace the name out from under the query the way a path-based one can. **Returns**: what the system knows about the open file [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FileSystem/Src/File.rux#L391){rel=""nofollow""} ## Implements Reader `File` conforms to `Reader`. ### `Read` ```rux pub func Read( self: &var File, into: var char8[..] ) -> uint ! IoError ``` Reads what one attempt yields into `into`; a short count is not an error and the end is `EndOfStream`. | Name | Type | Description | | ------ | --------------- | ------------------ | | `into` | `var char8[..]` | receives the bytes | **Returns**: how many bytes were read; `IsEnd` at the end of the file [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FileSystem/Src/File.rux#L31){rel=""nofollow""} ## Implements Writer `File` conforms to `Writer`. ### `Write` ```rux pub func Write( self: &var File, bytes: char8[..] ) -> uint ! IoError ``` Writes what one attempt takes of `bytes`; a short count means call again, which `WriteAll` does. | Name | Type | Description | | ------- | ----------- | ------------------ | | `bytes` | `char8[..]` | the bytes to write | **Returns**: how many bytes were taken, which may be fewer than offered [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FileSystem/Src/File.rux#L60){rel=""nofollow""} ### `Flush` ```rux pub func Flush(self: &var File) -> ! IoError ``` Nothing: these writes hold nothing back. Durability is [`Sync`](https://rux-lang.dev/docs/api/filesystem/file#sync), which is a different promise. **Returns**: success when everything written reached the system [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FileSystem/Src/File.rux#L81){rel=""nofollow""} ## Implements Seeker `File` conforms to `Seeker`. ### `Seek` ```rux pub func Seek( self: &var File, origin: SeekFrom, offset: int64 ) -> uint64 ! IoError ``` Moves the position `offset` bytes from `origin` and reports where it landed. A position before the start of the file is refused by the platform; one past the end is allowed, and a later write there leaves a hole. A handle opened for appending still seeks — but its writes land at the end regardless, because append is a property of the writes, not of the position. | Name | Type | Description | | -------- | ---------- | --------------------------------- | | `origin` | `SeekFrom` | where the offset is measured from | | `offset` | `int64` | how far to move | **Returns**: the resulting offset from the start [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FileSystem/Src/File.rux#L95){rel=""nofollow""} ## Destructor ```rux func ~File(self: &var File) ``` Closes with the outcome discarded: the safety net, not the contract. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FileSystem/Src/File.rux#L256){rel=""nofollow""} ## Related ### `OpenOptions` ```rux pub struct OpenOptions { pub write: bool; pub truncate: bool; pub create: bool; pub createNew: bool; // private fields } ``` What an open may do, and what it does about existence. `read`, `write` and `append` say what may happen through the handle; `create`, `createNew` and `truncate` say what happens to the file itself. `append` positions every write at the end, whatever was written in between, which is the property log writers need and `write` alone does not have. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FileSystem/Src/File.rux#L41){rel=""nofollow""} **Fields** | Name | Type | Description | | ----------- | ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `write` | `bool` | The handle may write. | | `truncate` | `bool` | An existing file's contents are discarded on open. Requires `write`. | | `create` | `bool` | A missing file is created. Requires `write` or `append`. | | `createNew` | `bool` | The file must not exist: it is created, and an existing one is `AlreadyExists`. Wins over `create` and `truncate`, and is the option that makes creation a claim rather than a race. | **Constructors** #### `OpenOptions` ```rux pub func OpenOptions() -> OpenOptions ``` Nothing at all: the caller states every intention. **Returns**: options that permit nothing, which must be added to before opening [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FileSystem/Src/File.rux#L61){rel=""nofollow""} **Associated functions** #### `Reading` ```rux pub func Reading() -> OpenOptions ``` Reading an existing file. **Returns**: options that open an existing file for reading [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FileSystem/Src/File.rux#L68){rel=""nofollow""} #### `Writing` ```rux pub func Writing() -> OpenOptions ``` Writing a file from its beginning: created if missing, emptied if not. **Returns**: options that create or truncate a file for writing [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FileSystem/Src/File.rux#L77){rel=""nofollow""} #### `Appending` ```rux pub func Appending() -> OpenOptions ``` Adding to a file's end: created if missing, appended to if not. **Returns**: options that create or open a file and write at its end [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FileSystem/Src/File.rux#L88){rel=""nofollow""} # FileStream A stored borrow of an open file that speaks the stream interfaces. ```rux pub struct FileStream { // private fields } ``` **Reach for this only when a stream has to be kept.** A [`File`](https://rux-lang.dev/docs/api/filesystem/file) already implements `Reader`, `Writer` and `Seeker`, so anything taking one for the duration of a call takes the file itself: ```rux let sink: &var Writer = file; WriteAll(sink, contents); ``` That borrows, and the file is still the caller's afterwards. What it cannot do is outlive the call, because a reference cannot be stored in a field — so a `BufferedReader`, which keeps its source, needs a value it can hold. Binding the file itself into an interface value would move it, since a [`File`](https://rux-lang.dev/docs/api/filesystem/file) owns its handle and prohibits copying, and the caller would no longer have a file to close. This is the value that fills that gap: it holds the file's address rather than the file, so it can be stored, and the file stays where it is. The address is private, and [`File::Stream`](https://rux-lang.dev/docs/api/filesystem/file#stream) is the only way to obtain one. That is deliberate: a `FileStream` assembled from an arbitrary pointer would be an unchecked promise about a file that may not exist, and the type is already the least checkable thing in this package without adding a second way to get it wrong. The file must outlive the stream, and must not be moved while one exists — a move relocates the file and leaves the stored address pointing at where it used to be. Nothing here tracks either, which is exactly why this is not the default way to reach a file's streams. A stream over a closed file is not unsafe: every operation refuses with `InvalidHandle`, because the file itself checks. ## Implements Reader `FileStream` conforms to `Reader`. ### `Read` ```rux pub func Read( self: &var FileStream, into: var char8[..] ) -> uint ! IoError ``` Reads through the borrowed file. | Name | Type | Description | | ------ | --------------- | ------------------ | | `into` | `var char8[..]` | receives the bytes | **Returns**: how many bytes were read; `IsEnd` at the end of the file [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FileSystem/Src/FileStream.rux#L230){rel=""nofollow""} ## Implements Writer `FileStream` conforms to `Writer`. ### `Write` ```rux pub func Write( self: &var FileStream, bytes: char8[..] ) -> uint ! IoError ``` Writes through the borrowed file. | Name | Type | Description | | ------- | ----------- | ------------------ | | `bytes` | `char8[..]` | the bytes to write | **Returns**: how many bytes were taken, which may be fewer than offered [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FileSystem/Src/FileStream.rux#L240){rel=""nofollow""} ### `Flush` ```rux pub func Flush(self: &var FileStream) -> ! IoError ``` Flushes the borrowed file, which holds nothing back. **Returns**: success when everything written reached the system [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FileSystem/Src/FileStream.rux#L247){rel=""nofollow""} ## Implements Seeker `FileStream` conforms to `Seeker`. ### `Seek` ```rux pub func Seek( self: &var FileStream, origin: SeekFrom, offset: int64 ) -> uint64 ! IoError ``` Seeks the borrowed file. | Name | Type | Description | | -------- | ---------- | --------------------------------- | | `origin` | `SeekFrom` | where the offset is measured from | | `offset` | `int64` | how far to move | **Returns**: the resulting offset from the start [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FileSystem/Src/FileStream.rux#L258){rel=""nofollow""} # Metadata Everything a single query can say about a file. ```rux pub struct Metadata { pub kind: FileKind; pub size: uint64; pub linkCount: uint64; pub permissions: Permissions; pub accessed: Timestamp; pub modified: Timestamp; pub hasCreated: bool; // private fields } ``` ## Fields | Name | Type | Description | | ------------- | ------------- | -------------------------------------------------------------------------------- | | `kind` | `FileKind` | What the name refers to. | | `size` | `uint64` | The length in bytes; zero for a directory, whose size means nothing portable. | | `linkCount` | `uint64` | How many names the content has. Always one on a system that does not count them. | | `permissions` | `Permissions` | Who may do what. | | `accessed` | `Timestamp` | When the contents were last read. | | `modified` | `Timestamp` | When the contents were last written. | | `hasCreated` | `bool` | Whether `created` means anything. | ## Related ### `FileKind` ```rux pub enum FileKind: int32 { File = 0, Directory = 1, SymbolicLink = 2, Other = 3 } ``` What kind of thing a name refers to. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FileSystem/Src/Metadata.rux#L31){rel=""nofollow""} **Cases** | Name | Value | Description | | -------------- | ----- | --------------------------------------------------------------------------------------------------- | | `File` | `0` | An ordinary file of bytes. | | `Directory` | `1` | A directory. | | `SymbolicLink` | `2` | A symbolic link — only ever reported by a no-follow query, since following one lands on its target. | | `Other` | `3` | A device, socket, pipe, or anything else the filesystem holds that is none of the above. | ### `MetadataOf` ```rux pub func MetadataOf( allocator: Allocator, path: Path, followLinks: bool ) -> Metadata ! IoError ``` Describes the file `path` names. `followLinks` decides what a symbolic link at the end of the path means: following it describes the target, and not following it describes the link, which is the only way `SymbolicLink` is ever reported. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FileSystem/Src/Metadata.rux#L362){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------------- | ----------- | --------------------------------------------------------------- | | `allocator` | `Allocator` | where the storage comes from | | `path` | `Path` | the path to act on | | `followLinks` | `bool` | whether a final symbolic link is followed rather than described | **Returns**: what the system knows about the path ### `SetTimes` ```rux pub func SetTimes( allocator: Allocator, path: Path, accessed: Timestamp, modified: Timestamp, followLinks: bool ) -> ! IoError ``` Sets the access and modification times of the file `path` names. Creation time is not settable here: Windows would allow it and the Unix systems would not, and an operation that silently means different things on different systems is worse than one that is not offered. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FileSystem/Src/Metadata.rux#L456){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------------- | ----------- | --------------------------------------------------------------- | | `allocator` | `Allocator` | where the storage comes from | | `path` | `Path` | the path to act on | | `accessed` | `Timestamp` | the access time to set, or `None` to leave it | | `modified` | `Timestamp` | the modification time to set, or `None` to leave it | | `followLinks` | `bool` | whether a final symbolic link is followed rather than described | **Returns**: success when the times were applied # Permissions Who may do what to a file, in both spellings the supported systems use. ```rux pub struct Permissions { pub mode: uint32; // private fields } ``` `mode` is the Unix permission bits, the low nine of which are the owner/group/other triple. `readOnly` is Windows' one portable attribute. Both are always filled: on Windows the mode is synthesized from the attribute (`0o444` when read-only, `0o666` otherwise) so a program that reasons in Unix terms is not blocked, and on Unix `readOnly` reports whether the owner-write bit is clear. [`Capabilities`](https://rux-lang.dev/docs/api/filesystem/capabilities) says which one is real. ## Fields | Name | Type | Description | | ------ | -------- | ------------------------- | | `mode` | `uint32` | The Unix permission bits. | ## Associated functions ### `FromMode` ```rux pub func FromMode(mode: uint32) -> Permissions ``` Permissions from Unix mode bits, with `readOnly` derived from the owner-write bit. | Name | Type | Description | | ------ | -------- | ------------------- | | `mode` | `uint32` | the permission bits | **Returns**: permissions carrying those bits [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FileSystem/Src/Metadata.rux#L60){rel=""nofollow""} ### `FromReadOnly` ```rux pub func FromReadOnly(readOnly: bool) -> Permissions ``` Permissions from the read-only flag alone, with the mode synthesized from it. | Name | Type | Description | | ---------- | ------ | --------------------------------- | | `readOnly` | `bool` | whether the file may only be read | **Returns**: permissions that are writable or not, which is all Windows records [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FileSystem/Src/Metadata.rux#L68){rel=""nofollow""} ## Methods ### `IsWritable` ```rux pub func IsWritable(self: &Permissions) -> bool ``` Whether the owner may write. **Returns**: whether the owner may write the file [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FileSystem/Src/Metadata.rux#L75){rel=""nofollow""} ## Related ### `SetPermissions` ```rux pub func SetPermissions( allocator: Allocator, path: Path, permissions: Permissions ) -> ! IoError ``` Sets who may do what to the file `path` names. On the Unix systems the mode bits are written as given. On Windows only the read-only attribute exists, so that alone is written and the rest of `permissions` is ignored — ask [`CapabilitiesOfSystem`](https://rux-lang.dev/docs/api/filesystem/capabilities#capabilities-of-system) first if the difference matters. A symbolic link is always followed: its own bits mean nothing on any supported system. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FileSystem/Src/Metadata.rux#L417){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------------- | ------------- | ---------------------------- | | `allocator` | `Allocator` | where the storage comes from | | `path` | `Path` | the path to act on | | `permissions` | `Permissions` | the permissions to apply | **Returns**: success when the permissions were applied # TemporaryDirectoryHandle A temporary directory that owns its name. ```rux pub struct TemporaryDirectoryHandle { // private fields } ``` Move-only, with the same contract as [`TemporaryFile`](https://rux-lang.dev/docs/api/filesystem/temporary-file): [`Close`](https://rux-lang.dev/docs/api/filesystem/temporary-directory-handle#close) removes it and reports, destruction removes it quietly, [`Keep`](https://rux-lang.dev/docs/api/filesystem/temporary-directory-handle#keep) gives up ownership. Removal is of the directory itself and requires it to be empty — nothing here deletes a tree, because a temporary directory that silently erased whatever a caller put inside it would be a worse surprise than a refusal. ## Associated functions ### `Create` ```rux pub func Create( allocator: Allocator, directory: Path, prefix: char8[..] ) -> TemporaryDirectoryHandle ! IoError ``` Creates a new temporary directory in `directory`, named from `prefix` and sixteen hex digits of entropy. | Name | Type | Description | | ----------- | ----------- | --------------------------------------- | | `allocator` | `Allocator` | where the storage comes from | | `directory` | `Path` | the directory to create it in | | `prefix` | `char8[..]` | the text the generated name starts with | **Returns**: the created directory, which is removed when closed unless kept [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FileSystem/Src/Temporary.rux#L202){rel=""nofollow""} ## Methods ### `AsPath` ```rux pub func AsPath(self: &TemporaryDirectoryHandle) -> Path ``` The directory's path, for building names inside it. **Returns**: the path it was created at [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FileSystem/Src/Temporary.rux#L228){rel=""nofollow""} ### `Close` ```rux pub func Close( self: &var TemporaryDirectoryHandle, allocator: Allocator ) -> ! IoError ``` Removes the directory and reports what the removal said. | Name | Type | Description | | ----------- | ----------- | ---------------------------- | | `allocator` | `Allocator` | where the storage comes from | **Returns**: success when it was removed [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FileSystem/Src/Temporary.rux#L236){rel=""nofollow""} ### `Keep` ```rux pub func Keep(self: &var TemporaryDirectoryHandle) ``` Leaves the directory where it is, giving up the name. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FileSystem/Src/Temporary.rux#L248){rel=""nofollow""} ## Destructor ```rux func ~TemporaryDirectoryHandle(self: &var TemporaryDirectoryHandle) ``` Removes the directory with the outcome discarded: the safety net, not the contract. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FileSystem/Src/Temporary.rux#L254){rel=""nofollow""} # TemporaryFile A temporary file that owns both its contents and its name. ```rux pub struct TemporaryFile { pub file: File; // private fields } ``` Move-only. [`Close`](https://rux-lang.dev/docs/api/filesystem/temporary-file#close) deletes the file and reports what the deletion said; destruction does the same with the outcome discarded. [`Keep`](https://rux-lang.dev/docs/api/filesystem/temporary-file#keep) gives up ownership of the name instead, for the caller who has decided the file should outlive this value — which is what a rename into place is built on. ## Fields | Name | Type | Description | | ------ | ------ | -------------- | | `file` | `File` | The open file. | ## Associated functions ### `Create` ```rux pub func Create( allocator: Allocator, directory: Path, prefix: char8[..] ) -> TemporaryFile ! IoError ``` Creates a new temporary file in `directory`, named from `prefix` and sixteen hex digits of entropy. The file is opened for reading and writing and is created, never opened: a name that already exists is a collision, and the next name is tried. | Name | Type | Description | | ----------- | ----------- | --------------------------------------- | | `allocator` | `Allocator` | where the storage comes from | | `directory` | `Path` | the directory to create it in | | `prefix` | `char8[..]` | the text the generated name starts with | **Returns**: the created file, which is removed when closed unless kept [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FileSystem/Src/Temporary.rux#L105){rel=""nofollow""} ## Methods ### `AsPath` ```rux pub func AsPath(self: &TemporaryFile) -> Path ``` The file's path, for handing to something that needs a name. **Returns**: the path it was created at [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FileSystem/Src/Temporary.rux#L136){rel=""nofollow""} ### `Close` ```rux pub func Close( self: &var TemporaryFile, allocator: Allocator ) -> ! IoError ``` Closes the file and deletes it, reporting the first thing that went wrong. | Name | Type | Description | | ----------- | ----------- | ---------------------------- | | `allocator` | `Allocator` | where the storage comes from | **Returns**: success when it was removed [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FileSystem/Src/Temporary.rux#L144){rel=""nofollow""} ### `Keep` ```rux pub func Keep(self: &var TemporaryFile) -> ! IoError ``` Closes the file and leaves it where it is, giving up the name. **Returns**: success when it will be left in place rather than removed [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FileSystem/Src/Temporary.rux#L159){rel=""nofollow""} ## Destructor ```rux func ~TemporaryFile(self: &var TemporaryFile) ``` Closes and deletes with the outcome discarded: the safety net, not the contract. A destructor has nowhere to report a failed deletion, so a caller who needs to know calls [`Close`](https://rux-lang.dev/docs/api/filesystem/temporary-file#close). What this guarantees is that a temporary file is never left behind by an early return or a failure path, which is the reason the type exists. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FileSystem/Src/Temporary.rux#L169){rel=""nofollow""} ## Related ### `TemporaryNameAttempts` ```rux pub const TemporaryNameAttempts: uint = 4; ``` How many names are tried before a temporary file gives up. With 128 bits of name, one collision is already a surprise and three in a row is not chance; failing is the honest response to an entropy source that has stopped being one. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FileSystem/Src/Temporary.rux#L26){rel=""nofollow""} ### `TemporaryDirectory` ```rux pub func TemporaryDirectory(allocator: Allocator) -> PathBuffer ! IoError ``` The directory the system sets aside for temporary files. On Windows this is what the platform reports, which consults `TMP`, `TEMP` and `USERPROFILE` in turn. On the Unix systems it is `/tmp`: reading `TMPDIR` needs environment access this package does not have yet, so a caller who must honor it passes the directory to the functions below instead. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FileSystem/Src/Temporary.rux#L35){rel=""nofollow""} **Parameters** | Name | Type | Description | | ----------- | ----------- | ---------------------------- | | `allocator` | `Allocator` | where the storage comes from | **Returns**: the system's directory for temporary files # Directories Creating, deleting and listing directories. ## `MakeDirectory` ```rux pub func MakeDirectory( allocator: Allocator, path: Path ) -> ! IoError ``` Creates the directory `path` names. Its parent must already exist; `AlreadyExists` if the name is taken. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FileSystem/Src/Directory.rux#L28){rel=""nofollow""} **Parameters** | Name | Type | Description | | ----------- | ----------- | ---------------------------- | | `allocator` | `Allocator` | where the storage comes from | | `path` | `Path` | the path to act on | **Returns**: success when the directory now exists ## `DeleteDirectory` ```rux pub func DeleteDirectory( allocator: Allocator, path: Path ) -> ! IoError ``` Deletes the empty directory `path` names; a directory with anything still in it is refused. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FileSystem/Src/Directory.rux#L50){rel=""nofollow""} **Parameters** | Name | Type | Description | | ----------- | ----------- | ---------------------------- | | `allocator` | `Allocator` | where the storage comes from | | `path` | `Path` | the path to act on | **Returns**: success when the directory is gone ## `DirectoryIterator` ```rux pub struct DirectoryIterator { // private fields } ``` A directory read one entry at a time. Move-only: [`Release`](https://rux-lang.dev/docs/api/filesystem/directories#directory-iterator-release) (or destruction) gives back the platform handle and the record buffer. [`Next`](https://rux-lang.dev/docs/api/filesystem/directories#directory-iterator-next) hands each name over as a fresh `OsString` owned by the caller. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FileSystem/Src/Directory.rux#L91){rel=""nofollow""} **Methods** ### `Next` ```rux pub func Next(self: &var DirectoryIterator) -> OsString? ! IoError ``` Hands over the next entry's name, or reports that the directory is done. Succeeds with a name freshly owned by the caller, or with `none` at the end; a failure says what stopped the enumeration. The `.` and `..` entries are skipped. **Returns**: the next entry's name, or `none` when the directory is done [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FileSystem/Src/Directory.rux#L194){rel=""nofollow""} ### `Release` ```rux pub func Release(self: &var DirectoryIterator) ``` Gives back the handle and the buffer. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FileSystem/Src/Directory.rux#L285){rel=""nofollow""} **Destructor** ### `~DirectoryIterator` ```rux func ~DirectoryIterator(self: &var DirectoryIterator) ``` [`Release`](https://rux-lang.dev/docs/api/filesystem/directories#directory-iterator-release), as the safety net. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FileSystem/Src/Directory.rux#L305){rel=""nofollow""} ## `ReadDirectory` ```rux pub func ReadDirectory( allocator: Allocator, path: Path ) -> DirectoryIterator ! IoError ``` Begins enumerating the directory `path` names. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FileSystem/Src/Directory.rux#L125){rel=""nofollow""} **Parameters** | Name | Type | Description | | ----------- | ----------- | ---------------------------- | | `allocator` | `Allocator` | where the storage comes from | | `path` | `Path` | the path to act on | **Returns**: a cursor over the directory's entries # File operations Deleting, renaming, copying and linking files by name. ## `DeleteFile` ```rux pub func DeleteFile( allocator: Allocator, path: Path ) -> ! IoError ``` Deletes the file `path` names. Removing the name does not disturb any handle still open on the file. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FileSystem/Src/Directory.rux#L71){rel=""nofollow""} **Parameters** | Name | Type | Description | | ----------- | ----------- | ---------------------------- | | `allocator` | `Allocator` | where the storage comes from | | `path` | `Path` | the path to act on | **Returns**: success when the file is gone ## `Rename` ```rux pub func Rename( allocator: Allocator, from: Path, to: Path ) -> ! IoError ``` Renames `from` to `to`, moving it between directories if the paths differ there. An existing `to` is replaced, atomically within one volume: a reader sees the old file or the new, never a gap. Across volumes Windows copies and deletes instead — not atomic — and the Unix systems refuse. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FileSystem/Src/Transfer.rux#L30){rel=""nofollow""} **Parameters** | Name | Type | Description | | ----------- | ----------- | ---------------------------------- | | `allocator` | `Allocator` | where the storage comes from | | `from` | `Path` | the path that exists now | | `to` | `Path` | the path it should have afterwards | **Returns**: success when the file is at its new path ## `CreateHardLink` ```rux pub func CreateHardLink( allocator: Allocator, existing: Path, link: Path ) -> ! IoError ``` Creates `link` as a hard link: a second name for the file `existing` names. The two names are then equals — neither is "the original" — and the content lives until the last name is deleted. A symbolic link at `existing` is not followed: the link is made to the name given. Directories cannot be hard-linked on any supported system. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FileSystem/Src/Transfer.rux#L57){rel=""nofollow""} **Parameters** | Name | Type | Description | | ----------- | ----------- | ---------------------------- | | `allocator` | `Allocator` | where the storage comes from | | `existing` | `Path` | the file that exists now | | `link` | `Path` | the link to create | **Returns**: success when the new name refers to the same file ## `CreateSymbolicLink` ```rux pub func CreateSymbolicLink( allocator: Allocator, target: Path, link: Path, targetIsDirectory: bool ) -> ! IoError ``` Creates `link` as a symbolic link holding `target` as its text. The target is stored, not checked: a dangling link is created as readily as a good one. `targetIsDirectory` matters only on Windows, which types its links; the Unix systems ignore it. Windows also gates creation behind a privilege unless the machine runs Developer Mode, so `PermissionDenied` here is an environment, not a bug. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FileSystem/Src/Transfer.rux#L86){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------------------- | ----------- | ------------------------------------------------------------------------ | | `allocator` | `Allocator` | where the storage comes from | | `target` | `Path` | the path the link will point at, which need not exist | | `link` | `Path` | the link to create | | `targetIsDirectory` | `bool` | whether the target is a directory, which Windows must be told in advance | **Returns**: success when the link was created; Windows needs a privilege for this ## `CopyFile` ```rux pub func CopyFile( allocator: Allocator, from: Path, to: Path ) -> ! IoError ``` Copies the file `from` names to `to`, following a symbolic link to the bytes it points at. An existing `to` is replaced. The copy is the bytes and nothing else: permissions, timestamps and the rest of the metadata are the destination's own, fresh — carrying them is a policy the metadata work owns. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FileSystem/Src/Transfer.rux#L116){rel=""nofollow""} **Parameters** | Name | Type | Description | | ----------- | ----------- | ---------------------------------- | | `allocator` | `Allocator` | where the storage comes from | | `from` | `Path` | the path that exists now | | `to` | `Path` | the path it should have afterwards | **Returns**: success when the destination holds a copy # Working directory The process's current directory, and a path made absolute or canonical against it. ## `SymbolicLinkLimit` ```rux pub const SymbolicLinkLimit: uint = 40; ``` How many symbolic links one canonicalization will follow before giving up. A link that points at itself, or at a chain that returns to it, would otherwise be followed forever. The limit is what every system uses for the same reason, and reaching it is reported as `LimitExceeded`. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FileSystem/Src/Location.rux#L30){rel=""nofollow""} ## `CurrentDirectory` ```rux pub func CurrentDirectory(allocator: Allocator) -> OsString ! IoError ``` The process's working directory, as an absolute path. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FileSystem/Src/Location.rux#L36){rel=""nofollow""} **Parameters** | Name | Type | Description | | ----------- | ----------- | ---------------------------- | | `allocator` | `Allocator` | where the storage comes from | **Returns**: the working directory ## `SetCurrentDirectory` ```rux pub func SetCurrentDirectory( allocator: Allocator, path: Path ) -> ! IoError ``` Makes `path` the process's working directory. Process-wide and immediately visible to every thread, which invalidates every relative path any of them was about to resolve. Nothing in this package calls it. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FileSystem/Src/Location.rux#L66){rel=""nofollow""} **Parameters** | Name | Type | Description | | ----------- | ----------- | ---------------------------- | | `allocator` | `Allocator` | where the storage comes from | | `path` | `Path` | the path to act on | **Returns**: success when the working directory changed ## `Absolute` ```rux pub func Absolute( allocator: Allocator, path: Path ) -> PathBuffer ! IoError ``` `path` made absolute against the working directory and simplified lexically. Arithmetic, not a question for the filesystem: the path need not exist, nothing is opened, and no symbolic link is resolved — so a `..` that crosses one is simplified away as though it did not. [`Canonicalize`](https://rux-lang.dev/docs/api/filesystem/location#canonicalize) is the operation that tells the truth about links, at the cost of requiring the file to be there. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FileSystem/Src/Location.rux#L90){rel=""nofollow""} **Parameters** | Name | Type | Description | | ----------- | ----------- | ---------------------------- | | `allocator` | `Allocator` | where the storage comes from | | `path` | `Path` | the path to act on | **Returns**: the path made absolute without touching the file system ## `Canonicalize` ```rux pub func Canonicalize( allocator: Allocator, path: Path ) -> PathBuffer ! IoError ``` The one true name of the existing file `path` refers to. Every symbolic link is resolved, every `.` and `..` is applied against what those links actually mean, and the result is absolute. Unlike [`Absolute`](https://rux-lang.dev/docs/api/filesystem/location#absolute), the file must exist: this is a question for the filesystem, and a name with nothing behind it has no true form. A link chain that returns to itself is `LimitExceeded` rather than a hang. On Windows the answer arrives in the verbatim form and spelled as the filesystem stores it — the case the name actually has, short names expanded — because that is what the system reports, and rewriting it would be this package guessing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FileSystem/Src/Location.rux#L218){rel=""nofollow""} **Parameters** | Name | Type | Description | | ----------- | ----------- | ---------------------------- | | `allocator` | `Allocator` | where the storage comes from | | `path` | `Path` | the path to act on | **Returns**: the path with every link and relative component resolved, which needs the file system and so can fail # Native error codes A platform's own error code, read as the IoError every operation here reports. ## `NativeKind` ```rux pub func NativeKind(raw: int32) -> IoErrorKind ``` The meaning of a platform error code on the platform this program was compiled for. Codes with no portable meaning translate to `Other`; the caller still has the raw code beside it. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FileSystem/Src/Translate.rux#L17){rel=""nofollow""} **Parameters** | Name | Type | Description | | ----- | ------- | --------------------------------------- | | `raw` | `int32` | the platform's own error number or code | **Returns**: the kind this package gives that platform code ## `TranslateNative` ```rux pub func TranslateNative(raw: int32) -> IoError ``` A platform error code as the structured error everything here reports. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FileSystem/Src/Translate.rux#L76){rel=""nofollow""} **Parameters** | Name | Type | Description | | ----- | ------- | --------------------------------------- | | `raw` | `int32` | the platform's own error number or code | **Returns**: the error this package gives that platform code, keeping the raw value # Path Native operating-system strings and filesystem paths. ## Installation Add `Path` to the `[Dependencies]` table of your package's `Rux.toml`: ```toml [Dependencies] Path = { Namespace = "Rux", Version = "0.1.0" } ``` Standard packages are declared by hand: the registry does not serve them, so `rux add Rux/Path` cannot add them. ## Dependencies - [`Allocator`](https://rux-lang.dev/docs/api/allocator) 0.1.0 - [`Core`](https://rux-lang.dev/docs/api/core) 0.1.0 - [`Memory`](https://rux-lang.dev/docs/api/memory) 0.1.0 - [`Text`](https://rux-lang.dev/docs/api/text) 0.1.0 ## Guide ### What it provides - **[`OsString`](https://rux-lang.dev/docs/api/path/os-string) and [`OsStringView`](https://rux-lang.dev/docs/api/path/os-string-view)** — text as the operating system actually stores it: arbitrary bytes on the Unix systems, arbitrary UTF-16 code units on Windows, unpaired surrogates included. Lossless by construction: whatever name the system hands over survives the round trip, whether or not it is valid text. Conversion **from** UTF-8 always succeeds; conversion **to** UTF-8 is fallible, because the system's names are under no obligation to be text. - **[`Path`](https://rux-lang.dev/docs/api/path/path) and [`PathBuffer`](https://rux-lang.dev/docs/api/path/path-buffer)** — borrowed structure and the owning, growable buffer; component iteration where separator runs count once and an absolute path opens with an empty root component. - **Parts and joins** — [`Parent`](https://rux-lang.dev/docs/api/path/path#parent), [`FileName`](https://rux-lang.dev/docs/api/path/path#file-name), [`Stem`](https://rux-lang.dev/docs/api/path/path#stem), [`Extension`](https://rux-lang.dev/docs/api/path/path#extension), [`Join`](https://rux-lang.dev/docs/api/path/path-buffer#join), and lexical [`Normalize`](https://rux-lang.dev/docs/api/path/path-buffer#normalize), each edge decided in writing — including that `x/..` simplification is the truth about directories and a lie about symlinks, with the filesystem-true answer deferred to canonicalization. - **Prefixes** — the Windows family (drive, UNC share, verbatim) behind [`PrefixLength`](https://rux-lang.dev/docs/api/path/syntax#prefix-length), [`HasRoot`](https://rux-lang.dev/docs/api/path/syntax#has-root) and [`IsAbsolute`](https://rux-lang.dev/docs/api/path/syntax#is-absolute); the Unix systems have no prefixes, and nothing here folds case. - **Two renderings, neither compromising** — [`OsStringView`](https://rux-lang.dev/docs/api/path/os-string-view), [`OsString`](https://rux-lang.dev/docs/api/path/os-string), [`Path`](https://rux-lang.dev/docs/api/path/path) and [`PathBuffer`](https://rux-lang.dev/docs/api/path/path-buffer) implement `Display` and `Debug`. `Display` is the name as a reader should see it, with every native unit that is not text replaced by U+FFFD: lossy on purpose, for a message, never for reopening a file. `Debug` is the name as it is, quoted, with a Unix byte outside a well-formed sequence written `\x{nn}` and a Windows code unit with no partner written `\u{xxxx}`, so nothing is lost and two different names never render alike. A precision is refused by both rather than applied, because a truncated path is a different path and may be one that exists. The exact conversions and the filesystem operations are untouched by either. [`Path`](https://rux-lang.dev/docs/api/path/path) and [`OsStringView`](https://rux-lang.dev/docs/api/path/os-string-view) are copyable borrowed values whose receivers use `&T`. Immutable [`OsString`](https://rux-lang.dev/docs/api/path/os-string) has deep-copy value semantics: a language copy allocates an independent native-unit block from the same allocator. [`PathBuffer`](https://rux-lang.dev/docs/api/path/path-buffer) prohibits copying, transfers with `<-`, and releases its block through [`~PathBuffer`](https://rux-lang.dev/docs/api/path/path-buffer#destructor). Use [`Path()`](https://rux-lang.dev/docs/api/path/path), [`OsStringView()`](https://rux-lang.dev/docs/api/path/os-string-view), `OsString(allocator)`, and `PathBuffer(allocator)` for empty values. Descriptive and fallible factories such as [`FromText`](https://rux-lang.dev/docs/api/path/os-string#from-text), [`FromPath`](https://rux-lang.dev/docs/api/path/path-buffer#from-path), [`Join`](https://rux-lang.dev/docs/api/path/path-buffer#join), and [`Normalize`](https://rux-lang.dev/docs/api/path/path-buffer#normalize) retain their names and return their value `! TextError`, as `OsStringView.ToText` returns `String ! TextError`. Raw pointers remain only for native storage and scalar output slots, where nullable or stored addresses are required. ## Index ### Types | Name | Summary | | --------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------- | | [`OsUnit`](https://rux-lang.dev/docs/api/path/os-string#os-unit) | The unit a native string is made of: a UTF-16 code unit on Windows, and a byte on the Unix systems. | | [`OsStringView`](https://rux-lang.dev/docs/api/path/os-string-view) | A borrowed run of native units. | | [`OsString`](https://rux-lang.dev/docs/api/path/os-string) | Native text that owns its units. | | [`Path`](https://rux-lang.dev/docs/api/path/path) | A borrowed path. | | [`ComponentIterator`](https://rux-lang.dev/docs/api/path/path#component-iterator) | A walk over a path's segments. | | [`PathBuffer`](https://rux-lang.dev/docs/api/path/path-buffer) | An owning, growable path. | | [`PrefixKind`](https://rux-lang.dev/docs/api/path/syntax#prefix-kind) | The kind of prefix a path opens with. | ### Functions | Name | Summary | | ------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | [`IsSeparator`](https://rux-lang.dev/docs/api/path/syntax#is-separator) | Whether `unit` separates path segments on this system. | | [`PreferredSeparator`](https://rux-lang.dev/docs/api/path/syntax#preferred-separator) | The separator this system prefers when one has to be written. | | [`Join`](https://rux-lang.dev/docs/api/path/path-buffer#join) | A fresh buffer holding `base` with `segment` pushed onto it. | | [`Normalize`](https://rux-lang.dev/docs/api/path/path-buffer#normalize) | A fresh buffer holding `path` lexically simplified: separator runs collapsed to the preferred separator, `.` segments dropped, and `..` resolved against the segment before it. | | [`PrefixLength`](https://rux-lang.dev/docs/api/path/syntax#prefix-length) | How many units of `path` are prefix, and which kind, reported through `kind`. | | [`HasRoot`](https://rux-lang.dev/docs/api/path/syntax#has-root) | Whether `path` has a root: a separator standing where the segments begin. | | [`IsAbsolute`](https://rux-lang.dev/docs/api/path/syntax#is-absolute) | Whether `path` names one place regardless of any current directory. | # OsString Native text that owns its units. ```rux pub struct OsString { // private fields } ``` Copyable with value semantics: each copy owns an independent native-unit block. ## Constructors ### `OsString` ```rux pub func OsString(allocator: Allocator) -> OsString ``` Native text of no length, which has allocated nothing. | Name | Type | Description | | ----------- | ----------- | ---------------------------- | | `allocator` | `Allocator` | where the storage comes from | **Returns**: an empty owned string that has taken no storage yet [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Path/Src/OsString.rux#L165){rel=""nofollow""} ## Associated functions ### `FromView` ```rux pub func FromView( allocator: Allocator, view: OsStringView ) -> OsString ! TextError ``` An owning copy of what `view` spans, exactly as it stands. This is the lossless direction: whatever the system handed over survives, valid text or not. It fails with `OutOfMemory` when the copy cannot be made. | Name | Type | Description | | ----------- | -------------- | ---------------------------- | | `allocator` | `Allocator` | where the storage comes from | | `view` | `OsStringView` | the borrowed text to copy | **Returns**: a copy of `view` this string owns, or an empty one when the allocator refused [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Path/Src/OsString.rux#L176){rel=""nofollow""} ### `FromText` ```rux pub func FromText( allocator: Allocator, text: char8[..] ) -> OsString ! TextError ``` An owning native copy of UTF-8 text. The direction that always succeeds: valid text encodes into either representation, byte for byte on the Unix systems and through UTF-16 on Windows. It fails only when the allocation does. The bytes must be well-formed UTF-8, which everything in `Rux/Text` produces and vouches for. | Name | Type | Description | | ----------- | ----------- | ---------------------------- | | `allocator` | `Allocator` | where the storage comes from | | `text` | `char8[..]` | the text to act on | **Returns**: the text converted to the platform's own units, or why it could not be [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Path/Src/OsString.rux#L244){rel=""nofollow""} ## Methods ### `Length` ```rux pub func Length(self: &OsString) -> uint ``` How many native units the text holds. **Returns**: how many units the value holds [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Path/Src/OsString.rux#L199){rel=""nofollow""} ### `IsEmpty` ```rux pub func IsEmpty(self: &OsString) -> bool ``` Whether the text holds nothing. **Returns**: whether it holds no units at all [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Path/Src/OsString.rux#L206){rel=""nofollow""} ### `View` ```rux pub func View(self: &OsString) -> OsStringView ``` A view over this text, which is what everything read-only takes. **Returns**: a borrowed view of the owned units [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Path/Src/OsString.rux#L213){rel=""nofollow""} ### `Clear` ```rux pub func Clear(self: &var OsString) ``` Gives the block back and leaves text of no length. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Path/Src/OsString.rux#L219){rel=""nofollow""} ## Operators ### `=` ```rux pub func =(self: &var OsString, other: &OsString) ``` Deep-copies native units into independent storage from the same allocator. | Name | Type | Description | | ------- | ----------- | ---------------------------- | | `other` | `&OsString` | the value to compare against | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Path/Src/OsString.rux#L148){rel=""nofollow""} ## Implements Display `OsString` conforms to `Display`. ### `WriteDisplay` ```rux pub func WriteDisplay( self: &OsString, writer: &var TextWriter, spec: FormatSpec ) -> ! FormatError ``` The lossy rendering of the units this text owns. The failures [`OsStringView::WriteDisplay`](https://rux-lang.dev/docs/api/path/os-string-view#write-display) reports. | Name | Type | Description | | -------- | ----------------- | ------------------------------ | | `writer` | `&var TextWriter` | the destination | | `spec` | `FormatSpec` | what the placeholder asked for | **Returns**: success when the whole name was accepted [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Path/Src/OsString.rux#L239){rel=""nofollow""} ## Implements Debug `OsString` conforms to `Debug`. ### `WriteDebug` ```rux pub func WriteDebug( self: &OsString, writer: &var TextWriter, spec: FormatSpec ) -> ! FormatError ``` The exact rendering of the units this text owns. The failures [`OsStringView::WriteDebug`](https://rux-lang.dev/docs/api/path/os-string-view#write-debug) reports. | Name | Type | Description | | -------- | ----------------- | ------------------------------ | | `writer` | `&var TextWriter` | the destination | | `spec` | `FormatSpec` | what the placeholder asked for | **Returns**: success when the whole name was accepted [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Path/Src/OsString.rux#L252){rel=""nofollow""} ## Destructor ```rux func ~OsString(self: &var OsString) ``` Gives the block back. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Path/Src/OsString.rux#L232){rel=""nofollow""} ## Related ### `OsUnit` ```rux // Windows pub type OsUnit = uint16 // Linux · macOS · FreeBSD pub type OsUnit = char8 ``` The unit a native string is made of: a UTF-16 code unit on Windows, and a byte on the Unix systems. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Path/Src/OsString.rux#L18){rel=""nofollow""} # OsStringView A borrowed run of native units. ```rux pub struct OsStringView { pub units: OsUnit[..]; } ``` `Copy`, owning nothing. The units it names must outlive it. ## Fields | Name | Type | Description | | ------- | ------------ | -------------------------------------------- | | `units` | `OsUnit[..]` | The units, exactly as the system holds them. | ## Constructors ### `OsStringView` ```rux pub func OsStringView() -> OsStringView ``` A view over nothing. **Returns**: an empty view [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Path/Src/OsString.rux#L38){rel=""nofollow""} ## Associated functions ### `FromUnits` ```rux pub func FromUnits(units: OsUnit[..]) -> OsStringView ``` A view over `units` as they stand: no validation, because there is nothing to validate against. | Name | Type | Description | | ------- | ------------ | -------------------------- | | `units` | `OsUnit[..]` | the borrowed units to view | **Returns**: a view over those units, which it does not copy [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Path/Src/OsString.rux#L46){rel=""nofollow""} ## Methods ### `Length` ```rux pub func Length(self: &OsStringView) -> uint ``` How many native units the view spans — bytes or code units, not characters. **Returns**: how many units the value holds [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Path/Src/OsString.rux#L53){rel=""nofollow""} ### `IsEmpty` ```rux pub func IsEmpty(self: &OsStringView) -> bool ``` Whether the view spans nothing. **Returns**: whether it holds no units at all [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Path/Src/OsString.rux#L60){rel=""nofollow""} ### `Units` ```rux pub func Units(self: &OsStringView) -> OsUnit[..] ``` The units themselves. **Returns**: the units, borrowed [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Path/Src/OsString.rux#L67){rel=""nofollow""} ### `Equals` ```rux pub func Equals( self: &OsStringView, other: &OsStringView ) -> bool ``` Whether two views hold the same units. Unit equality and nothing smarter: no case folding, no normalization. Two names the filesystem treats as one are still two names here, because which names those are is the filesystem's opinion, not the string's. | Name | Type | Description | | ------- | --------------- | ---------------------------- | | `other` | `&OsStringView` | the value to compare against | **Returns**: whether both hold the same units in the same order [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Path/Src/OsString.rux#L77){rel=""nofollow""} ### `ToText` ```rux pub func ToText( self: &OsStringView, allocator: Allocator ) -> String ! TextError ``` This native text as UTF-8, or nothing where it is not text. The fallible direction, and fallible for a different reason per platform: Unix bytes may simply not be UTF-8, and Windows units may hold an unpaired surrogate, which no UTF-8 sequence can spell. It fails with `InvalidUtf8` for both, because both mean the same thing to the caller — this name is not text, and a program that must show it anyway shows it lossily by its own policy, knowingly. | Name | Type | Description | | ----------- | ----------- | ---------------------------- | | `allocator` | `Allocator` | where the storage comes from | **Returns**: the units converted to text, or a failure when they are not valid in it [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Path/Src/OsString.rux#L95){rel=""nofollow""} ## Implements Display `OsStringView` conforms to `Display`. ### `WriteDisplay` ```rux pub func WriteDisplay( self: &OsStringView, writer: &var TextWriter, spec: FormatSpec ) -> ! FormatError ``` Writes the name as text, with every native unit that is not text replaced by U+FFFD. Lossy, deliberately and only here. A name the system holds is not obliged to be text, and a program reporting which file it could not open still has to name it; U+FFFD is what the standard provides for exactly that. What this produces is for a reader, never for reopening the file — two different names can render alike, and `Debug` is the rendering that does not. Reports whatever the writer reported, and `UnsupportedRequest` for any style or precision. A precision is refused rather than applied because a truncated path is a different path, and may be one that exists. | Name | Type | Description | | -------- | ----------------- | ------------------------------ | | `writer` | `&var TextWriter` | the destination | | `spec` | `FormatSpec` | what the placeholder asked for | **Returns**: success when the whole name was accepted [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Path/Src/OsString.rux#L208){rel=""nofollow""} ## Implements Debug `OsStringView` conforms to `Debug`. ### `WriteDebug` ```rux pub func WriteDebug( self: &OsStringView, writer: &var TextWriter, spec: FormatSpec ) -> ! FormatError ``` Writes the name exactly, quoted, with every unit that is not text spelled as an escape. Nothing is lost: a Unix byte outside a well-formed sequence is written `\x{nn}` and a Windows code unit with no partner is written `\u{xxxx}`, so the native units can be read back off the output and two different names never render alike. The quote, the backslash and the control characters are escaped the way this repository escapes them everywhere else. Reports whatever the writer reported, and `UnsupportedRequest` for any style or precision. | Name | Type | Description | | -------- | ----------------- | ------------------------------ | | `writer` | `&var TextWriter` | the destination | | `spec` | `FormatSpec` | what the placeholder asked for | **Returns**: success when the whole name was accepted [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Path/Src/OsString.rux#L226){rel=""nofollow""} # Path A borrowed path. ```rux pub struct Path { pub name: OsStringView; } ``` `Copy`, owning nothing: structure over an [`OsStringView`](https://rux-lang.dev/docs/api/path/os-string-view)'s units. ## Fields | Name | Type | Description | | ------ | -------------- | ---------------------------------------------- | | `name` | `OsStringView` | The name, exactly as the system would hold it. | ## Constructors ### `Path` ```rux pub func Path() -> Path ``` A path over nothing. **Returns**: an empty path [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Path/Src/Path.rux#L50){rel=""nofollow""} ## Associated functions ### `FromView` ```rux pub func FromView(view: OsStringView) -> Path ``` A path over `view`'s units as they stand. | Name | Type | Description | | ------ | -------------- | ------------------------- | | `view` | `OsStringView` | the borrowed text to copy | **Returns**: a path over those units, which it does not copy [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Path/Src/Path.rux#L58){rel=""nofollow""} ## Methods ### `Parent` ```rux pub func Parent(self: &Path) -> Path? ``` This path without its last component, or `none` where nothing is left to remove. The parent of `/a` is `/`, and the root's parent is `none`: the root is not inside anything. The parent of a bare segment is the empty path, which is what lets a loop walk parents to a fixed end. **Returns**: the path without its last component, or `none` when there is none to remove [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Path/Src/Path.rux#L15){rel=""nofollow""} ### `FileName` ```rux pub func FileName(self: &Path) -> OsStringView? ``` The last component's name, or `none` for the empty path and the root. Trailing separators are ignored: `a/b/` names `b`, because that is what everything from shells to libraries has always meant by it. **Returns**: the last component, or `none` for a root or a path ending in a separator [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Path/Src/Path.rux#L40){rel=""nofollow""} ### `Stem` ```rux pub func Stem(self: &Path) -> OsStringView? ``` The file name before its extension, or `none` where there is no file name. A leading dot is part of the name, not an extension marker: the stem of `.bashrc` is `.bashrc`. Of `a.tar.gz` it is `a.tar` — one extension comes off, the last. **Returns**: the file name without its extension, or `none` when there is no file name [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Path/Src/Path.rux#L60){rel=""nofollow""} ### `Extension` ```rux pub func Extension(self: &Path) -> OsStringView? ``` The extension after the last dot, without the dot, or `none` where there is none. `none` for `.bashrc` and for `Makefile` alike: a name that is all extension has none. **Returns**: the file name's extension without the dot, or `none` when it has none [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Path/Src/Path.rux#L74){rel=""nofollow""} ### `Length` ```rux pub func Length(self: &Path) -> uint ``` How many native units the path spans. **Returns**: how many units the path holds [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Path/Src/Path.rux#L65){rel=""nofollow""} ### `IsEmpty` ```rux pub func IsEmpty(self: &Path) -> bool ``` Whether the path is empty, which names nothing at all. **Returns**: whether the path holds no units [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Path/Src/Path.rux#L72){rel=""nofollow""} ### `AsView` ```rux pub func AsView(self: &Path) -> OsStringView ``` The name under the structure. **Returns**: the path's units, borrowed [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Path/Src/Path.rux#L79){rel=""nofollow""} ### `Equals` ```rux pub func Equals(self: &Path, other: Path) -> bool ``` Whether two paths are the same units. Lexical, not semantic: `a/b` and `a//b` name the same file and are different paths here. Making them equal is normalization's job, asked for by name. | Name | Type | Description | | ------- | ------ | ---------------------------- | | `other` | `Path` | the value to compare against | **Returns**: whether both hold the same units in the same order, without normalizing either [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Path/Src/Path.rux#L89){rel=""nofollow""} ### `Components` ```rux pub func Components(self: &Path) -> ComponentIterator ``` A walk over the path's components, first to last. **Returns**: a cursor over the path's components [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Path/Src/Path.rux#L97){rel=""nofollow""} ## Implements Display `Path` conforms to `Display`. ### `WriteDisplay` ```rux pub func WriteDisplay( self: &Path, writer: &var TextWriter, spec: FormatSpec ) -> ! FormatError ``` The lossy rendering of the path's units. The separators are written as they stand: a path is shown as it is, not normalized towards the platform's preferred separator, because which separators a name contains is part of what it is. The failures [`OsStringView::WriteDisplay`](https://rux-lang.dev/docs/api/path/os-string-view#write-display) reports. | Name | Type | Description | | -------- | ----------------- | ------------------------------ | | `writer` | `&var TextWriter` | the destination | | `spec` | `FormatSpec` | what the placeholder asked for | **Returns**: success when the whole path was accepted [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Path/Src/Path.rux#L267){rel=""nofollow""} ## Implements Debug `Path` conforms to `Debug`. ### `WriteDebug` ```rux pub func WriteDebug( self: &Path, writer: &var TextWriter, spec: FormatSpec ) -> ! FormatError ``` The exact, quoted rendering of the path's units. The failures [`OsStringView::WriteDebug`](https://rux-lang.dev/docs/api/path/os-string-view#write-debug) reports. | Name | Type | Description | | -------- | ----------------- | ------------------------------ | | `writer` | `&var TextWriter` | the destination | | `spec` | `FormatSpec` | what the placeholder asked for | **Returns**: success when the whole path was accepted [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Path/Src/Path.rux#L280){rel=""nofollow""} ## Related ### `ComponentIterator` ```rux pub struct ComponentIterator { // private fields } ``` A walk over a path's segments. Runs of separators count as one, and a trailing separator ends the walk rather than yielding an empty segment: `a//b/` walks as `a`, `b`. A leading separator is the root, which the walk reports as an empty first component so that an absolute path is distinguishable from a relative one holding the same segments. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Path/Src/Path.rux#L107){rel=""nofollow""} **Methods** #### `Next` ```rux pub func Next(self: &var ComponentIterator) -> OsStringView? ``` The next component, or `none` when the walk is done. **Returns**: the next component, or `none` at the end [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Path/Src/Path.rux#L118){rel=""nofollow""} # PathBuffer An owning, growable path. ```rux pub struct PathBuffer { pub data: *var OsUnit; pub length: uint; pub allocator: Allocator; // private fields } ``` Move-only: it prohibits copying and gives its block back with [`~PathBuffer`](https://rux-lang.dev/docs/api/path/path-buffer#destructor). ## Fields | Name | Type | Description | | ----------- | ------------- | ----------------------------------------------------- | | `data` | `*var OsUnit` | The units, or null before the first push. | | `length` | `uint` | How many units are in use. | | `allocator` | `Allocator` | Where the block came from, and where it goes back to. | ## Constructors ### `PathBuffer` ```rux pub func PathBuffer(allocator: Allocator) -> PathBuffer ``` An empty buffer that has allocated nothing. | Name | Type | Description | | ----------- | ----------- | ---------------------------- | | `allocator` | `Allocator` | where the storage comes from | **Returns**: an empty buffer that has taken no storage yet [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Path/Src/PathBuffer.rux#L32){rel=""nofollow""} ## Associated functions ### `FromPath` ```rux pub func FromPath( allocator: Allocator, path: Path ) -> PathBuffer ! TextError ``` A buffer opening with `path`'s units. | Name | Type | Description | | ----------- | ----------- | ---------------------------- | | `allocator` | `Allocator` | where the storage comes from | | `path` | `Path` | the path to act on | **Returns**: a copy of `path` this buffer owns, or an empty one when the allocator refused [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Path/Src/PathBuffer.rux#L41){rel=""nofollow""} ## Methods ### `Length` ```rux pub func Length(self: &PathBuffer) -> uint ``` How many units the buffer holds. **Returns**: how many units the buffer holds [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Path/Src/PathBuffer.rux#L50){rel=""nofollow""} ### `IsEmpty` ```rux pub func IsEmpty(self: &PathBuffer) -> bool ``` Whether the buffer holds nothing. **Returns**: whether the buffer holds no units [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Path/Src/PathBuffer.rux#L57){rel=""nofollow""} ### `AsPath` ```rux pub func AsPath(self: &PathBuffer) -> Path ``` The buffer as a borrowed path, which is what every reading operation takes. The path borrows the buffer and must not outlive it or survive a push. **Returns**: a borrowed path over the buffer's units [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Path/Src/PathBuffer.rux#L65){rel=""nofollow""} ### `Push` ```rux pub func Push( self: &var PathBuffer, segment: OsStringView ) -> ! TextError ``` Appends `segment` as one more component, supplying the separator where one is missing. A segment that is itself absolute — opening with a separator — replaces the buffer instead of extending it, which is what joining means everywhere paths are joined: `join(a, /b)` is `/b`. | Name | Type | Description | | --------- | -------------- | ----------------------- | | `segment` | `OsStringView` | the component to append | **Returns**: nothing when the component was appended, or why not [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Path/Src/PathBuffer.rux#L112){rel=""nofollow""} ### `Release` ```rux pub func Release(self: &var PathBuffer) ``` Gives the block back and leaves an empty buffer. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Path/Src/PathBuffer.rux#L129){rel=""nofollow""} ## Implements Display `PathBuffer` conforms to `Display`. ### `WriteDisplay` ```rux pub func WriteDisplay( self: &PathBuffer, writer: &var TextWriter, spec: FormatSpec ) -> ! FormatError ``` The lossy rendering of the units the buffer owns. The failures [`OsStringView::WriteDisplay`](https://rux-lang.dev/docs/api/path/os-string-view#write-display) reports. | Name | Type | Description | | -------- | ----------------- | ------------------------------ | | `writer` | `&var TextWriter` | the destination | | `spec` | `FormatSpec` | what the placeholder asked for | **Returns**: success when the whole path was accepted [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Path/Src/PathBuffer.rux#L293){rel=""nofollow""} ## Implements Debug `PathBuffer` conforms to `Debug`. ### `WriteDebug` ```rux pub func WriteDebug( self: &PathBuffer, writer: &var TextWriter, spec: FormatSpec ) -> ! FormatError ``` The exact, quoted rendering of the units the buffer owns. The failures [`OsStringView::WriteDebug`](https://rux-lang.dev/docs/api/path/os-string-view#write-debug) reports. | Name | Type | Description | | -------- | ----------------- | ------------------------------ | | `writer` | `&var TextWriter` | the destination | | `spec` | `FormatSpec` | what the placeholder asked for | **Returns**: success when the whole path was accepted [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Path/Src/PathBuffer.rux#L306){rel=""nofollow""} ## Destructor ```rux func ~PathBuffer(self: &var PathBuffer) ``` Gives the block back. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Path/Src/PathBuffer.rux#L144){rel=""nofollow""} ## Related ### `Join` ```rux pub func Join( allocator: Allocator, base: Path, segment: OsStringView ) -> PathBuffer ! TextError ``` A fresh buffer holding `base` with `segment` pushed onto it. The join every path library means: a separator supplied where one is missing, and an absolute `segment` replacing `base` entirely. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Path/Src/PathBuffer.rux#L157){rel=""nofollow""} **Parameters** | Name | Type | Description | | ----------- | -------------- | ---------------------------- | | `allocator` | `Allocator` | where the storage comes from | | `base` | `Path` | the path to extend | | `segment` | `OsStringView` | the component to append | **Returns**: `base` with `segment` appended, or why it could not be ### `Normalize` ```rux pub func Normalize( allocator: Allocator, path: Path ) -> PathBuffer ! TextError ``` A fresh buffer holding `path` lexically simplified: separator runs collapsed to the preferred separator, `.` segments dropped, and `..` resolved against the segment before it. Lexically is the load-bearing word. Dropping `x/..` is the truth about directories and a lie about symbolic links — `a/link/..` need not be `a` when `link` points elsewhere — so this is for display, comparison and deduplication, and the filesystem-true answer is canonicalization, which asks the system. A `..` with nothing before it survives in a relative path and vanishes at the root, where there is nowhere further up. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Path/Src/PathBuffer.rux#L173){rel=""nofollow""} **Parameters** | Name | Type | Description | | ----------- | ----------- | ---------------------------- | | `allocator` | `Allocator` | where the storage comes from | | `path` | `Path` | the path to act on | **Returns**: the path with its redundant components resolved, or why it could not be # Path syntax Which units separate segments on this system, and the prefix and root a path opens with. ## `IsSeparator` ```rux pub func IsSeparator(unit: OsUnit) -> bool ``` Whether `unit` separates path segments on this system. Both slashes on Windows, the forward one alone elsewhere. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Path/Src/Path.rux#L17){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------ | -------- | ---------------- | | `unit` | `OsUnit` | the unit to test | **Returns**: whether the unit separates components on this system ## `PreferredSeparator` ```rux pub func PreferredSeparator() -> OsUnit ``` The separator this system prefers when one has to be written. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Path/Src/Path.rux#L29){rel=""nofollow""} **Returns**: the separator this system writes, which is not the only one it accepts ## `PrefixKind` ```rux pub enum PrefixKind: int32 { None = 0, Drive = 1, Share = 2, Verbatim = 3 } ``` The kind of prefix a path opens with. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Path/Src/Prefix.rux#L14){rel=""nofollow""} **Cases** | Name | Value | Description | | ---------- | ----- | ------------------------------------------------------ | | `None` | `0` | No prefix: the path is a plain name, rooted or not. | | `Drive` | `1` | A drive, `C:`, with or without a root after it. | | `Share` | `2` | A UNC share, `\server\share`. | | `Verbatim` | `3` | The verbatim prefix `\?\` and everything it qualifies. | ## `PrefixLength` ```rux pub func PrefixLength( path: Path, kind: *var PrefixKind ) -> uint ``` How many units of `path` are prefix, and which kind, reported through `kind`. Zero and `None` on the Unix systems always: a leading `//server` is just a path there, whatever tools make of it. On Windows the drive is two units, a share runs through the end of its share name, and the verbatim prefix covers its four units plus the drive or share inside it. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Path/Src/Prefix.rux#L33){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------ | ----------------- | ---------------------------- | | `path` | `Path` | the path to act on | | `kind` | `*var PrefixKind` | which prefix form to measure | **Returns**: how many leading units the prefix occupies, or zero when there is none ## `HasRoot` ```rux pub func HasRoot(path: Path) -> bool ``` Whether `path` has a root: a separator standing where the segments begin. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Path/Src/Prefix.rux#L106){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------ | ------ | ------------------ | | `path` | `Path` | the path to act on | **Returns**: whether the path begins at a root ## `IsAbsolute` ```rux pub func IsAbsolute(path: Path) -> bool ``` Whether `path` names one place regardless of any current directory. On the Unix systems, rooted is absolute. On Windows a rooted drive (`C:\x`), a share and a verbatim path are absolute; `C:name` is drive-relative and `\name` drive-absent, and neither names one place on its own. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Path/Src/Prefix.rux#L123){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------ | ------ | ------------------ | | `path` | `Path` | the path to act on | **Returns**: whether the path names a location without needing a working directory # Time Durations, monotonic clocks and wall clocks. ## Installation Add `Time` to the `[Dependencies]` table of your package's `Rux.toml`: ```toml [Dependencies] Time = { Namespace = "Rux", Version = "0.1.0" } ``` Standard packages are declared by hand: the registry does not serve them, so `rux add Rux/Time` cannot add them. ## Dependencies - [`Core`](https://rux-lang.dev/docs/api/core) 0.1.0 - [`FreeBSD`](https://rux-lang.dev/docs/api/freebsd) 0.1.0 (FreeBSD only) - [`Linux`](https://rux-lang.dev/docs/api/linux) 0.1.0 (Linux only) - [`macOS`](https://rux-lang.dev/docs/api/macos) 0.1.0 (macOS only) - [`Text`](https://rux-lang.dev/docs/api/text) 0.1.0 - [`Windows`](https://rux-lang.dev/docs/api/windows) 0.1.0 (Windows only) ## Guide Nanosecond durations, monotonic and wall clocks, Gregorian calendar values, and RFC 3339 text. ### What it provides - **[`Duration`](https://rux-lang.dev/docs/api/time/duration)** — a span of time exact to the nanosecond, normalized so the fraction is always in \[0, 1e9) with the sign carried by the seconds: equality is bytewise, ordering is two comparisons, and arithmetic is a carry. All of it is checked — an overflow at the edge of a 292-billion-year range is a bug in the caller's arithmetic, and gets a report rather than a wrap that turns a timeout into a deadline in the past. - **[`Instant`](https://rux-lang.dev/docs/api/time/instant) and [`Timestamp`](https://rux-lang.dev/docs/api/time/timestamp)** — monotonic readings for measuring elapsed time and UTC wall-clock moments for interchange. [`SleepFor`](https://rux-lang.dev/docs/api/time/sleep) waits against the platform clock without exposing its raw handles, and reports a [`TimeError`](https://rux-lang.dev/docs/api/time/sleep#time-error) rather than leaving a wait that did not happen indistinguishable from one that did. - **[`Stopwatch`](https://rux-lang.dev/docs/api/time/stopwatch)** — elapsed time on the monotonic clock that can be paused and resumed: [`Start`](https://rux-lang.dev/docs/api/time/stopwatch#start), [`Stop`](https://rux-lang.dev/docs/api/time/stopwatch#stop), [`Reset`](https://rux-lang.dev/docs/api/time/stopwatch#reset), [`Restart`](https://rux-lang.dev/docs/api/time/stopwatch#restart), [`IsRunning`](https://rux-lang.dev/docs/api/time/stopwatch#is-running), `Elapsed` while running or stopped, and [`Lap`](https://rux-lang.dev/docs/api/time/stopwatch#lap) for splits that exclude paused time. It measures elapsed time and nothing more; repetition, warm-up and statistics are a benchmarking tool's concern. - **Calendar values** — validated [`Date`](https://rux-lang.dev/docs/api/time/date) and [`TimeOfDay`](https://rux-lang.dev/docs/api/time/time-of-day) values, fixed [`UtcOffset`](https://rux-lang.dev/docs/api/time/utc-offset)s, [`DateTime`](https://rux-lang.dev/docs/api/time/date-time) conversion, and checked date arithmetic over the proleptic Gregorian calendar. - **RFC 3339 and the calendar shapes** — [`ParseDate`](https://rux-lang.dev/docs/api/time/date#parse-date), [`ParseTimeOfDay`](https://rux-lang.dev/docs/api/time/time-of-day#parse-time-of-day), [`ParseDateTime`](https://rux-lang.dev/docs/api/time/date-time#parse-date-time) and [`ParseRfc3339`](https://rux-lang.dev/docs/api/time/offset-date-time#parse-rfc3339) each answer a native fallible `T ! TimeParseError`, and every failure carries a zero-based byte offset into the text. The categories are the ones a caller acts on differently: a malformed shape, a month that is not one, a day the month does not have, a time out of range, a fraction too long, and an offset that is not one. Second 60 folds to the last nanosecond of second 59, and formatting never produces it, so the fold is one-way. [`ParseDuration`](https://rux-lang.dev/docs/api/time/duration#parse-duration) reads the span form back the same way. - **Presentation** — [`Date`](https://rux-lang.dev/docs/api/time/date), [`TimeOfDay`](https://rux-lang.dev/docs/api/time/time-of-day), [`UtcOffset`](https://rux-lang.dev/docs/api/time/utc-offset), [`DateTime`](https://rux-lang.dev/docs/api/time/date-time), [`OffsetDateTime`](https://rux-lang.dev/docs/api/time/offset-date-time), [`Duration`](https://rux-lang.dev/docs/api/time/duration) and [`Timestamp`](https://rux-lang.dev/docs/api/time/timestamp) implement `Display` and `Debug`. A [`DateTime`](https://rux-lang.dev/docs/api/time/date-time) writes no offset, because it holds none: `Z` would claim UTC and the machine's offset would claim a place. [`OffsetDateTime`](https://rux-lang.dev/docs/api/time/offset-date-time) is the pairing that carries one and therefore the type that produces RFC 3339. A precision names 0 to 9 fractional digits and truncates; without one the fraction is written to the digits it has, trailing zeros trimmed. - **One default per value** — a [`Timestamp`](https://rux-lang.dev/docs/api/time/timestamp) is a moment on the calendar and a count of seconds at once, and only the first is what a bare placeholder writes: `{}` is RFC 3339 in UTC, and `{:unix}` is the signed second count. A moment outside years 0000 through 9999 has no RFC 3339 text and is refused with `ValueOutOfRange` before anything is written, which the second count still spells. [`Instant`](https://rux-lang.dev/docs/api/time/instant) implements `Debug` alone, showing `Instant(nanoseconds: N)`: a monotonic reading counts from an origin the system chose at boot and has no text for a reader, only a difference from another reading. Calendar readers return their parsed values and positioned failures through native fallibles and `?`, and the checked constructors and arithmetic ([`Date::New`](https://rux-lang.dev/docs/api/time/date#new), [`PlusDays`](https://rux-lang.dev/docs/api/time/date#plus-days), `Duration.Plus`, `Instant.Since`, ...) return native optionals. They allocate no storage; an embedded date or time keeps its byte offset within the complete input. All public value receivers borrow with `&T`. The remaining raw pointers are writable scalar/aggregate output slots and platform FFI addresses, never ownership handles. The package's value types are structurally `Copy`; descriptive and fallible factories retain names such as `Now`, [`FromSeconds`](https://rux-lang.dev/docs/api/time/duration#from-seconds), and `New`. ### Waiting, and what is not here [`SleepFor`](https://rux-lang.dev/docs/api/time/sleep) is the supported way to wait. It is a clock operation — it blocks the calling thread against the platform clock — and it is the only one v0.1.0 offers, because v0.1.0 has no concurrency support at all. There is no thread creation, no thread identifier, no yield, no lock, no atomic and no channel in any first-party package; see [First-Party Packages](https://github.com/rux-lang/Rux/blob/main/Packages/Time/../../Docs/Packages.md#not-in-v010){rel=""nofollow""} for why the `Sync` and `Thread` packages were withdrawn rather than shipped. A caller that needs those must supply them, and [`SleepFor`](https://rux-lang.dev/docs/api/time/sleep) does not imply that a second thread exists to be woken. It waits for the whole span. A signal can cut a Unix wait short, and the loop goes back for what is left rather than returning early — a caller asked for a span, not for a span unless the process happened to receive a signal. Windows takes its interval as a 32-bit millisecond count, which runs out after about 49.7 days, so a longer span is waited for in chunks rather than clamped to the ceiling; [`MaximumWaitMilliseconds`](https://rux-lang.dev/docs/api/time/sleep#maximum-wait-milliseconds) is that ceiling and [`WaitChunkMilliseconds`](https://rux-lang.dev/docs/api/time/sleep#wait-chunk-milliseconds) is the arithmetic, public so that a hundred-day sleep can be checked without waiting a hundred days. A wait can also simply fail, and [`SleepFor`](https://rux-lang.dev/docs/api/time/sleep) says so. It returns `! TimeError` and succeeds only when the span really elapsed; `InvalidDuration` means the system refused the request outright, which is a case that used to be indistinguishable from success because a refused wait and a completed one both leave the remainder at zero. A caller with nothing to do about it says so with `SleepFor(span) catch { else => {} }` — the point is that the information exists. The system wait is reached through the [`Waiter`](https://rux-lang.dev/docs/api/time/waiter) interface, and [`SleepUsing`](https://rux-lang.dev/docs/api/time/sleep#sleep-using) drives whichever one it is given. That is what makes the chunking, the retry and the failure paths testable: a test for a hundred-day sleep must not take a hundred days, and a test for an interrupted sleep cannot arrange a signal. ## Index ### Interfaces | Name | Summary | | ----------------------------------------------------- | ------------------------------------------------ | | [`Waiter`](https://rux-lang.dev/docs/api/time/waiter) | One wait, however the caller reaches the system. | ### Types | Name | Summary | | ------------------------------------------------------------------------- | ------------------------------------------------------------------------- | | [`Date`](https://rux-lang.dev/docs/api/time/date) | A calendar date that exists. | | [`TimeOfDay`](https://rux-lang.dev/docs/api/time/time-of-day) | A time within a day, to the nanosecond. | | [`UtcOffset`](https://rux-lang.dev/docs/api/time/utc-offset) | A fixed shift from UTC, in whole minutes. | | [`DateTime`](https://rux-lang.dev/docs/api/time/date-time) | A date and a time of day together, in some understood offset. | | [`TimeParseError`](https://rux-lang.dev/docs/api/time/time-parse-error) | Why text could not be read as a calendar value. | | [`OffsetDateTime`](https://rux-lang.dev/docs/api/time/offset-date-time) | A date and time together with the offset from UTC they are stated in. | | [`Duration`](https://rux-lang.dev/docs/api/time/duration) | A span of time: seconds and a fraction, normalized. | | [`Instant`](https://rux-lang.dev/docs/api/time/instant) | A reading of the monotonic clock. | | [`TimeError`](https://rux-lang.dev/docs/api/time/sleep#time-error) | Why a wait did not happen. | | [`SystemWaiter`](https://rux-lang.dev/docs/api/time/waiter#system-waiter) | The wait every supported system actually provides. | | [`Stopwatch`](https://rux-lang.dev/docs/api/time/stopwatch) | A pausable timer over the monotonic clock. | | [`Timestamp`](https://rux-lang.dev/docs/api/time/timestamp) | A moment in UTC: seconds since the Unix epoch and a fraction, normalized. | ### Functions | Name | Summary | | ------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------- | | [`IsLeapYear`](https://rux-lang.dev/docs/api/time/date#is-leap-year) | Whether `year` is a leap year: every fourth, except every hundredth, except every four-hundredth. | | [`DaysInMonth`](https://rux-lang.dev/docs/api/time/date#days-in-month) | How many days `month` holds in `year`. | | [`ParseDate`](https://rux-lang.dev/docs/api/time/date#parse-date) | Reads `YYYY-MM-DD`. | | [`ParseTimeOfDay`](https://rux-lang.dev/docs/api/time/time-of-day#parse-time-of-day) | Reads `HH:MM:SS` with an optional fractional second. | | [`ParseDateTime`](https://rux-lang.dev/docs/api/time/date-time#parse-date-time) | Reads `YYYY-MM-DDTHH:MM:SS[.fraction]`, with no offset. | | [`ParseRfc3339`](https://rux-lang.dev/docs/api/time/offset-date-time#parse-rfc3339) | Reads `YYYY-MM-DDTHH:MM:SS[.fraction](Z|+HH:MM|-HH:MM)`. | | [`ParseDuration`](https://rux-lang.dev/docs/api/time/duration#parse-duration) | Reads a span written as signed decimal seconds followed by `s`. | | [`WaitChunkMilliseconds`](https://rux-lang.dev/docs/api/time/sleep#wait-chunk-milliseconds) | How long the next single wait should be asked for, given how much of the span is left. | | [`SleepUsing<W>`](https://rux-lang.dev/docs/api/time/sleep#sleep-using) | Waits out `span` through `waiter`, retrying interruptions and chunking what one wait cannot express. | | [`SleepFor`](https://rux-lang.dev/docs/api/time/sleep) | Stops the calling thread for at least `span`. | ### Constants | Name | Summary | | ----------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------ | | [`NanosecondsPerSecond`](https://rux-lang.dev/docs/api/time/duration#nanoseconds-per-second) | How many nanoseconds one second holds. | | [`MaximumWaitMilliseconds`](https://rux-lang.dev/docs/api/time/sleep#maximum-wait-milliseconds) | The longest interval one system wait may be asked for, in milliseconds. | | [`MaximumWaitAttempts`](https://rux-lang.dev/docs/api/time/sleep#maximum-wait-attempts) | How many waits [`SleepFor`](https://rux-lang.dev/docs/api/time/sleep) will make before giving up on a span that never shrinks. | # Waiter One wait, however the caller reaches the system. ```rux pub interface Waiter { func WaitFor( self: &var Self, span: Duration ) -> Duration ! TimeError; } ``` An implementation waits for at most `span` and reports what is left of it. Reporting less than the whole span as remaining is how a wait says it did some of the work, including when a signal stopped it early; failing is how it says the system refused. [`SleepFor`](https://rux-lang.dev/docs/api/time/sleep) drives whichever implementation it is given until nothing is left. ## Requirements ### `WaitFor` ```rux func WaitFor( self: &var Self, span: Duration ) -> Duration ! TimeError ``` Waits for at most `span`, and reports what remains of it. Succeeds with the unwaited part, which is zero when the whole span was waited for and more than zero when something stopped the wait early with time still to go. Fails when the system refused the wait. An implementation must not succeed with zero unless the span really elapsed. | Name | Type | Description | | ------ | ---------- | ------------------------- | | `span` | `Duration` | how much time to wait for | **Returns**: what is left of `span`, or why the wait did not happen [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Time/Src/Sleep.rux#L91){rel=""nofollow""} ## Implementations | Type | Summary | | ------------------------------------------------------------------------- | -------------------------------------------------- | | [`SystemWaiter`](https://rux-lang.dev/docs/api/time/waiter#system-waiter) | The wait every supported system actually provides. | ## Related ### `SystemWaiter` ```rux pub struct SystemWaiter { // private fields } ``` The wait every supported system actually provides. `Copy`. Holds nothing: the system is the state. Construct one with `SystemWaiter()` and hand it to [`SleepUsing`](https://rux-lang.dev/docs/api/time/sleep#sleep-using), or use [`SleepFor`](https://rux-lang.dev/docs/api/time/sleep), which does that. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Time/Src/Sleep.rux#L98){rel=""nofollow""} **Constructors** #### `SystemWaiter` ```rux pub func SystemWaiter() -> SystemWaiter ``` A waiter that reaches the operating system. Cannot fail. Runs in constant time and allocates nothing. **Returns**: the waiter [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Time/Src/Sleep.rux#L109){rel=""nofollow""} **Implements Waiter** `SystemWaiter` conforms to [`Waiter`](https://rux-lang.dev/docs/api/time/waiter). # Date A calendar date that exists. ```rux pub struct Date { pub year: int32; pub month: uint8; pub day: uint8; } ``` `Copy`. Only constructible through the fallible [`New`](https://rux-lang.dev/docs/api/time/date#new) factory, which lets everything downstream assume validity. ## Fields | Name | Type | Description | | ------- | ------- | -------------------------------------------------------------- | | `year` | `int32` | The year, astronomically numbered: year 0 exists and is 1 BCE. | | `month` | `uint8` | The month, 1 through 12. | | `day` | `uint8` | The day, 1 through the month's length. | ## Associated functions ### `New` ```rux pub func New(year: int32, month: uint8, day: uint8) -> Date? ``` The date, when it exists. | Name | Type | Description | | ------- | ------- | ------------------------------------------ | | `year` | `int32` | the year, as a signed count from year zero | | `month` | `uint8` | the month, 1 through 12 | | `day` | `uint8` | the day of the month, counting from one | **Returns**: the date, or `None` when the components do not name one [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Time/Src/Calendar.rux#L53){rel=""nofollow""} ### `FromEpochDays` ```rux pub func FromEpochDays(days: int64) -> Date ``` The date `days` after 1970-01-01, negative before it. The inverse of [`DaysFromEpoch`](https://rux-lang.dev/docs/api/time/date#days-from-epoch), exactly: the pair round-trips every day of every representable year. | Name | Type | Description | | ------ | ------- | ------------- | | `days` | `int64` | how many days | **Returns**: the date that many days after 1970-01-01 [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Time/Src/Calendar.rux#L81){rel=""nofollow""} ## Methods ### `DaysFromEpoch` ```rux pub func DaysFromEpoch(self: &Date) -> int64 ``` Days since 1970-01-01, negative before it. The civil-calendar formula: the year is shifted so March opens it, which puts the leap day at the end where it cannot disturb the month arithmetic. **Returns**: days since 1970-01-01, negative before it [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Time/Src/Calendar.rux#L63){rel=""nofollow""} ### `DayOfWeek` ```rux pub func DayOfWeek(self: &Date) -> uint8 ``` The day of the week, 0 for Sunday through 6 for Saturday. **Returns**: the day of the week, with Monday as one [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Time/Src/Calendar.rux#L98){rel=""nofollow""} ### `DayOfYear` ```rux pub func DayOfYear(self: &Date) -> uint16 ``` The day of the year, 1 through 365 or 366. **Returns**: the day of the year, counting from one [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Time/Src/Calendar.rux#L108){rel=""nofollow""} ### `Equals` ```rux pub func Equals(self: &Date, other: Date) -> bool ``` Whether two dates are the same day. | Name | Type | Description | | ------- | ------ | ---------------------------- | | `other` | `Date` | the value to compare against | **Returns**: whether the two are the same [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Time/Src/Calendar.rux#L117){rel=""nofollow""} ### `Compare` ```rux pub func Compare(self: &Date, other: Date) -> Ordering ``` How this date orders against `other`. | Name | Type | Description | | ------- | ------ | ---------------------------- | | `other` | `Date` | the value to compare against | **Returns**: how this one orders against `other` [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Time/Src/Calendar.rux#L125){rel=""nofollow""} ### `PlusDays` ```rux pub func PlusDays(self: &Date, days: int64) -> Date? ``` The date `days` later, negative for earlier, or `None` outside the years the calendar spells. Exact: a day is a day, and the round trip through the epoch count neither loses nor invents one. | Name | Type | Description | | ------ | ------- | ------------- | | `days` | `int64` | how many days | **Returns**: the date that many days later, or `None` when it leaves the range [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Time/Src/Calendar.rux#L19){rel=""nofollow""} ### `PlusMonths` ```rux pub func PlusMonths(self: &Date, months: int64) -> Date? ``` The date `months` later, clamped to the month's end where the day is missing. January 31st plus one month is the last day of February; the clamp is the policy the module header states. | Name | Type | Description | | -------- | ------- | --------------- | | `months` | `int64` | how many months | **Returns**: the date that many months later, clamped to the month's last day, or `None` when it leaves the range [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Time/Src/Calendar.rux#L33){rel=""nofollow""} ### `PlusYears` ```rux pub func PlusYears(self: &Date, years: int64) -> Date? ``` The date `years` later, with February 29th clamping to the 28th where the year is not leap. | Name | Type | Description | | ------- | ------- | -------------- | | `years` | `int64` | how many years | **Returns**: the date that many years later, clamped for 29 February, or `None` when it leaves the range [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Time/Src/Calendar.rux#L53){rel=""nofollow""} ### `DaysSince` ```rux pub func DaysSince(self: &Date, earlier: Date) -> int64 ``` The whole days from `earlier` to this date, negative when it is the later one. | Name | Type | Description | | --------- | ------ | ------------------- | | `earlier` | `Date` | the earlier reading | **Returns**: how many days `earlier` is before this date, negative if it is after [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Time/Src/Calendar.rux#L66){rel=""nofollow""} ## Implements Display `Date` conforms to `Display`. ### `WriteDisplay` ```rux pub func WriteDisplay( self: &Date, writer: &var TextWriter, spec: FormatSpec ) -> ! FormatError ``` Writes the date as `YYYY-MM-DD`. A year outside 0 through 9999 carries a sign and as many digits as it needs, which is what ISO 8601 requires for one: four digits is the agreed width, and anything wider is ambiguous without a sign to mark it. Reports whatever the writer reported, and `UnsupportedRequest` for a style other than `iso8601` or `rfc3339`, or for a precision, which a date has nothing to apply one to. | Name | Type | Description | | -------- | ----------------- | ------------------------------ | | `writer` | `&var TextWriter` | the destination | | `spec` | `FormatSpec` | what the placeholder asked for | **Returns**: success when the whole date was accepted [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Time/Src/Calendar.rux#L155){rel=""nofollow""} ## Implements Debug `Date` conforms to `Debug`. ### `WriteDebug` ```rux pub func WriteDebug( self: &Date, writer: &var TextWriter, spec: FormatSpec ) -> ! FormatError ``` The same text as `Display`: a date has one reading, and quoting it would say nothing extra. The failures [`WriteDisplay`](https://rux-lang.dev/docs/api/time/date#write-display) reports. | Name | Type | Description | | -------- | ----------------- | ------------------------------ | | `writer` | `&var TextWriter` | the destination | | `spec` | `FormatSpec` | what the placeholder asked for | **Returns**: success when the whole date was accepted [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Time/Src/Calendar.rux#L174){rel=""nofollow""} ## Related ### `IsLeapYear` ```rux pub func IsLeapYear(year: int32) -> bool ``` Whether `year` is a leap year: every fourth, except every hundredth, except every four-hundredth. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Time/Src/Calendar.rux#L27){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------ | ------- | ------------------------------------------ | | `year` | `int32` | the year, as a signed count from year zero | **Returns**: whether that year has 366 days under the proleptic Gregorian calendar ### `DaysInMonth` ```rux pub func DaysInMonth(year: int32, month: uint8) -> uint8 ``` How many days `month` holds in `year`. Zero for a month that does not exist, which is what lets [`Date::New`](https://rux-lang.dev/docs/api/time/date#new) use it as the validator. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Time/Src/Calendar.rux#L39){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------- | ------- | ------------------------------------------ | | `year` | `int32` | the year, as a signed count from year zero | | `month` | `uint8` | the month, 1 through 12 | **Returns**: how many days that month has in that year ### `ParseDate` ```rux pub func ParseDate(text: char8[..]) -> Date ! TimeParseError ``` Reads `YYYY-MM-DD`. Strict: four year digits, two month digits, two day digits, dashes between, and nothing after. Reports `InvalidSyntax` for a shape that does not match, `InvalidMonth` for a month outside 1 through 12, and `NonexistentDay` for a day the month does not have. Each carries the byte offset where it was found. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Time/Src/CalendarParse.rux#L233){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------ | ----------- | ---------------- | | `text` | `char8[..]` | the text to read | **Returns**: the date, or why the text is not one # DateTime A date and a time of day together, in some understood offset. ```rux pub struct DateTime { pub date: Date; pub time: TimeOfDay; } ``` `Copy`. What offset the pair is in is the caller's knowledge, carried beside it where it matters — attaching one permanently would make every arithmetic answer depend on a field that is usually UTC anyway. ## Fields | Name | Type | Description | | ------ | ----------- | ------------------- | | `date` | `Date` | The day. | | `time` | `TimeOfDay` | The time within it. | ## Associated functions ### `FromTimestamp` ```rux pub func FromTimestamp( moment: Timestamp, offset: UtcOffset ) -> DateTime ``` The date and time `moment` names, shifted into `offset`. | Name | Type | Description | | -------- | ----------- | --------------------- | | `moment` | `Timestamp` | the moment to convert | | `offset` | `UtcOffset` | the offset from UTC | **Returns**: the local date and time that moment names at that offset [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Time/Src/Calendar.rux#L254){rel=""nofollow""} ## Methods ### `ToTimestamp` ```rux pub func ToTimestamp( self: &DateTime, offset: UtcOffset ) -> Timestamp ``` The moment this date and time name in UTC, shifted by `offset`. The shift subtracts: half past nine at plus two is half past seven in UTC. The range of a timestamp dwarfs the calendar's, so the conversion cannot overflow for any date [`Date::New`](https://rux-lang.dev/docs/api/time/date#new) accepts. | Name | Type | Description | | -------- | ----------- | ------------------- | | `offset` | `UtcOffset` | the offset from UTC | **Returns**: the moment this local time names at that offset [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Time/Src/Calendar.rux#L242){rel=""nofollow""} ### `Equals` ```rux pub func Equals(self: &DateTime, other: DateTime) -> bool ``` Whether two pairs name the same date and time. Same field values — two pairs in different offsets naming one moment are different here, which is what carrying the offset beside the pair means. | Name | Type | Description | | ------- | ---------- | ---------------------------- | | `other` | `DateTime` | the value to compare against | **Returns**: whether the two are the same [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Time/Src/Calendar.rux#L279){rel=""nofollow""} ## Implements Display `DateTime` conforms to `Display`. ### `WriteDisplay` ```rux pub func WriteDisplay( self: &DateTime, writer: &var TextWriter, spec: FormatSpec ) -> ! FormatError ``` Writes the local date and time as `YYYY-MM-DDTHH:MM:SS`, with no offset. The absence is deliberate and is the point of the type. A [`DateTime`](https://rux-lang.dev/docs/api/time/date-time) holds no offset, so writing one would mean inventing it: `Z` would claim UTC and the machine's local offset would claim a place, and both would be a guess presented as a fact. [`OffsetDateTime`](https://rux-lang.dev/docs/api/time/offset-date-time) is the type that has somewhere to keep an offset, and it is what produces RFC 3339. Reports whatever the writer reported, `UnsupportedRequest` for a style other than `iso8601` or `rfc3339`, and `UnsupportedRequest` for a precision past nine. | Name | Type | Description | | -------- | ----------------- | ------------------------------ | | `writer` | `&var TextWriter` | the destination | | `spec` | `FormatSpec` | what the placeholder asked for | **Returns**: success when the whole date and time were accepted [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Time/Src/Calendar.rux#L263){rel=""nofollow""} ## Implements Debug `DateTime` conforms to `Debug`. ### `WriteDebug` ```rux pub func WriteDebug( self: &DateTime, writer: &var TextWriter, spec: FormatSpec ) -> ! FormatError ``` The same text as `Display`. The failures [`WriteDisplay`](https://rux-lang.dev/docs/api/time/date-time#write-display) reports. | Name | Type | Description | | -------- | ----------------- | ------------------------------ | | `writer` | `&var TextWriter` | the destination | | `spec` | `FormatSpec` | what the placeholder asked for | **Returns**: success when the whole date and time were accepted [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Time/Src/Calendar.rux#L279){rel=""nofollow""} ## Related ### `ParseDateTime` ```rux pub func ParseDateTime(text: char8[..]) -> DateTime ! TimeParseError ``` Reads `YYYY-MM-DDTHH:MM:SS[.fraction]`, with no offset. The separator may be `T`, `t` or a space, which is as far as the RFC 3339 liberality goes. No offset is read, and one present is text after the value: a [`DateTime`](https://rux-lang.dev/docs/api/time/date-time) has nowhere to keep an offset, so accepting one would discard it silently. [`ParseRfc3339`](https://rux-lang.dev/docs/api/time/offset-date-time#parse-rfc3339) is what reads a moment that carries one. The failures [`ParseDate`](https://rux-lang.dev/docs/api/time/date#parse-date) and [`ParseTimeOfDay`](https://rux-lang.dev/docs/api/time/time-of-day#parse-time-of-day) report, at their offsets within this text. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Time/Src/CalendarParse.rux#L261){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------ | ----------- | ---------------- | | `text` | `char8[..]` | the text to read | **Returns**: the local date and time, or why the text is not one # Duration A span of time: seconds and a fraction, normalized. ```rux pub struct Duration { pub seconds: int64; // private fields } ``` `Copy`. The value is `seconds + nanoseconds / 1e9`, and `nanoseconds` is always in \[0, 1e9). ## Fields | Name | Type | Description | | --------- | ------- | ------------------------------------- | | `seconds` | `int64` | The whole seconds, carrying the sign. | ## Associated functions ### `Zero` ```rux pub func Zero() -> Duration ``` No time at all. **Returns**: a span of no time at all [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Time/Src/Duration.rux#L30){rel=""nofollow""} ### `FromSeconds` ```rux pub func FromSeconds(seconds: int64) -> Duration ``` Exactly `seconds` seconds. | Name | Type | Description | | --------- | ------- | ---------------- | | `seconds` | `int64` | how many seconds | **Returns**: that many seconds [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Time/Src/Duration.rux#L38){rel=""nofollow""} ### `FromMinutes` ```rux pub func FromMinutes(minutes: int64) -> Duration? ``` Exactly `minutes` minutes, or `None` past the range. | Name | Type | Description | | --------- | ------- | ---------------- | | `minutes` | `int64` | how many minutes | **Returns**: that many minutes, or `None` when the count does not fit [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Time/Src/Duration.rux#L46){rel=""nofollow""} ### `FromHours` ```rux pub func FromHours(hours: int64) -> Duration? ``` Exactly `hours` hours, or `None` past the range. | Name | Type | Description | | ------- | ------- | -------------- | | `hours` | `int64` | how many hours | **Returns**: that many hours, or `None` when the count does not fit [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Time/Src/Duration.rux#L56){rel=""nofollow""} ### `FromMilliseconds` ```rux pub func FromMilliseconds(milliseconds: int64) -> Duration ``` Exactly `milliseconds` milliseconds. Cannot overflow: every `int64` count of milliseconds fits. | Name | Type | Description | | -------------- | ------- | --------------------- | | `milliseconds` | `int64` | how many milliseconds | **Returns**: that many milliseconds [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Time/Src/Duration.rux#L67){rel=""nofollow""} ### `FromMicroseconds` ```rux pub func FromMicroseconds(microseconds: int64) -> Duration ``` Exactly `microseconds` microseconds. | Name | Type | Description | | -------------- | ------- | --------------------- | | `microseconds` | `int64` | how many microseconds | **Returns**: that many microseconds [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Time/Src/Duration.rux#L75){rel=""nofollow""} ### `FromNanoseconds` ```rux pub func FromNanoseconds(nanoseconds: int64) -> Duration ``` Exactly `nanoseconds` nanoseconds. | Name | Type | Description | | ------------- | ------- | -------------------- | | `nanoseconds` | `int64` | how many nanoseconds | **Returns**: that many nanoseconds [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Time/Src/Duration.rux#L83){rel=""nofollow""} ## Methods ### `IsZero` ```rux pub func IsZero(self: &Duration) -> bool ``` Whether this span is exactly nothing. **Returns**: whether the span is exactly zero [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Time/Src/Duration.rux#L103){rel=""nofollow""} ### `IsNegative` ```rux pub func IsNegative(self: &Duration) -> bool ``` Whether this span is negative. The sign lives in the seconds alone, which the normalization guarantees. **Returns**: whether the span runs backwards [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Time/Src/Duration.rux#L111){rel=""nofollow""} ### `WholeSeconds` ```rux pub func WholeSeconds(self: &Duration) -> int64 ``` The whole seconds, rounded toward negative infinity. **Returns**: the whole seconds, truncated toward zero [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Time/Src/Duration.rux#L118){rel=""nofollow""} ### `SubsecondNanoseconds` ```rux pub func SubsecondNanoseconds(self: &Duration) -> uint32 ``` The fraction beyond the whole seconds, in nanoseconds, always in \[0, 1e9). **Returns**: the nanoseconds within the second, in `[0, 999999999]` [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Time/Src/Duration.rux#L125){rel=""nofollow""} ### `TotalMilliseconds` ```rux pub func TotalMilliseconds(self: &Duration) -> int64? ``` This span as milliseconds, truncated toward zero, or `None` where an `int64` of them cannot hold it. **Returns**: the whole span in milliseconds, or `None` when it does not fit [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Time/Src/Duration.rux#L132){rel=""nofollow""} ### `TotalMicroseconds` ```rux pub func TotalMicroseconds(self: &Duration) -> int64? ``` This span as microseconds, truncated toward zero. **Returns**: the whole span in microseconds, or `None` when it does not fit [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Time/Src/Duration.rux#L139){rel=""nofollow""} ### `TotalNanoseconds` ```rux pub func TotalNanoseconds(self: &Duration) -> int64? ``` This span as nanoseconds, or `None` where an `int64` of them cannot hold it — about 292 years. **Returns**: the whole span in nanoseconds, or `None` when it does not fit [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Time/Src/Duration.rux#L146){rel=""nofollow""} ### `Plus` ```rux pub func Plus(self: &Duration, other: Duration) -> Duration? ``` The sum of two spans, or `None` past the range. | Name | Type | Description | | ------- | ---------- | ---------------------------- | | `other` | `Duration` | the value to compare against | **Returns**: the sum, or `None` when it does not fit [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Time/Src/Duration.rux#L164){rel=""nofollow""} ### `Minus` ```rux pub func Minus( self: &Duration, other: Duration ) -> Duration? ``` The difference of two spans, or `None` past the range. | Name | Type | Description | | ------- | ---------- | ---------------------------- | | `other` | `Duration` | the value to compare against | **Returns**: the difference, or `None` when it does not fit [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Time/Src/Duration.rux#L179){rel=""nofollow""} ### `Negated` ```rux pub func Negated(self: &Duration) -> Duration? ``` This span negated, or `None` for the one value whose negation does not fit. **Returns**: the span running the other way, or `None` when it does not fit [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Time/Src/Duration.rux#L193){rel=""nofollow""} ### `Times` ```rux pub func Times(self: &Duration, factor: int64) -> Duration? ``` This span scaled by a whole factor, or `None` past the range. | Name | Type | Description | | -------- | ------- | ------------------- | | `factor` | `int64` | what to multiply by | **Returns**: the product, or `None` when it does not fit [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Time/Src/Duration.rux#L202){rel=""nofollow""} ### `Equals` ```rux pub func Equals(self: &Duration, other: Duration) -> bool ``` Whether two spans are the same time. | Name | Type | Description | | ------- | ---------- | ---------------------------- | | `other` | `Duration` | the value to compare against | **Returns**: whether the two spans are the same length [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Time/Src/Duration.rux#L219){rel=""nofollow""} ### `Compare` ```rux pub func Compare( self: &Duration, other: Duration ) -> Ordering ``` How this span orders against `other`. Two comparisons, which the normalization pays for: the seconds decide, and the fractions only tie-break. | Name | Type | Description | | ------- | ---------- | ---------------------------- | | `other` | `Duration` | the value to compare against | **Returns**: how this span orders against `other` [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Time/Src/Duration.rux#L228){rel=""nofollow""} ## Implements Display `Duration` conforms to `Display`. ### `WriteDisplay` ```rux pub func WriteDisplay( self: &Duration, writer: &var TextWriter, spec: FormatSpec ) -> ! FormatError ``` Writes the span as signed decimal seconds followed by `s`. The magnitude is recomputed from the normalized representation rather than read off it: a negative duration stores minus one and a half seconds as seconds = -2 with a fraction of 0.5, so printing the fields as they sit would say "-2.5s". A precision names exactly that many fractional digits, 0 through 9, and truncates. Without one the fraction is written to the digits it has with trailing zeros trimmed, and omitted when it is zero, so a whole number of seconds renders as one. Reports whatever the writer reported, and `UnsupportedRequest` for a style other than `seconds` or for a precision past nine. | Name | Type | Description | | -------- | ----------------- | ------------------------------ | | `writer` | `&var TextWriter` | the destination | | `spec` | `FormatSpec` | what the placeholder asked for | **Returns**: success when the whole rendering was accepted [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Time/Src/Duration.rux#L109){rel=""nofollow""} ## Implements Debug `Duration` conforms to `Debug`. ### `WriteDebug` ```rux pub func WriteDebug( self: &Duration, writer: &var TextWriter, spec: FormatSpec ) -> ! FormatError ``` The same text as `Display`: a span has one reading. The failures [`WriteDisplay`](https://rux-lang.dev/docs/api/time/duration#write-display) reports. | Name | Type | Description | | -------- | ----------------- | ------------------------------ | | `writer` | `&var TextWriter` | the destination | | `spec` | `FormatSpec` | what the placeholder asked for | **Returns**: success when the whole rendering was accepted [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Time/Src/Duration.rux#L129){rel=""nofollow""} ## Related ### `NanosecondsPerSecond` ```rux pub const NanosecondsPerSecond: uint32 = 1000000000; ``` How many nanoseconds one second holds. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Time/Src/Duration.rux#L14){rel=""nofollow""} ### `ParseDuration` ```rux pub func ParseDuration(text: char8[..]) -> Duration ! TimeParseError ``` Reads a span written as signed decimal seconds followed by `s`. Accepts what `Display` writes: an optional sign, at least one digit, an optional fraction of up to nine digits, and a closing `s`. A leading `+` is accepted and means the same as no sign. Reports `InvalidSyntax` with the byte offset where the shape stopped matching, and `ExcessiveFraction` at the first digit that a nanosecond cannot hold. A magnitude too large for the representation is `InvalidSyntax` at the digit that overflowed, since the text is well formed and the value simply is not one. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Time/Src/DurationText.rux#L143){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------ | ----------- | ---------------- | | `text` | `char8[..]` | the text to read | **Returns**: the span, or why the text is not one # Instant A reading of the monotonic clock. ```rux pub struct Instant { // private fields } ``` `Copy`. Meaningful only against another reading from the same process: there is no epoch and no calendar here, which is the point — nothing anybody does to the wall clock changes what [`Since`](https://rux-lang.dev/docs/api/time/instant#since) answers. ## Associated functions ### `Now` ```rux pub func Now() -> Instant ``` The clock, read now. Cannot fail on any supported system: the monotonic clock exists from boot and needs no permission. **Returns**: the monotonic clock, read now [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Time/Src/Instant.rux#L33){rel=""nofollow""} ## Methods ### `Since` ```rux pub func Since( self: &Instant, earlier: Instant ) -> Duration? ``` The time between `earlier` and this reading, or `None` when `earlier` is not earlier. Refusing the reversed pair rather than answering with garbage is what makes a mixed-up argument order a visible bug instead of a wildly large duration. | Name | Type | Description | | --------- | --------- | ------------------- | | `earlier` | `Instant` | the earlier reading | **Returns**: the time between the two readings, or `None` when `earlier` is not earlier [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Time/Src/Instant.rux#L60){rel=""nofollow""} ### `Elapsed` ```rux pub func Elapsed(self: &Instant) -> Duration ``` The time from this reading to now. **Returns**: the time from this reading to now [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Time/Src/Instant.rux#L71){rel=""nofollow""} ## Implements Debug `Instant` conforms to `Debug`. ### `WriteDebug` ```rux pub func WriteDebug( self: &Instant, writer: &var TextWriter, spec: FormatSpec ) -> ! FormatError ``` Writes the reading as `Instant(nanoseconds: N)`. The tick count is shown as it is held, in the unit it is held in, named and wrapped so it cannot be mistaken for a moment on any calendar. There is no `Display` counterpart: a monotonic reading has no text for a reader, only a difference from another reading, and that difference is a [`Duration`](https://rux-lang.dev/docs/api/time/duration). Reports whatever the writer reported, and `UnsupportedRequest` for any style or precision — a reading has one form, and neither a style nor a fraction has anything to select here. | Name | Type | Description | | -------- | ----------------- | ------------------------------ | | `writer` | `&var TextWriter` | the destination | | `spec` | `FormatSpec` | what the placeholder asked for | **Returns**: success when the whole reading was accepted [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Time/Src/Instant.rux#L26){rel=""nofollow""} # OffsetDateTime A date and time together with the offset from UTC they are stated in. ```rux pub struct OffsetDateTime { pub dateTime: DateTime; pub offset: UtcOffset; } ``` [`DateTime`](https://rux-lang.dev/docs/api/time/date-time) deliberately carries no offset, since what offset a bare date and time is in is usually the caller's knowledge rather than the value's. This is the pairing for when it is not: an instant written down for interchange, where the offset is part of what was recorded and losing it changes the meaning. `Copy`, and exactly as wide as its two halves. ## Fields | Name | Type | Description | | ---------- | ----------- | ------------------------------------------------- | | `dateTime` | `DateTime` | The local date and time, as stated in `offset`. | | `offset` | `UtcOffset` | The offset from UTC that `dateTime` is stated in. | ## Constructors ### `OffsetDateTime` ```rux pub func OffsetDateTime( dateTime: DateTime, offset: UtcOffset ) -> OffsetDateTime ``` The local date and time `dateTime` paired with the offset it is stated in. Cannot fail: both halves are already valid, and no combination of a valid date-time and a valid offset is invalid. Runs in constant time and allocates nothing. | Name | Type | Description | | ---------- | ----------- | ------------------------------------------------ | | `dateTime` | `DateTime` | the local date and time | | `offset` | `UtcOffset` | the offset from UTC that `dateTime` is stated in | **Returns**: the pairing [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Time/Src/CalendarText.rux#L37){rel=""nofollow""} ## Methods ### `ToTimestamp` ```rux pub func ToTimestamp(self: &OffsetDateTime) -> Timestamp ``` The moment this names in UTC. Cannot fail; runs in constant time and allocates nothing. **Returns**: the instant, as a timestamp [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Time/Src/CalendarText.rux#L45){rel=""nofollow""} ## Implements Display `OffsetDateTime` conforms to `Display`. ### `WriteDisplay` ```rux pub func WriteDisplay( self: &OffsetDateTime, writer: &var TextWriter, spec: FormatSpec ) -> ! FormatError ``` Writes the moment as RFC 3339: `YYYY-MM-DDTHH:MM:SS[.fraction]` followed by `Z` or a signed `HH:MM`. This is the type that can produce RFC 3339, because it is the one that carries an offset. The offset is written as it is held rather than normalized to UTC: what was recorded includes where, and shifting it away would discard that. Reports whatever the writer reported, `UnsupportedRequest` for a style other than `iso8601` or `rfc3339`, and `UnsupportedRequest` for a precision past nine. | Name | Type | Description | | -------- | ----------------- | ------------------------------ | | `writer` | `&var TextWriter` | the destination | | `spec` | `FormatSpec` | what the placeholder asked for | **Returns**: success when the whole moment was accepted [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Time/Src/CalendarText.rux#L305){rel=""nofollow""} ## Implements Debug `OffsetDateTime` conforms to `Debug`. ### `WriteDebug` ```rux pub func WriteDebug( self: &OffsetDateTime, writer: &var TextWriter, spec: FormatSpec ) -> ! FormatError ``` The same text as `Display`. The failures [`WriteDisplay`](https://rux-lang.dev/docs/api/time/offset-date-time#write-display) reports. | Name | Type | Description | | -------- | ----------------- | ------------------------------ | | `writer` | `&var TextWriter` | the destination | | `spec` | `FormatSpec` | what the placeholder asked for | **Returns**: success when the whole moment was accepted [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Time/Src/CalendarText.rux#L321){rel=""nofollow""} ## Related ### `ParseRfc3339` ```rux pub func ParseRfc3339(text: char8[..]) -> OffsetDateTime ! TimeParseError ``` Reads `YYYY-MM-DDTHH:MM:SS[.fraction](Z|+HH:MM|-HH:MM)`. The offset is required, which is what RFC 3339 requires and what makes the result a moment rather than a local reading. Second 60 folds to the last nanosecond of second 59, as this package's leap-second policy states; formatting never produces second 60, so the fold is one-way and the round trip is clean for every ordinary moment. The failures the date, time and offset readers report, plus `InvalidSyntax` for text after the offset. Each carries the byte offset where it was found. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Time/Src/CalendarParse.rux#L280){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------ | ----------- | ---------------- | | `text` | `char8[..]` | the text to read | **Returns**: the moment with the offset it was stated in, or why the text is not one # Stopwatch A pausable timer over the monotonic clock. ```rux pub struct Stopwatch { // private fields } ``` `Copy`, owning nothing; a copy is an independent stopwatch with the same history. Starts stopped at zero. The elapsed time is the sum of every stretch between a start and a stop, plus the current stretch while running. ## Constructors ### `Stopwatch` ```rux pub func Stopwatch() -> Stopwatch ``` A stopwatch that is stopped and reads zero. Cannot fail and does not read the clock. **Returns**: a stopped stopwatch at zero [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Time/Src/Stopwatch.rux#L34){rel=""nofollow""} ## Associated functions ### `StartNew` ```rux pub func StartNew() -> Stopwatch ``` A stopwatch that reads zero and is already running. Reads the clock once. Cannot fail. **Returns**: a running stopwatch, started now [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Time/Src/Stopwatch.rux#L42){rel=""nofollow""} ## Methods ### `Start` ```rux pub func Start(self: &var Stopwatch) ``` Starts the stopwatch, or resumes it from the total it already holds. Does nothing when it is already running, so a second start does not restart the current stretch. Cannot fail. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Time/Src/Stopwatch.rux#L51){rel=""nofollow""} ### `Stop` ```rux pub func Stop(self: &var Stopwatch) ``` Stops the stopwatch, adding the current stretch to its total. Does nothing when it is already stopped. The total then stays fixed until the stopwatch is started again. Cannot fail. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Time/Src/Stopwatch.rux#L60){rel=""nofollow""} ### `Reset` ```rux pub func Reset(self: &var Stopwatch) ``` Stops the stopwatch and sets it back to zero, clearing the laps. Cannot fail and does not read the clock. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Time/Src/Stopwatch.rux#L69){rel=""nofollow""} ### `Restart` ```rux pub func Restart(self: &var Stopwatch) ``` Sets the stopwatch back to zero, clearing the laps, and starts it. The same as [`Reset`](https://rux-lang.dev/docs/api/time/stopwatch#reset) followed by [`Start`](https://rux-lang.dev/docs/api/time/stopwatch#start), with one clock reading. Cannot fail. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Time/Src/Stopwatch.rux#L78){rel=""nofollow""} ### `IsRunning` ```rux pub func IsRunning(self: &Stopwatch) -> bool ``` Whether the stopwatch is running. Cannot fail and does not read the clock. **Returns**: true between a start and the next stop or reset [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Time/Src/Stopwatch.rux#L87){rel=""nofollow""} ### `Elapsed` ```rux pub func Elapsed(self: &Stopwatch) -> Duration ``` The total elapsed time: every finished stretch, plus the current one while running. Reading it does not stop or otherwise change the stopwatch. Reads the clock only while running, and two readings of a stopped stopwatch are equal. Cannot fail. **Returns**: the elapsed time, never negative [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Time/Src/Stopwatch.rux#L99){rel=""nofollow""} ### `Lap` ```rux pub func Lap(self: &var Stopwatch) -> Duration ``` Ends the current lap and returns its length: the elapsed time since the previous lap ended, or since zero. The stopwatch keeps running or stays stopped as it was; only time the stopwatch counted is part of a lap, so a lap spanning a pause excludes the pause. The laps since the last reset add up to the elapsed time at the end of the last one. Cannot fail. **Returns**: the length of the lap just ended, never negative [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Time/Src/Stopwatch.rux#L112){rel=""nofollow""} # TimeOfDay A time within a day, to the nanosecond. ```rux pub struct TimeOfDay { pub hour: uint8; pub minute: uint8; pub second: uint8; pub nanosecond: uint32; } ``` `Copy`, and only constructible valid. The second stops at 59: leap seconds are a policy for the text boundary, not a representable value here. ## Fields | Name | Type | Description | | ------------ | -------- | ----------------------------- | | `hour` | `uint8` | The hour, 0 through 23. | | `minute` | `uint8` | The minute, 0 through 59. | | `second` | `uint8` | The second, 0 through 59. | | `nanosecond` | `uint32` | The fraction, in nanoseconds. | ## Associated functions ### `New` ```rux pub func New( hour: uint8, minute: uint8, second: uint8, nanosecond: uint32 ) -> TimeOfDay? ``` The time, when it exists. | Name | Type | Description | | ------------ | -------- | -------------------------------- | | `hour` | `uint8` | the hour, 0 through 23 | | `minute` | `uint8` | the minute, 0 through 59 | | `second` | `uint8` | the second, 0 through 59 | | `nanosecond` | `uint32` | the nanosecond within the second | **Returns**: the time, or `None` when the components do not name one [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Time/Src/Calendar.rux#L157){rel=""nofollow""} ### `Midnight` ```rux pub func Midnight() -> TimeOfDay ``` Midnight exactly. **Returns**: the first instant of a day [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Time/Src/Calendar.rux#L172){rel=""nofollow""} ## Methods ### `SecondsFromMidnight` ```rux pub func SecondsFromMidnight(self: &TimeOfDay) -> uint32 ``` The seconds from midnight to this time, ignoring the fraction. **Returns**: how many whole seconds into the day this is [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Time/Src/Calendar.rux#L179){rel=""nofollow""} ## Implements Display `TimeOfDay` conforms to `Display`. ### `WriteDisplay` ```rux pub func WriteDisplay( self: &TimeOfDay, writer: &var TextWriter, spec: FormatSpec ) -> ! FormatError ``` Writes the time as `HH:MM:SS`, with a fractional part when there is one. A precision names exactly that many fractional digits, 0 through 9, and truncates. Without one the fraction is written to the digits it has with trailing zeros trimmed, and omitted when it is zero. Reports whatever the writer reported, `UnsupportedRequest` for a style other than `iso8601` or `rfc3339`, and `UnsupportedRequest` for a precision past nine, which no fraction has. | Name | Type | Description | | -------- | ----------------- | ------------------------------ | | `writer` | `&var TextWriter` | the destination | | `spec` | `FormatSpec` | what the placeholder asked for | **Returns**: success when the whole time was accepted [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Time/Src/Calendar.rux#L189){rel=""nofollow""} ## Implements Debug `TimeOfDay` conforms to `Debug`. ### `WriteDebug` ```rux pub func WriteDebug( self: &TimeOfDay, writer: &var TextWriter, spec: FormatSpec ) -> ! FormatError ``` The same text as `Display`. The failures [`WriteDisplay`](https://rux-lang.dev/docs/api/time/time-of-day#write-display) reports. | Name | Type | Description | | -------- | ----------------- | ------------------------------ | | `writer` | `&var TextWriter` | the destination | | `spec` | `FormatSpec` | what the placeholder asked for | **Returns**: success when the whole time was accepted [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Time/Src/Calendar.rux#L208){rel=""nofollow""} ## Related ### `ParseTimeOfDay` ```rux pub func ParseTimeOfDay(text: char8[..]) -> TimeOfDay ! TimeParseError ``` Reads `HH:MM:SS` with an optional fractional second. Reports `InvalidSyntax` for a shape that does not match, `InvalidTime` for a field outside its range, and `ExcessiveFraction` for more fraction digits than a nanosecond holds. Second 60 folds rather than failing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Time/Src/CalendarParse.rux#L246){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------ | ----------- | ---------------- | | `text` | `char8[..]` | the text to read | **Returns**: the time of day, or why the text is not one # TimeParseError Why text could not be read as a calendar value. ```rux pub variant TimeParseError { InvalidSyntax(uint), InvalidMonth(uint), NonexistentDay(uint), InvalidTime(uint), ExcessiveFraction(uint), InvalidOffset(uint) } ``` Failure-only: every case is a failure, and each carries the zero-based UTF-8 byte offset into the text where it was found. Success is `Result::Success`. Copy, carrying one offset. ## Cases | Name | Description | | ------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `InvalidSyntax(uint)` | The text does not have the shape required: a missing separator, a non-digit where a digit belongs, text after the value, or input that stops early. The offset is where the shape stopped matching, which is the text's length when it ran out. | | `InvalidMonth(uint)` | A well-formed two-digit month naming no month. The offset is the first of its digits. | | `NonexistentDay(uint)` | A well-formed day that the month does not have, such as the thirtieth of February. The offset is the first of its digits. | | `InvalidTime(uint)` | A well-formed hour, minute or second outside its range. The offset is the first digit of the offending field. Second 60 is not here: it is the leap second, and it folds rather than failing. | | `ExcessiveFraction(uint)` | More fraction digits than a nanosecond can hold. The offset is the first digit that could not be kept. | | `InvalidOffset(uint)` | A well-formed offset outside what an offset may be. The offset is the sign that opened it. | ## Implements ParseFailure `TimeParseError` conforms to `ParseFailure`. ### `Offset` ```rux pub func Offset(self: &TimeParseError) -> uint ``` Where in the input the failure was found. Borrows the error. Cannot fail; runs in constant time and allocates nothing. **Returns**: the zero-based UTF-8 byte offset, which is the text's length at end of input [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Time/Src/CalendarParse.rux#L46){rel=""nofollow""} # Timestamp A moment in UTC: seconds since the Unix epoch and a fraction, normalized. ```rux pub struct Timestamp { pub seconds: int64; pub nanoseconds: uint32; } ``` `Copy`. The value is `seconds + nanoseconds / 1e9` from 1970-01-01T00:00:00 UTC, and `nanoseconds` is always in \[0, 1e9). ## Fields | Name | Type | Description | | ------------- | -------- | -------------------------------------------------- | | `seconds` | `int64` | Whole seconds since the epoch, carrying the sign. | | `nanoseconds` | `uint32` | The fraction, in nanoseconds, always in \[0, 1e9). | ## Associated functions ### `Epoch` ```rux pub func Epoch() -> Timestamp ``` The epoch itself: 1970-01-01T00:00:00 UTC exactly. **Returns**: 1970-01-01T00:00:00Z [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Time/Src/Timestamp.rux#L37){rel=""nofollow""} ### `Now` ```rux pub func Now() -> Timestamp ``` The wall clock, read now. **Returns**: the wall clock, read now [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Time/Src/Timestamp.rux#L44){rel=""nofollow""} ### `FromUnixSeconds` ```rux pub func FromUnixSeconds(seconds: int64) -> Timestamp ``` A moment from a plain second count, the shape most protocols carry. | Name | Type | Description | | --------- | ------- | ---------------- | | `seconds` | `int64` | how many seconds | **Returns**: that many seconds after the epoch [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Time/Src/Timestamp.rux#L69){rel=""nofollow""} ## Methods ### `UnixSeconds` ```rux pub func UnixSeconds(self: &Timestamp) -> int64 ``` The whole seconds since the epoch, rounded toward negative infinity. **Returns**: whole seconds since the epoch, negative before it [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Time/Src/Timestamp.rux#L76){rel=""nofollow""} ### `SubsecondNanoseconds` ```rux pub func SubsecondNanoseconds(self: &Timestamp) -> uint32 ``` The fraction beyond the whole seconds, in nanoseconds. **Returns**: the nanoseconds within the second, in `[0, 999999999]` [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Time/Src/Timestamp.rux#L83){rel=""nofollow""} ### `Since` ```rux pub func Since( self: &Timestamp, earlier: Timestamp ) -> Duration? ``` The span from `earlier` to this moment, or `None` past a duration's range. May be negative: the wall clock jumps, and two readings taken across a clock-set really can come back reversed. That is information, not an error, which is the difference from [`Instant::Since`](https://rux-lang.dev/docs/api/time/instant#since). | Name | Type | Description | | --------- | ----------- | ------------------- | | `earlier` | `Timestamp` | the earlier reading | **Returns**: the time between the two moments, or `None` when `earlier` is not earlier [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Time/Src/Timestamp.rux#L93){rel=""nofollow""} ### `Plus` ```rux pub func Plus( self: &Timestamp, span: Duration ) -> Timestamp? ``` This moment shifted by `span`, or `None` past the range. | Name | Type | Description | | ------ | ---------- | ------------ | | `span` | `Duration` | the duration | **Returns**: the moment that far later, or `None` when it does not fit [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Time/Src/Timestamp.rux#L102){rel=""nofollow""} ### `Equals` ```rux pub func Equals(self: &Timestamp, other: Timestamp) -> bool ``` Whether two timestamps name the same moment. | Name | Type | Description | | ------- | ----------- | ---------------------------- | | `other` | `Timestamp` | the value to compare against | **Returns**: whether the two name the same moment [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Time/Src/Timestamp.rux#L114){rel=""nofollow""} ### `Compare` ```rux pub func Compare( self: &Timestamp, other: Timestamp ) -> Ordering ``` How this moment orders against `other`. | Name | Type | Description | | ------- | ----------- | ---------------------------- | | `other` | `Timestamp` | the value to compare against | **Returns**: how this moment orders against `other` [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Time/Src/Timestamp.rux#L122){rel=""nofollow""} ### `IsInCalendarRange` ```rux pub func IsInCalendarRange(self: &Timestamp) -> bool ``` Whether this moment falls inside the years the calendar spells, and so has an RFC 3339 text. The bound is years 0000 through 9999, which is the range [`Date`](https://rux-lang.dev/docs/api/time/date) arithmetic already treats as the package's own and the range RFC 3339's four year digits allow. A caller that must not meet a formatting failure asks here first; one that renders through a placeholder learns the same thing as `ValueOutOfRange`. Borrows the moment and leaves it untouched. Cannot fail; runs in constant time and allocates nothing. **Returns**: true when the calendar form exists for this moment [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Time/Src/Timestamp.rux#L32){rel=""nofollow""} ## Implements Display `Timestamp` conforms to `Display`. ### `WriteDisplay` ```rux pub func WriteDisplay( self: &Timestamp, writer: &var TextWriter, spec: FormatSpec ) -> ! FormatError ``` Writes the moment as RFC 3339 in UTC, or as the Unix second count under the `unix` style. The calendar form is the default and the only one an unadorned placeholder produces: `1970-01-01T00:00:00Z` rather than `0`. `rfc3339` and `iso8601` name that same form explicitly, and `unix` asks for the signed second count instead — a value with two readings does not get to guess which one a caller meant. A precision names exactly that many fractional digits, 0 through 9, and truncates, in either form. Without one the fraction is written to the digits it has with trailing zeros trimmed, and omitted when it is zero. Reports whatever the writer reported, `UnsupportedRequest` for a style other than the three named above or for a precision past nine, and `ValueOutOfRange` for a moment outside years 0000 through 9999, which RFC 3339's four year digits cannot spell. The range is checked before anything is written, so a refused moment leaves the destination as it was. | Name | Type | Description | | -------- | ----------------- | ------------------------------ | | `writer` | `&var TextWriter` | the destination | | `spec` | `FormatSpec` | what the placeholder asked for | **Returns**: success when the whole moment was accepted [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Time/Src/Timestamp.rux#L86){rel=""nofollow""} ## Implements Debug `Timestamp` conforms to `Debug`. ### `WriteDebug` ```rux pub func WriteDebug( self: &Timestamp, writer: &var TextWriter, spec: FormatSpec ) -> ! FormatError ``` The same text as `Display`: a moment has one reading, and the style chooses between the two forms here too. The failures [`WriteDisplay`](https://rux-lang.dev/docs/api/time/timestamp#write-display) reports, including `ValueOutOfRange` before any output. | Name | Type | Description | | -------- | ----------------- | ------------------------------ | | `writer` | `&var TextWriter` | the destination | | `spec` | `FormatSpec` | what the placeholder asked for | **Returns**: success when the whole moment was accepted [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Time/Src/Timestamp.rux#L101){rel=""nofollow""} # UtcOffset A fixed shift from UTC, in whole minutes. ```rux pub struct UtcOffset { pub seconds: int32; } ``` Fixed is the word doing the work: this names what an offset is at one moment, and never which zone produced it or when that zone changes its mind. Zone rules are a database with a release cycle, and belong to a later phase. ## Fields | Name | Type | Description | | --------- | ------- | ------------------------------------------------------------------------- | | `seconds` | `int32` | The shift in seconds east of UTC, negative west, within a day either way. | ## Associated functions ### `Utc` ```rux pub func Utc() -> UtcOffset ``` UTC itself. **Returns**: the zero offset [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Time/Src/Calendar.rux#L197){rel=""nofollow""} ### `Of` ```rux pub func Of(hours: int32, minutes: int32) -> UtcOffset? ``` The offset `hours` and `minutes` from UTC, when it is one an offset can be. The two carry the same sign — minus five thirty is `Of(-5, -30)` — and the whole must stay within a day. Real offsets stop at eighteen hours, but text may carry any legal-looking one and refusing to represent it would turn parsing into policy. | Name | Type | Description | | --------- | ------- | ---------------- | | `hours` | `int32` | how many hours | | `minutes` | `int32` | how many minutes | **Returns**: the offset, or `None` when it is outside the range UTC offsets take [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Time/Src/Calendar.rux#L209){rel=""nofollow""} ## Methods ### `TotalSeconds` ```rux pub func TotalSeconds(self: &UtcOffset) -> int32 ``` The whole seconds east of UTC, negative west. **Returns**: the offset in seconds, negative west of Greenwich [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Time/Src/Calendar.rux#L219){rel=""nofollow""} ## Implements Display `UtcOffset` conforms to `Display`. ### `WriteDisplay` ```rux pub func WriteDisplay( self: &UtcOffset, writer: &var TextWriter, spec: FormatSpec ) -> ! FormatError ``` Writes the offset as `Z` for UTC, and as a signed `+HH:MM` otherwise. `Z` rather than `+00:00` because that is what RFC 3339 names UTC, and because the two are the same offset written two ways rather than two different offsets. A value that must be `+00:00` in its output is not asking about the offset but about the format, which is a question for whatever assembles the text. Reports whatever the writer reported, and `UnsupportedRequest` for a style other than `iso8601` or `rfc3339`, or for a precision, which an offset has nothing to apply one to. | Name | Type | Description | | -------- | ----------------- | ------------------------------ | | `writer` | `&var TextWriter` | the destination | | `spec` | `FormatSpec` | what the placeholder asked for | **Returns**: success when the whole offset was accepted [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Time/Src/Calendar.rux#L224){rel=""nofollow""} ## Implements Debug `UtcOffset` conforms to `Debug`. ### `WriteDebug` ```rux pub func WriteDebug( self: &UtcOffset, writer: &var TextWriter, spec: FormatSpec ) -> ! FormatError ``` The same text as `Display`. The failures [`WriteDisplay`](https://rux-lang.dev/docs/api/time/utc-offset#write-display) reports. | Name | Type | Description | | -------- | ----------------- | ------------------------------ | | `writer` | `&var TextWriter` | the destination | | `spec` | `FormatSpec` | what the placeholder asked for | **Returns**: success when the whole offset was accepted [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Time/Src/Calendar.rux#L246){rel=""nofollow""} # SleepFor Stops the calling thread for at least `span`. ```rux pub func SleepFor(span: Duration) -> ! TimeError ``` At least: the system wakes the thread no earlier, and how much later is the scheduler's business. A negative or zero span returns at once. A signal can interrupt the wait on the Unix systems, and this goes back for the remainder until the whole span has passed — the interruption is invisible, which is what makes this safe to use for pacing. A span longer than one system wait can express is waited for in chunks rather than clamped, so a hundred-day sleep is a hundred days. Fails with `InvalidDuration` when the system refused the request, which a normalized non-negative span should not produce, and `Failed` for anything else. A caller with nothing to do about a failed wait says so with `SleepFor(span) catch { else => {} }`; the point is that it is no longer indistinguishable from success. ## Parameters | Name | Type | Description | | ------ | ---------- | -------------------- | | `span` | `Duration` | how long to wait for | **Returns**: nothing when the whole span was waited out, or why it was not ## Related ### `TimeError` ```rux pub enum TimeError: uint8 { InvalidDuration = 2, Failed = 3 } ``` Why a wait did not happen. `Copy`. Every case is a failure. An interruption is not one: a waiter that was cut short succeeds with the part of the span still to wait, and [`SleepFor`](https://rux-lang.dev/docs/api/time/sleep) goes back for it, because a caller that asked for a span asked for the whole span. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Time/Src/Sleep.rux#L32){rel=""nofollow""} **Cases** | Name | Value | Description | | ----------------- | ----- | ----------------------------------------------------------------------------- | | `InvalidDuration` | `2` | The system refused the request itself, rather than being unable to finish it. | | `Failed` | `3` | The system reported a failure this module has no name for. | ### `MaximumWaitMilliseconds` ```rux pub const MaximumWaitMilliseconds: int64 = 4294967294; ``` The longest interval one system wait may be asked for, in milliseconds. Windows takes a 32-bit count and reserves `0xFFFFFFFF` to mean "wait forever", so the largest finite request is one less. Every system's wait is chunked to this so that the loop is the same everywhere and so that a test of the chunking is a test of what actually runs. About 49.7 days. A span longer than this is waited for in more than one chunk. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Time/Src/Sleep.rux#L45){rel=""nofollow""} ### `WaitChunkMilliseconds` ```rux pub func WaitChunkMilliseconds(span: Duration) -> int64 ``` How long the next single wait should be asked for, given how much of the span is left. Returns the whole millisecond count to ask the system for: the remaining span rounded **up**, since a wait promises at least what was asked and never less, or [`MaximumWaitMilliseconds`](https://rux-lang.dev/docs/api/time/sleep#maximum-wait-milliseconds) when the remainder is longer than one wait can express. Never zero for a positive span, so a loop driven by this always makes progress. A negative or zero span gives zero, which is the value a caller uses to stop. This is where the old clamp was, and it is public so that the hundred-day case can be checked without waiting a hundred days. Cannot fail. Runs in constant time and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Time/Src/Sleep.rux#L58){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------ | ---------- | ---------------------------- | | `span` | `Duration` | how much of the wait is left | **Returns**: the milliseconds to ask the system for ### `MaximumWaitAttempts` ```rux pub const MaximumWaitAttempts: uint = 4096; ``` How many waits [`SleepFor`](https://rux-lang.dev/docs/api/time/sleep) will make before giving up on a span that never shrinks. A [`Waiter`](https://rux-lang.dev/docs/api/time/waiter) that reports success without waiting and without reducing the remainder would spin forever. This is not a limit any real wait reaches: the system waiter always either advances or fails. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Time/Src/Sleep.rux#L159){rel=""nofollow""} ### `SleepUsing<W>` ```rux pub func SleepUsing<W: Waiter>( waiter: &var W, span: Duration ) -> ! TimeError ``` Waits out `span` through `waiter`, retrying interruptions and chunking what one wait cannot express. A negative or zero span returns at once, having waited for nothing. Otherwise this calls `waiter` until it reports that nothing is left, so an interruption is invisible to the caller and a span longer than one wait takes several. Fails with whatever the waiter failed with, having stopped there rather than asking again. Fails with `Failed` when the waiter neither advanced nor failed [`MaximumWaitAttempts`](https://rux-lang.dev/docs/api/time/sleep#maximum-wait-attempts) times running, which no real wait does and which is what keeps a broken implementation from hanging a program. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Time/Src/Sleep.rux#L173){rel=""nofollow""} **Type parameters** | Name | Description | | ----------- | ----------------- | | `W: Waiter` | the waiter's type | **Parameters** | Name | Type | Description | | -------- | ---------- | --------------------- | | `waiter` | `&var W` | how to reach the wait | | `span` | `Duration` | how long to wait for | **Returns**: nothing when the whole span was waited out, or why it was not # Entropy Unpredictable bytes from the operating system. ## Installation Add `Entropy` to the `[Dependencies]` table of your package's `Rux.toml`: ```toml [Dependencies] Entropy = { Namespace = "Rux", Version = "0.1.0" } ``` Standard packages are declared by hand: the registry does not serve them, so `rux add Rux/Entropy` cannot add them. ## Dependencies - [`Core`](https://rux-lang.dev/docs/api/core) 0.1.0 - [`FreeBSD`](https://rux-lang.dev/docs/api/freebsd) 0.1.0 (FreeBSD only) - [`Linux`](https://rux-lang.dev/docs/api/linux) 0.1.0 (Linux only) - [`macOS`](https://rux-lang.dev/docs/api/macos) 0.1.0 (macOS only) - [`Memory`](https://rux-lang.dev/docs/api/memory) 0.1.0 - [`Windows`](https://rux-lang.dev/docs/api/windows) 0.1.0 (Windows only) ## Guide ### What it provides | Module | Covers | | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `Error` | [`EntropyError`](https://rux-lang.dev/docs/api/entropy/entropy-error), and the questions worth asking of one | | `Source` | [`FillFromSource`](https://rux-lang.dev/docs/api/entropy/system-entropy#fill-from-source), the system generator reached the way each system wants | | `Fill` | [`EntropySource`](https://rux-lang.dev/docs/api/entropy/entropy-source), `Fill`, [`FillFrom`](https://rux-lang.dev/docs/api/entropy/entropy-source#fill-from) and [`FillWithRetries`](https://rux-lang.dev/docs/api/entropy/entropy-source#fill-with-retries) | ### Design This package does one thing: fill a buffer with bytes an adversary cannot guess. It is not a generator. There is no state here, nothing is reproducible, and drawing many bytes is slower than drawing them from a seeded generator — ask here for a seed, and take the rest from `Rux/Random`. Four systems offer four interfaces. Linux and FreeBSD have a `getrandom` system call that may write fewer bytes than asked for and may be interrupted by a signal, so filling a whole buffer means looping; a signal is retried a bounded number of times and then reported as `Interrupted` rather than spun on forever. Darwin's `arc4random_buf` is seeded before any user code runs, never blocks, and cannot fail, so it returns nothing at all. Windows has `BCryptGenRandom`, which fills the whole buffer or fails, and reports through an `NTSTATUS` rather than an error number. One [`EntropyError`](https://rux-lang.dev/docs/api/entropy/entropy-error) covers all four. A failure leaves nothing usable behind. Whatever a short read managed to write is zeroized before the failure is reported, because a half-filled key looks exactly as random as a whole one — a caller who ignores the result should get an obviously wrong buffer rather than a subtly weak one. ### Injecting failures Entropy failures are the ones nobody tests. Reaching them needs a kernel with no generator, a process being signalled steadily, or a cryptographic provider that refuses — none of which a test can arrange. So [`FillFrom`](https://rux-lang.dev/docs/api/entropy/entropy-source#fill-from) takes an [`EntropySource`](https://rux-lang.dev/docs/api/entropy/entropy-source) rather than calling the system by name: [`SystemEntropy`](https://rux-lang.dev/docs/api/entropy/system-entropy) is the real one, and a test supplies one that fails exactly when it wants it to. The code that handles a failure is then the same code in the test and in production, which is the only way to know it works. [`FillFrom`](https://rux-lang.dev/docs/api/entropy/entropy-source#fill-from) borrows an [`EntropySource`](https://rux-lang.dev/docs/api/entropy/entropy-source) interface view for the duration of the call. The view refers to the original source rather than copying it, so an implementation can keep mutable state directly in its own fields and callers observe the same state after the fill. [`FillWithRetries`](https://rux-lang.dev/docs/api/entropy/entropy-source#fill-with-retries) only retries a transient failure. `Interrupted` says a signal arrived rather than that anything is wrong; a system with no source and a provider that refused are both reported at once, since repeating them would only take longer to reach the same answer. Its `attempts` is how many *extra* tries to make, so zero is one attempt. ## Index ### Interfaces | Name | Summary | | ----------------------------------------------------------------------- | ---------------------------------------------------------- | | [`EntropySource`](https://rux-lang.dev/docs/api/entropy/entropy-source) | Something that can fill a buffer with unpredictable bytes. | ### Types | Name | Summary | | ----------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------- | | [`EntropyError`](https://rux-lang.dev/docs/api/entropy/entropy-error) | Why unpredictable bytes could not be obtained. | | [`SystemEntropy`](https://rux-lang.dev/docs/api/entropy/system-entropy) | The operating system's generator, as an [`EntropySource`](https://rux-lang.dev/docs/api/entropy/entropy-source). | ### Functions | Name | Summary | | ------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------ | | [`FillFrom`](https://rux-lang.dev/docs/api/entropy/entropy-source#fill-from) | Fills `length` bytes of `buffer` from `source`, in as many calls as it takes. | | [`FillWithRetries`](https://rux-lang.dev/docs/api/entropy/entropy-source#fill-with-retries) | Fills `length` bytes of `buffer` from `source`, trying again while the failure says trying again might work. | | [`Fill`](https://rux-lang.dev/docs/api/entropy/fill) | Fills `length` bytes of `buffer` from the operating system. | | [`NextUint64`](https://rux-lang.dev/docs/api/entropy/next-uint64) | An unpredictable 64-bit value, which is what a generator wants for a seed. | | [`FillFromSource`](https://rux-lang.dev/docs/api/entropy/system-entropy#fill-from-source) | Fills `length` bytes of `buffer` from the system's generator, in one pass. | ### Constants | Name | Summary | | ------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------- | | [`MaxEntropyAttempts`](https://rux-lang.dev/docs/api/entropy/system-entropy#max-entropy-attempts) | How many times a fill will go back to an interrupted source before giving up. | | [`MaxEntropyRequest`](https://rux-lang.dev/docs/api/entropy/system-entropy#max-entropy-request) | The largest request the source accepts in a single call. | # EntropySource Something that can fill a buffer with unpredictable bytes. ```rux pub interface EntropySource { func Fill( self: &var Self, buffer: *var opaque, length: uint ) -> ! EntropyError; } ``` Implemented by [`SystemEntropy`](https://rux-lang.dev/docs/api/entropy/system-entropy) for the operating system's generator, and by a test for a source that fails on demand. An implementation either fills the whole buffer and succeeds, or fails with why it did not. ## Requirements ### `Fill` ```rux func Fill( self: &var Self, buffer: *var opaque, length: uint ) -> ! EntropyError ``` Fills `length` bytes of `buffer` with unpredictable bytes. `buffer` is borrowed and written; `length` is read by value. Succeeds only when every byte was written. An implementation may write part of the buffer before failing — the caller is what guarantees nothing partial survives. `buffer` must be writable for `length` bytes. | Name | Type | Description | | -------- | ------------- | ---------------------- | | `buffer` | `*var opaque` | receives the bytes | | `length` | `uint` | how many bytes to fill | **Returns**: nothing when every byte was written, or why not [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Entropy/Src/Fill.rux#L28){rel=""nofollow""} ## Implementations | Type | Summary | | ----------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------- | | [`SystemEntropy`](https://rux-lang.dev/docs/api/entropy/system-entropy) | The operating system's generator, as an [`EntropySource`](https://rux-lang.dev/docs/api/entropy/entropy-source). | ## Related ### `FillFrom` ```rux pub func FillFrom( source: &var EntropySource, buffer: *var opaque, length: uint ) -> ! EntropyError ``` Fills `length` bytes of `buffer` from `source`, in as many calls as it takes. `source` is borrowed for the call; `buffer` is borrowed and written; `length` is read by value. Succeeds only when every byte was written, and otherwise fails with what the source reported. A request larger than a single call accepts is split, so a caller need not know what that limit is. A failure part-way through a split request is a failure of the whole request: there is no state in which some of a buffer is unpredictable and the rest is not, because nothing downstream could act on the difference. Runs in time proportional to `length` and allocates nothing. `buffer` must be writable for `length` bytes. On any failure the whole buffer is zeroized, including the parts an earlier call filled successfully. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Entropy/Src/Fill.rux#L79){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | -------------------- | ------------------------- | | `source` | `&var EntropySource` | where the bytes come from | | `buffer` | `*var opaque` | receives the bytes | | `length` | `uint` | how many bytes to fill | **Returns**: nothing when every byte was written, or why not ### `FillWithRetries` ```rux pub func FillWithRetries( source: &var EntropySource, buffer: *var opaque, length: uint, attempts: uint ) -> ! EntropyError ``` Fills `length` bytes of `buffer` from `source`, trying again while the failure says trying again might work. `source` is borrowed for the call; `buffer` is borrowed and written; `length` and `attempts` are read by value. `attempts` is how many extra tries to make, so zero is one attempt and behaves exactly like [`FillFrom`](https://rux-lang.dev/docs/api/entropy/entropy-source#fill-from). Only a transient failure is retried — `Interrupted`, which says a signal arrived rather than that anything is wrong. A system with no source and a provider that refused are both reported at once, because repeating them would only take longer to reach the same answer. Runs in time proportional to `length` times the attempts made, and allocates nothing. `buffer` must be writable for `length` bytes. Every failed attempt zeroizes the buffer, so a failure that exhausts the attempts leaves zeros. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Entropy/Src/Fill.rux#L113){rel=""nofollow""} **Parameters** | Name | Type | Description | | ---------- | -------------------- | ------------------------------------------------------------------- | | `source` | `&var EntropySource` | where the bytes come from | | `buffer` | `*var opaque` | receives the bytes | | `length` | `uint` | how many bytes to fill | | `attempts` | `uint` | how many times to go back to an interrupted source before giving up | **Returns**: nothing when every byte was written, or why not — `Interrupted` after `attempts` tries # EntropyError Why unpredictable bytes could not be obtained. ```rux pub enum EntropyError { Unsupported, Interrupted, Failed, TooLarge } ``` Every case is a failure: nothing was written that a caller may rely on. A filled buffer is the success channel of the `! EntropyError` the fill returns. ## Cases | Name | Description | | ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `Unsupported` | This system has no entropy source this package can reach. A kernel too old for its own generator reports this. It does not change while a program runs, so retrying is pointless. | | `Interrupted` | The source kept being interrupted, and the call gave up rather than looping forever. Ordinary on a process taking signals steadily. Worth one more attempt; not worth an unbounded number. | | `Failed` | The source refused for a reason the system did not make actionable. | | `TooLarge` | The request was larger than the source accepts in one call. Windows takes a 32-bit count, so a request above four gigabytes has no honest answer. Split it. | ## Methods ### `IsTransient` ```rux pub func IsTransient(self: *EntropyError) -> bool ``` Whether trying again might work. `self` is borrowed. True for `Interrupted`, which says a signal arrived rather than that anything is wrong. False for everything else: a system with no source will not grow one, and a refusal repeated is still a refusal. Cannot fail. Runs in constant time and allocates nothing. **Returns**: whether asking again could succeed [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Entropy/Src/Error.rux#L37){rel=""nofollow""} # SystemEntropy The operating system's generator, as an [`EntropySource`](https://rux-lang.dev/docs/api/entropy/entropy-source). ```rux pub struct SystemEntropy {} ``` Holds nothing: the system's generator needs no handle, no seed and no shutdown. It exists so that code taking a source can be handed the real one. ## Constructors ### `SystemEntropy` ```rux pub func SystemEntropy() -> SystemEntropy ``` The operating system's generator. Takes nothing and cannot fail. Costs nothing to make, so there is no reason to keep one around rather than making one where it is needed. Runs in constant time and allocates nothing. **Returns**: the source, which holds no state of its own [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Entropy/Src/Fill.rux#L45){rel=""nofollow""} ## Implements EntropySource `SystemEntropy` conforms to [`EntropySource`](https://rux-lang.dev/docs/api/entropy/entropy-source). ### `Fill` ```rux pub func Fill( self: &var SystemEntropy, buffer: *var opaque, length: uint ) -> ! EntropyError ``` Fills `length` bytes of `buffer` from the operating system. Exactly [`FillFromSource`](https://rux-lang.dev/docs/api/entropy/system-entropy#fill-from-source), reached through the interface. Succeeds only when every byte was written. Runs in time proportional to `length` and allocates nothing. `buffer` must be writable for `length` bytes. | Name | Type | Description | | -------- | ------------- | ---------------------- | | `buffer` | `*var opaque` | receives the bytes | | `length` | `uint` | how many bytes to fill | **Returns**: nothing when every byte was written, or why not [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Entropy/Src/Fill.rux#L60){rel=""nofollow""} ## Related ### `MaxEntropyAttempts` ```rux pub const MaxEntropyAttempts: uint = 16; ``` How many times a fill will go back to an interrupted source before giving up. A signal arriving during the call is ordinary and retrying is correct, but a process taking signals steadily must not spin forever inside what its caller believes is one operation. Reaching this reports `Interrupted`, which says exactly that and leaves trying again to the caller, who knows whether it is worth it. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Entropy/Src/Source.rux#L31){rel=""nofollow""} ### `MaxEntropyRequest` ```rux pub const MaxEntropyRequest: uint = 0xFFFFFFFF; ``` The largest request the source accepts in a single call. Windows takes a 32-bit count, so this is what a portable caller may ask for at once. A larger buffer is filled by asking more than once, which `Fill` does. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Entropy/Src/Source.rux#L37){rel=""nofollow""} ### `FillFromSource` ```rux pub func FillFromSource( buffer: *var opaque, length: uint ) -> ! EntropyError ``` Fills `length` bytes of `buffer` from the system's generator, in one pass. `buffer` is borrowed and written; `length` is read by value. Succeeds only when every byte was written. A zero length succeeds without touching anything. A length past what the source accepts is reported before the buffer is looked at, so an impossible request is refused whatever was passed with it; a null buffer with an ordinary length reports `Failed` rather than being written through. On Linux and FreeBSD a short count is not a failure, so this loops until the buffer is full; a signal in the middle is retried up to [`MaxEntropyAttempts`](https://rux-lang.dev/docs/api/entropy/system-entropy#max-entropy-attempts) times before reporting `Interrupted`. A kernel with no such call reports `Unsupported`. On Darwin the source cannot fail. On Windows a request above [`MaxEntropyRequest`](https://rux-lang.dev/docs/api/entropy/system-entropy#max-entropy-request) reports `TooLarge`, since the count is passed as 32 bits. Runs in time proportional to `length` and allocates nothing. `buffer` must be writable for `length` bytes. On any failure the buffer is zeroized, so a caller who ignores the result gets zeros rather than a partly random buffer that would pass a glance. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Entropy/Src/Source.rux#L55){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | ------------- | ---------------------- | | `buffer` | `*var opaque` | receives the bytes | | `length` | `uint` | how many bytes to fill | **Returns**: nothing when every byte was written in this one pass, or why not # Fill Fills `length` bytes of `buffer` from the operating system. ```rux pub func Fill( buffer: *var opaque, length: uint ) -> ! EntropyError ``` `buffer` is borrowed and written; `length` is read by value. This is the call to make when there is no reason to name a source: it is [`FillFrom`](https://rux-lang.dev/docs/api/entropy/entropy-source#fill-from) over [`SystemEntropy`](https://rux-lang.dev/docs/api/entropy/system-entropy), with the same contract. Runs in time proportional to `length` and allocates nothing. `buffer` must be writable for `length` bytes. On any failure the whole buffer is zeroized. ## Parameters | Name | Type | Description | | -------- | ------------- | ---------------------- | | `buffer` | `*var opaque` | receives the bytes | | `length` | `uint` | how many bytes to fill | **Returns**: nothing when every byte was written, or why not # NextUint64 An unpredictable 64-bit value, which is what a generator wants for a seed. ```rux pub func NextUint64() -> uint64 ! EntropyError ``` A failed draw scrubs its local copy before failing, so nothing of a partial draw is left behind on the stack. Runs in constant time and allocates nothing. **Returns**: eight unpredictable bytes as a value, or why the draw failed # Json JSON parsing and serialization. ## Installation Add `Json` to the `[Dependencies]` table of your package's `Rux.toml`: ```toml [Dependencies] Json = { Namespace = "Rux", Version = "0.1.0" } ``` Standard packages are declared by hand: the registry does not serve them, so `rux add Rux/Json` cannot add them. ## Dependencies - [`Allocator`](https://rux-lang.dev/docs/api/allocator) 0.1.0 - [`Collections`](https://rux-lang.dev/docs/api/collections) 0.1.0 - [`Core`](https://rux-lang.dev/docs/api/core) 0.1.0 - [`Format`](https://rux-lang.dev/docs/api/format) 0.1.0 - [`Io`](https://rux-lang.dev/docs/api/io) 0.1.0 - [`Text`](https://rux-lang.dev/docs/api/text) 0.1.0 ## Guide ### What it provides - **A document model** — move-only [`JsonValue`](https://rux-lang.dev/docs/api/json/json-value) trees with explicit `<-` transfers and deterministic `~Type` cleanup, covering the six kinds RFC 8259 defines. Objects keep arrival order, and numbers keep their original text, so an identifier past 2^53 comes back as itself rather than as the nearest double. - **A parser** — strict RFC 8259, refusing every JavaScript-only form. Duplicate object names are rejected by default, and the other three policies are chosen per call. - **A document or a reason, never both** — `Parse` and [`ParseWith`](https://rux-lang.dev/docs/api/json/parse#parse-with) return `JsonValue ! JsonParseError`. A refusal hands back no value at all, which is the distinction the old shape could not make: it answered a refused parse with `null`, and `null` is a perfectly good document, so a caller who did not read the outcome beside it could not tell one from the other. Whatever the parser had built when it stopped is released rather than handed over, so a caller is never left holding a partial tree. ```rux match Parse(allocator, bytes) { .Success(document) => Use(document), .Failure(reason) => Report(reason.Offset(), reason) } ``` - **Failures carry where, and the lexer's reason with them** — every case of [`JsonParseError`](https://rux-lang.dev/docs/api/json/json-parse-error) holds the zero-based byte offset where parsing stopped, reachable through `Text::ParseFailure`, and `Lexical` nests the [`JsonLexError`](https://rux-lang.dev/docs/api/json/json-lexer#json-lex-error) inside itself so a caller holding the failure cannot be holding half of it. `Display` gives the description and `Debug` names the case with its position: `JsonParseError::Lexical(MalformedNumber, 1)`. - **Limits** — depth, bytes, string length and container size, each refused under its own positioned reason, so a document written to exhaust the stack or the heap is refused while there is still room to refuse it. A limit the parser measures arrives as `TooDeep` or `TooManyEntries`; one the lexer measures arrives nested inside `Lexical`. - **Streaming** — events in document order from a stored `Rux/Io` reader handle, with a move-only owned buffer bounded by the largest token rather than by the document and safe operations borrowed through references. [`JsonEventReader::Failure`](https://rux-lang.dev/docs/api/json/json-event-reader#failure) answers the same positioned [`JsonParseError`](https://rux-lang.dev/docs/api/json/json-parse-error) the tree parser does, as an optional, so the two report a refusal the same way; its offset counts from the start of the document, not from the start of the buffer. A source whose `Read` fails with anything but the end of the stream stops the reader with `JsonParseError::Source`, and [`JsonEventReader::SourceError`](https://rux-lang.dev/docs/api/json/json-event-reader#source-error) hands back the `IoError` the source reported, so a broken stream is never mistaken for a malformed document. - **Writers** — compact and pretty, borrowing values without copying, escaping exactly what the grammar requires and no more, and refusing to write a NaN or an infinity because JSON cannot spell one. They report `! FormatError`, the same contract every writer in the workspace uses, so a document goes into anything a `TextWriter` reaches with no translation at the seam. What the destination said travels unchanged: a buffer that is merely full reports `InsufficientCapacity` and a stream that has died reports `WriterFailure`, where `JsonWriteError` had one case standing for both. A non-finite number, and a document nested past [`MaximumWriteDepth`](https://rux-lang.dev/docs/api/json/write-value#maximum-write-depth), are `ValueOutOfRange` — the value is good and the requested form cannot hold it. ## Index ### Types | Name | Summary | | ------------------------------------------------------------------------------------- | ------------------------------------------------------------- | | [`JsonEvent`](https://rux-lang.dev/docs/api/json/json-event-reader#json-event) | What just happened in the document. | | [`JsonEventReader`](https://rux-lang.dev/docs/api/json/json-event-reader) | Reads a document as events, pulling bytes as it needs them. | | [`JsonTokenKind`](https://rux-lang.dev/docs/api/json/json-lexer#json-token-kind) | What kind of token this is. | | [`JsonLexError`](https://rux-lang.dev/docs/api/json/json-lexer#json-lex-error) | Why lexing stopped. | | [`JsonLimits`](https://rux-lang.dev/docs/api/json/json-limits) | What a caller will accept from a document. | | [`JsonToken`](https://rux-lang.dev/docs/api/json/json-lexer#json-token) | One token, and where in the input it came from. | | [`JsonLexer`](https://rux-lang.dev/docs/api/json/json-lexer) | A JSON lexer over a byte slice. | | [`DuplicateKeyPolicy`](https://rux-lang.dev/docs/api/json/parse#duplicate-key-policy) | What to do about an object containing the same name twice. | | [`JsonParseError`](https://rux-lang.dev/docs/api/json/json-parse-error) | Why parsing stopped, and where. | | [`JsonParser`](https://rux-lang.dev/docs/api/json/json-parser) | A parser over a document. | | [`JsonKind`](https://rux-lang.dev/docs/api/json/json-value#json-kind) | Which kind of JSON value this is. | | [`JsonNumber`](https://rux-lang.dev/docs/api/json/json-number) | A JSON number, held as the text it was written with. | | [`JsonMember`](https://rux-lang.dev/docs/api/json/json-value#json-member) | A name-value pair inside an object. | | [`JsonValue`](https://rux-lang.dev/docs/api/json/json-value) | A JSON value: one of the six kinds, owning whatever it holds. | | [`JsonStyle`](https://rux-lang.dev/docs/api/json/write-value#json-style) | How a document should be laid out. | ### Functions | Name | Summary | | ------------------------------------------------------------------------------ | ---------------------------------------------------------------------- | | [`Parse`](https://rux-lang.dev/docs/api/json/parse) | Parses `input` into a value, rejecting duplicate names. | | [`ParseWith`](https://rux-lang.dev/docs/api/json/parse#parse-with) | Parses `input` under chosen limits and a chosen duplicate-name policy. | | [`WriteEscaped`](https://rux-lang.dev/docs/api/json/write-value#write-escaped) | Writes the escaped form of `text`, including its surrounding quotes. | | [`WriteValue`](https://rux-lang.dev/docs/api/json/write-value) | Writes `value` to `writer` in the given style. | ### Constants | Name | Summary | | ----------------------------------------------------------------------------------------- | ------------------------------------------------------- | | [`MaximumWriteDepth`](https://rux-lang.dev/docs/api/json/write-value#maximum-write-depth) | How deep a document may nest before the writer refuses. | # JsonEventReader Reads a document as events, pulling bytes as it needs them. ```rux pub struct JsonEventReader { // private fields } ``` ## Associated functions ### `New` ```rux pub func New( allocator: Allocator, source: Reader, limits: JsonLimits ) -> JsonEventReader ! IoError ``` A reader over `source` under `limits`. | Name | Type | Description | | ----------- | ------------ | -------------------------------------- | | `allocator` | `Allocator` | where the storage comes from | | `source` | `Reader` | the text to read | | `limits` | `JsonLimits` | the bounds the parse refuses to exceed | **Returns**: a reader positioned before the first event; `Other` when its buffer could not be allocated [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Json/Src/Events.rux#L102){rel=""nofollow""} ## Methods ### `Failure` ```rux pub func Failure(self: &JsonEventReader) -> JsonParseError? ``` Why reading stopped, positioned, or `none` while nothing has gone wrong. This is what a caller asks after [`Next`](https://rux-lang.dev/docs/api/json/json-event-reader#next) reports `Error`. A lexical refusal carries the lexer's own reason inside it rather than in a second call, so a caller holding the failure is holding all of it. The offset counts bytes from the start of the document, however many times the buffer has been refilled. A source that failed is reported as `Source`, and what it reported is on [`SourceError`](https://rux-lang.dev/docs/api/json/json-event-reader#source-error). **Returns**: the failure, positioned at the byte of the document the reader stopped on, or `none` [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Json/Src/Events.rux#L124){rel=""nofollow""} ### `SourceError` ```rux pub func SourceError(self: &JsonEventReader) -> IoError? ``` What the source reported when reading it failed, or `none` when it has not failed. The end of the stream is not a failure and is never reported here; any other `IoError` from the source's `Read` stops the reader, makes [`Next`](https://rux-lang.dev/docs/api/json/json-event-reader#next) report `Error` and [`Failure`](https://rux-lang.dev/docs/api/json/json-event-reader#failure) report `Source`, and is kept here unchanged, so a caller can tell a document that is malformed from a stream that broke. **Returns**: the source's failure, or `none` [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Json/Src/Events.rux#L134){rel=""nofollow""} ### `Text` ```rux pub func Text(self: &JsonEventReader) -> char8[..] ``` The text of the event just reported, valid until the next one. For a name, a string or a number. Escapes are left as written — resolving them would mean allocating, and a caller skipping past a field should not pay for its contents. **Returns**: the current event's text, borrowed from the input [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Json/Src/Events.rux#L143){rel=""nofollow""} ### `TextIsEscaped` ```rux pub func TextIsEscaped(self: &JsonEventReader) -> bool ``` Whether that text holds escapes a caller must resolve. **Returns**: whether the text still holds escape sequences a caller must decode [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Json/Src/Events.rux#L150){rel=""nofollow""} ### `Depth` ```rux pub func Depth(self: &JsonEventReader) -> uint ``` How deeply nested the reader currently is. **Returns**: how many arrays and objects are currently open [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Json/Src/Events.rux#L157){rel=""nofollow""} ### `Release` ```rux pub func Release(self: &var JsonEventReader) ``` Gives the buffer back. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Json/Src/Events.rux#L219){rel=""nofollow""} ### `Next` ```rux pub func Next(self: &var JsonEventReader) -> JsonEvent ``` The next event. Separators are consumed silently: a caller sees values and structure, not commas and colons, which is the level a streaming reader is useful at. **Returns**: the next event, or the end-of-input event [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Json/Src/Events.rux#L359){rel=""nofollow""} ## Destructor ```rux func ~JsonEventReader(self: &var JsonEventReader) ``` Releases the buffer. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Json/Src/Events.rux#L230){rel=""nofollow""} ## Related ### `JsonEvent` ```rux pub enum JsonEvent: int32 { End = 0, ObjectStart = 1, ObjectEnd = 2, ArrayStart = 3, ArrayEnd = 4, Name = 5, Text = 6, Number = 7, True = 8, False = 9, Null = 10, Error = 11 } ``` What just happened in the document. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Json/Src/Events.rux#L19){rel=""nofollow""} **Cases** | Name | Value | Description | | ------------- | ----- | ----------------------------------------------------------- | | `End` | `0` | The document is finished. | | `ObjectStart` | `1` | An object opened. | | `ObjectEnd` | `2` | An object closed. | | `ArrayStart` | `3` | An array opened. | | `ArrayEnd` | `4` | An array closed. | | `Name` | `5` | A member name; its text is available until the next event. | | `Text` | `6` | A string value; its text is available until the next event. | | `Number` | `7` | A number; its text is available until the next event. | | `True` | `8` | `true`. | | `False` | `9` | `false`. | | `Null` | `10` | `null`. | | `Error` | `11` | Something went wrong; the reason is on the reader. | # JsonLexer A JSON lexer over a byte slice. ```rux pub struct JsonLexer { pub position: uint; // private fields } ``` ## Fields | Name | Type | Description | | ---------- | ------ | ---------------------------- | | `position` | `uint` | How far reading has reached. | ## Constructors ### `JsonLexer` ```rux pub func JsonLexer( input: char8[..], limits: JsonLimits ) -> JsonLexer ``` A lexer over `input` under `limits`. | Name | Type | Description | | -------- | ------------ | -------------------------------------- | | `input` | `char8[..]` | the text to read | | `limits` | `JsonLimits` | the bounds the parse refuses to exceed | **Returns**: a lexer positioned at the start of the input [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Json/Src/Lexer.rux#L151){rel=""nofollow""} ## Methods ### `Position` ```rux pub func Position(self: &JsonLexer) -> uint ``` Where reading has reached, as a byte offset. **Returns**: how many bytes have been consumed [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Json/Src/Lexer.rux#L158){rel=""nofollow""} ### `Next` ```rux pub func Next(self: &var JsonLexer) -> JsonToken ``` The next token. **Returns**: the next token, or the end-of-input token [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Json/Src/Lexer.rux#L341){rel=""nofollow""} ## Related ### `JsonTokenKind` ```rux pub enum JsonTokenKind: int32 { End = 0, ObjectStart = 1, ObjectEnd = 2, ArrayStart = 3, ArrayEnd = 4, Colon = 5, Comma = 6, Text = 7, Number = 8, True = 9, False = 10, Null = 11, Error = 12 } ``` What kind of token this is. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Json/Src/Lexer.rux#L16){rel=""nofollow""} **Cases** | Name | Value | Description | | ------------- | ----- | -------------------------------------------------------- | | `End` | `0` | The input is exhausted. | | `ObjectStart` | `1` | `{` | | `ObjectEnd` | `2` | `}` | | `ArrayStart` | `3` | `[` | | `ArrayEnd` | `4` | `]` | | `Colon` | `5` | `:` | | `Comma` | `6` | `,` | | `Text` | `7` | A string, whose span excludes the quotes. | | `Number` | `8` | A number, whose span is its whole text. | | `True` | `9` | `true` | | `False` | `10` | `false` | | `Null` | `11` | `null` | | `Error` | `12` | Something that is not JSON, or a limit that was reached. | ### `JsonLexError` ```rux pub enum JsonLexError: int32 { None = 0, UnexpectedByte = 1, UnterminatedText = 2, BadEscape = 3, BadUnicodeEscape = 4, MalformedNumber = 5, InvalidUtf8 = 6, UnescapedControl = 7, TooManyBytes = 8, TextTooLong = 9, TooDeep = 10, TooManyEntries = 11 } ``` Why lexing stopped. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Json/Src/Lexer.rux#L47){rel=""nofollow""} **Cases** | Name | Value | Description | | ------------------ | ----- | ---------------------------------------------------------------------------- | | `None` | `0` | Nothing went wrong. | | `UnexpectedByte` | `1` | A byte that begins no token. | | `UnterminatedText` | `2` | A string that the input ended before closing. | | `BadEscape` | `3` | An escape sequence JSON does not define. | | `BadUnicodeEscape` | `4` | A `\u` escape that is not four hexadecimal digits. | | `MalformedNumber` | `5` | A number whose shape JSON's grammar does not allow. | | `InvalidUtf8` | `6` | Bytes that are not well-formed UTF-8. | | `UnescapedControl` | `7` | A control character appearing unescaped inside a string, which JSON forbids. | | `TooManyBytes` | `8` | The document is longer than the configured limit. | | `TextTooLong` | `9` | A string is longer than the configured limit. | | `TooDeep` | `10` | Containers are nested deeper than the configured limit. | | `TooManyEntries` | `11` | A container holds more entries than the configured limit. | ### `JsonToken` ```rux pub struct JsonToken { pub kind: JsonTokenKind; pub start: uint; pub end: uint; pub escaped: bool; pub error: JsonLexError; } ``` One token, and where in the input it came from. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Json/Src/Lexer.rux#L120){rel=""nofollow""} **Fields** | Name | Type | Description | | --------- | --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `kind` | `JsonTokenKind` | What kind of token this is. | | `start` | `uint` | Where its text starts, as a byte offset into the input. | | `end` | `uint` | Where its text ends. | | `escaped` | `bool` | For a string, whether it contains any escape that must be resolved. A string without one can be used directly from the input, which is what keeps ordinary documents free of copying. | | `error` | `JsonLexError` | Why lexing stopped, when the kind is `Error`. | # JsonLimits What a caller will accept from a document. ```rux pub struct JsonLimits { pub maximumBytes: uint; pub maximumTextBytes: uint; pub maximumDepth: uint; pub maximumEntries: uint; } ``` Every field is a refusal a caller might need to make against untrusted input, and every default is generous enough for ordinary documents and far short of what exhausts a machine. ## Fields | Name | Type | Description | | ------------------ | ------ | ----------------------------------------------------------------------------------------- | | `maximumBytes` | `uint` | The longest document, in bytes. | | `maximumTextBytes` | `uint` | The longest single string, in bytes. | | `maximumDepth` | `uint` | How deeply containers may nest. This is the one that protects a recursive parser's stack. | | `maximumEntries` | `uint` | How many elements or members one container may hold. | ## Associated functions ### `Default` ```rux pub func Default() -> JsonLimits ``` Limits generous enough for ordinary documents: sixty-four mebibytes, sixteen mebibyte strings, a hundred and twenty-eight levels of nesting, and a million entries per container. **Returns**: the limits an ordinary parse uses [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Json/Src/Lexer.rux#L94){rel=""nofollow""} ### `Unlimited` ```rux pub func Unlimited() -> JsonLimits ``` No limits at all, for input that is already trusted. Named so that choosing it is visible: a document read from the network should never use this, and a reviewer should be able to find every place that did. **Returns**: limits that refuse nothing, for input that is already trusted [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Json/Src/Lexer.rux#L108){rel=""nofollow""} # JsonNumber A JSON number, held as the text it was written with. ```rux pub struct JsonNumber { // private fields } ``` JSON does not say what precision a number has, so nothing here decides on the caller's behalf. Ask for the shape wanted — [`AsInt64`](https://rux-lang.dev/docs/api/json/json-number#as-int64), [`AsUint64`](https://rux-lang.dev/docs/api/json/json-number#as-uint64), [`AsFloat64`](https://rux-lang.dev/docs/api/json/json-number#as-float64) — and each reports whether the value fits. Keeping the text is also what lets a document round-trip exactly, which a parser converting to a double cannot do. ## Associated functions ### `New` ```rux pub func New( allocator: Allocator, text: char8[..] ) -> JsonNumber ! TextError ``` A number from its text, which is copied. | Name | Type | Description | | ----------- | ----------- | ---------------------------- | | `allocator` | `Allocator` | where the storage comes from | | `text` | `char8[..]` | the text to act on | **Returns**: the number, holding the text it was given [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Json/Src/Value.rux#L51){rel=""nofollow""} ## Methods ### `Text` ```rux pub func Text(self: &JsonNumber) -> StringView ``` The number exactly as written. **Returns**: the number's text, exactly as the input spelled it [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Json/Src/Value.rux#L61){rel=""nofollow""} ### `AsInt64` ```rux pub func AsInt64( self: &JsonNumber, result: *var int64 ) -> bool ``` The value as a signed integer, or `false` if it does not fit one. A number with a fraction or an exponent does not fit, even when its value happens to be whole: `1.0` is not an integer in JSON's grammar and pretending otherwise loses the distinction a document was making. | Name | Type | Description | | -------- | ------------ | ----------------------------------------- | | `result` | `*var int64` | receives the value when this reports true | **Returns**: whether the text is an integer that fits [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Json/Src/Value.rux#L71){rel=""nofollow""} ### `AsUint64` ```rux pub func AsUint64( self: &JsonNumber, result: *var uint64 ) -> bool ``` The value as an unsigned integer, or `false` if it does not fit one. | Name | Type | Description | | -------- | ------------- | ----------------------------------------- | | `result` | `*var uint64` | receives the value when this reports true | **Returns**: whether the text is a non-negative integer that fits [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Json/Src/Value.rux#L80){rel=""nofollow""} ### `AsFloat64` ```rux pub func AsFloat64( self: &JsonNumber, result: *var float64 ) -> bool ``` The value as a float, or `false` if the text is not a number at all. Succeeds for values a float cannot hold exactly, since that is what a float is for; a caller who needs exactness should ask for an integer or read the text. | Name | Type | Description | | -------- | -------------- | ----------------------------------------- | | `result` | `*var float64` | receives the value when this reports true | **Returns**: whether the text converted; the value is the nearest representable one [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Json/Src/Value.rux#L91){rel=""nofollow""} ### `IsIntegral` ```rux pub func IsIntegral(self: &JsonNumber) -> bool ``` Whether the text has no fraction and no exponent, so it denotes an integer. **Returns**: whether the text has no fraction and no exponent [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Json/Src/Value.rux#L99){rel=""nofollow""} ### `Release` ```rux pub func Release(self: &var JsonNumber) ``` Gives the text back. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Json/Src/Value.rux#L112){rel=""nofollow""} # JsonParseError Why parsing stopped, and where. ```rux pub variant JsonParseError { Lexical(JsonLexError, uint), Unexpected(uint), Truncated(uint), TrailingContent(uint), DuplicateName(uint), TooDeep(uint), TooManyEntries(uint), OutOfMemory(uint), BadSurrogate(uint), Source(uint) } ``` Failure-only: there is no case meaning nothing went wrong, because a parse that did not fail hands back a document instead. Every case carries the zero-based byte offset into the input where the parser stopped, which is the first thing anybody debugging a document asks for and used to live in a separate structure that a caller had to remember to read. ## Cases | Name | Description | | ----------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `Lexical(JsonLexError, uint)` | The lexer refused the input, for the reason carried. Nested rather than reported beside this, so a caller holding the failure cannot be holding half of it. | | `Unexpected(uint)` | A token that cannot appear where it did. | | `Truncated(uint)` | The document ended in the middle of a value. | | `TrailingContent(uint)` | Text after the end of the top-level value. The offset is where that text begins. | | `DuplicateName(uint)` | An object contained the same name twice, under the rejecting policy. The offset is the second occurrence. | | `TooDeep(uint)` | Containers nested deeper than the limit allowed. | | `TooManyEntries(uint)` | A container held more entries than the limit allowed. | | `OutOfMemory(uint)` | The allocator refused. | | `BadSurrogate(uint)` | A `\u` escape naming half of a surrogate pair with no valid partner. JSON's escapes are UTF-16, and a lone surrogate is not a character; the offset is the escape that has no partner. | | `Source(uint)` | The stream a [`JsonEventReader`](https://rux-lang.dev/docs/api/json/json-event-reader) reads from failed with something other than its end. Only a streaming reader reports this; the source's own `IoError` is kept on the reader, through [`JsonEventReader::SourceError`](https://rux-lang.dev/docs/api/json/json-event-reader#source-error). | ## Implements ParseFailure `JsonParseError` conforms to `ParseFailure`. ### `Offset` ```rux pub func Offset(self: &JsonParseError) -> uint ``` Where in the input parsing stopped. Borrows the failure and leaves it untouched. Cannot fail; runs in constant time and allocates nothing. **Returns**: the zero-based byte offset into the document [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Json/Src/Parser.rux#L67){rel=""nofollow""} ## Implements Display `JsonParseError` conforms to `Display`. ### `WriteDisplay` ```rux pub func WriteDisplay( self: &JsonParseError, writer: &var TextWriter, spec: FormatSpec ) -> ! FormatError ``` Writes the description of why parsing stopped, without the position. The offset is a number a caller renders where it makes sense for them — beside a line and column they computed, or not at all — so it is not written into the middle of a sentence here. `Debug` carries it. Reports whatever the writer reported, and `UnsupportedRequest` for any style or precision. | Name | Type | Description | | -------- | ----------------- | ------------------------------ | | `writer` | `&var TextWriter` | the destination | | `spec` | `FormatSpec` | what the placeholder asked for | **Returns**: success when the whole description was accepted [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Json/Src/Parser.rux#L110){rel=""nofollow""} ## Implements Debug `JsonParseError` conforms to `Debug`. ### `WriteDebug` ```rux pub func WriteDebug( self: &JsonParseError, writer: &var TextWriter, spec: FormatSpec ) -> ! FormatError ``` Names the case and its position: `JsonParseError::Unexpected(12)`. A lexical failure names both, so nothing about it has to be looked up elsewhere: `JsonParseError::Lexical(BadEscape, 12)`. Reports whatever the writer reported, and `UnsupportedRequest` for any style or precision. | Name | Type | Description | | -------- | ----------------- | ------------------------------ | | `writer` | `&var TextWriter` | the destination | | `spec` | `FormatSpec` | what the placeholder asked for | **Returns**: success when the whole name was accepted [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Json/Src/Parser.rux#L166){rel=""nofollow""} # JsonParser A parser over a document. ```rux pub struct JsonParser { // private fields } ``` ## Constructors ### `JsonParser` ```rux pub func JsonParser( allocator: Allocator, input: char8[..], limits: JsonLimits ) -> JsonParser ``` A parser over `input` under `limits`, rejecting duplicate names. | Name | Type | Description | | ----------- | ------------ | -------------------------------------- | | `allocator` | `Allocator` | where the storage comes from | | `input` | `char8[..]` | the text to read | | `limits` | `JsonLimits` | the bounds the parse refuses to exceed | **Returns**: a parser ready to read the input [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Json/Src/Parser.rux#L242){rel=""nofollow""} ## Methods ### `SetDuplicatePolicy` ```rux pub func SetDuplicatePolicy( self: &var JsonParser, policy: DuplicateKeyPolicy ) ``` Chooses what to do about duplicate object names. | Name | Type | Description | | -------- | -------------------- | ------------------------------------ | | `policy` | `DuplicateKeyPolicy` | what to do when a name appears twice | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Json/Src/Parser.rux#L259){rel=""nofollow""} ### `Failure` ```rux pub func Failure(self: &JsonParser) -> JsonParseError? ``` Whether parsing stopped, and why. `none` while nothing has gone wrong, which for a parser that has finished means the document was read. A caller using [`Parse`](https://rux-lang.dev/docs/api/json/json-parser#parse) never needs this: the failure comes back in the result. **Returns**: the failure, positioned, or `none` [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Json/Src/Parser.rux#L268){rel=""nofollow""} ### `Parse` ```rux pub func Parse(self: &var JsonParser) -> JsonValue ! JsonParseError ``` Parses the whole document and returns its top-level value, or why it could not. Anything after that value is `TrailingContent` — a document is one value, and two concatenated ones are not a document however well-formed each is. A failure gives back nothing at all. Whatever had been built when the parser stopped is released here, which is the only place that can be done once: an array that failed at its third element owns two, and handing those back beside an error would leave a caller holding a document that is not one. Fails with any case of [`JsonParseError`](https://rux-lang.dev/docs/api/json/json-parse-error), positioned at the byte where parsing stopped. **Returns**: the document, or the failure that stopped it [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Json/Src/Parser.rux#L551){rel=""nofollow""} # JsonValue A JSON value: one of the six kinds, owning whatever it holds. ```rux pub struct JsonValue { pub kind: JsonKind; // private fields } ``` Move-only, because it owns strings and nested values. The allocator it was built with is carried along, so a subtree can be released without the caller having to remember where it came from — which is what makes a document assembled from several sources safe to take apart. The tag is inspected with [`Kind`](https://rux-lang.dev/docs/api/json/json-value#kind) and the payload read with the matching accessor; asking for the wrong one reports failure rather than reinterpreting the bytes. ## Fields | Name | Type | Description | | ------ | ---------- | ------------------------------- | | `kind` | `JsonKind` | Which of the six kinds this is. | ## Associated functions ### `Null` ```rux pub func Null(allocator: Allocator) -> JsonValue ``` The literal `null`. | Name | Type | Description | | ----------- | ----------- | ---------------------------- | | `allocator` | `Allocator` | where the storage comes from | **Returns**: the null value [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Json/Src/Value.rux#L158){rel=""nofollow""} ### `Boolean` ```rux pub func Boolean( allocator: Allocator, value: bool ) -> JsonValue ``` A boolean value. | Name | Type | Description | | ----------- | ----------- | ---------------------------- | | `allocator` | `Allocator` | where the storage comes from | | `value` | `bool` | the value to act on | **Returns**: that boolean as a value [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Json/Src/Value.rux#L175){rel=""nofollow""} ### `Number` ```rux pub func Number( allocator: Allocator, text: char8[..] ) -> JsonValue ! TextError ``` A number, from the text it was written with. | Name | Type | Description | | ----------- | ----------- | ---------------------------- | | `allocator` | `Allocator` | where the storage comes from | | `text` | `char8[..]` | the text to act on | **Returns**: that text as a number value, or the null value when the allocator refused [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Json/Src/Value.rux#L187){rel=""nofollow""} ### `Text` ```rux pub func Text( allocator: Allocator, value: char8[..] ) -> JsonValue ! TextError ``` A string value. | Name | Type | Description | | ----------- | ----------- | ---------------------------- | | `allocator` | `Allocator` | where the storage comes from | | `value` | `char8[..]` | the value to act on | **Returns**: that text as a string value, or the null value when the allocator refused [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Json/Src/Value.rux#L199){rel=""nofollow""} ### `Array` ```rux pub func Array(allocator: Allocator) -> JsonValue ``` An empty array. | Name | Type | Description | | ----------- | ----------- | ---------------------------- | | `allocator` | `Allocator` | where the storage comes from | **Returns**: an empty array [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Json/Src/Value.rux#L210){rel=""nofollow""} ### `Object` ```rux pub func Object(allocator: Allocator) -> JsonValue ``` An empty object. | Name | Type | Description | | ----------- | ----------- | ---------------------------- | | `allocator` | `Allocator` | where the storage comes from | **Returns**: an empty object [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Json/Src/Value.rux#L220){rel=""nofollow""} ## Methods ### `Kind` ```rux pub func Kind(self: &JsonValue) -> JsonKind ``` Which kind this value is. **Returns**: which of the six JSON kinds this is [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Json/Src/Value.rux#L229){rel=""nofollow""} ### `IsNull` ```rux pub func IsNull(self: &JsonValue) -> bool ``` Whether this is `null`. **Returns**: whether this is the null value [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Json/Src/Value.rux#L236){rel=""nofollow""} ### `AsBoolean` ```rux pub func AsBoolean( self: &JsonValue, result: *var bool ) -> bool ``` The boolean payload, or `false` when this is not a boolean — which [`Kind`](https://rux-lang.dev/docs/api/json/json-value#kind) distinguishes from a genuine `false`. | Name | Type | Description | | -------- | ----------- | ----------------------------------------- | | `result` | `*var bool` | receives the value when this reports true | **Returns**: whether this is a boolean [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Json/Src/Value.rux#L245){rel=""nofollow""} ### `AsNumber` ```rux pub func AsNumber(self: &JsonValue) -> *JsonNumber ``` The number payload, borrowed. **Returns**: the number, or null when this is not one [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Json/Src/Value.rux#L254){rel=""nofollow""} ### `AsText` ```rux pub func AsText(self: &JsonValue) -> StringView ``` The string payload, or an empty view when this is not a string. **Returns**: the string, or an empty view when this is not one [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Json/Src/Value.rux#L261){rel=""nofollow""} ### `Length` ```rux pub func Length(self: &JsonValue) -> uint ``` How many elements an array holds, or members an object holds; zero for anything else. **Returns**: how many elements or members this holds; zero for anything else [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Json/Src/Value.rux#L269){rel=""nofollow""} ### `Push` ```rux pub func Push( self: &var JsonValue, value: JsonValue ) -> bool ``` Appends `value` to an array, taking ownership of it. Reports `false` when this is not an array or the allocator refused; `value` is consumed either way, so a caller does not have to decide who owns it on failure. | Name | Type | Description | | ------- | ----------- | ------------------- | | `value` | `JsonValue` | the value to act on | **Returns**: whether the element was appended [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Json/Src/Value.rux#L281){rel=""nofollow""} ### `Insert` ```rux pub func Insert( self: &var JsonValue, name: String, value: JsonValue ) -> bool ``` Appends a member to an object, taking ownership of both name and value. The order members are added in is the order they are kept and written, which is what makes a document round-trip recognisably. Nothing here rejects a duplicate name — that policy lives in the parser, where the caller can choose it. | Name | Type | Description | | ------- | ----------- | ------------------- | | `name` | `String` | the member's name | | `value` | `JsonValue` | the value to act on | **Returns**: whether the member was added [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Json/Src/Value.rux#L294){rel=""nofollow""} ### `At` ```rux pub func At(self: &JsonValue, index: uint) -> *JsonValue ``` The element at `index`, borrowed, or null when there is none. | Name | Type | Description | | ------- | ------ | ----------------------------- | | `index` | `uint` | which one, counting from zero | **Returns**: the element at `index`, or null when there is none [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Json/Src/Value.rux#L304){rel=""nofollow""} ### `Find` ```rux pub func Find( self: &JsonValue, name: StringView ) -> *JsonValue ``` The value of the member named `name`, borrowed, or null when there is none. With duplicate names present — which only a permissive parser policy allows — this finds the first, since that is the one a reader encounters. | Name | Type | Description | | ------ | ------------ | ----------------- | | `name` | `StringView` | the member's name | **Returns**: the first member with that name, or null when there is none [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Json/Src/Value.rux#L316){rel=""nofollow""} ### `MemberAt` ```rux pub func MemberAt( self: &JsonValue, index: uint ) -> *JsonMember ``` The member at `index`, borrowed, or null when there is none. | Name | Type | Description | | ------- | ------ | ----------------------------- | | `index` | `uint` | which one, counting from zero | **Returns**: the member at `index`, or null when there is none [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Json/Src/Value.rux#L332){rel=""nofollow""} ### `RemoveFirst` ```rux pub func RemoveFirst( self: &var JsonValue, name: StringView ) -> bool ``` Removes the first member named `name`, if there is one. Used by the duplicate-name policy that keeps the last occurrence: dropping the earlier one is what keeps the object a map rather than a list that happens to repeat itself. The members after it are popped and pushed back rather than shifted, because shifting would move owning values around inside the vector, and a move out of a container is the one thing the ownership rules will not allow silently. Duplicates are rare enough that the cost never matters. | Name | Type | Description | | ------ | ------------ | ----------------- | | `name` | `StringView` | the member's name | **Returns**: whether a member with that name was removed [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Json/Src/Value.rux#L347){rel=""nofollow""} ## Destructor ```rux func ~JsonValue(self: &var JsonValue) ``` Releases everything this value owns. Written out rather than left to the compiler, because a value owns its strings and its children own theirs: the recursion here is the shape of the document, and stating it makes the ownership of a nested tree something a reader can check. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Json/Src/Value.rux#L385){rel=""nofollow""} ## Related ### `JsonKind` ```rux pub enum JsonKind: int32 { Null = 0, Boolean = 1, Number = 2, Text = 3, Array = 4, Object = 5 } ``` Which kind of JSON value this is. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Json/Src/Value.rux#L20){rel=""nofollow""} **Cases** | Name | Value | Description | | --------- | ----- | ----------------------------------------------- | | `Null` | `0` | The literal `null`. | | `Boolean` | `1` | `true` or `false`. | | `Number` | `2` | A number, whose precision JSON does not define. | | `Text` | `3` | A string. | | `Array` | `4` | An ordered sequence of values. | | `Object` | `5` | A collection of name-value members. | ### `JsonMember` ```rux pub struct JsonMember { pub name: String; pub value: JsonValue; } ``` A name-value pair inside an object. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Json/Src/Value.rux#L119){rel=""nofollow""} **Fields** | Name | Type | Description | | ------- | ----------- | ------------------- | | `name` | `String` | The member's name. | | `value` | `JsonValue` | The member's value. | **Destructor** #### `~JsonMember` ```rux func ~JsonMember(self: &var JsonMember) ``` Releases the member's name and value. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Json/Src/Value.rux#L399){rel=""nofollow""} # Parse Parses `input` into a value, rejecting duplicate names. ```rux pub func Parse( allocator: Allocator, input: char8[..] ) -> JsonValue ! JsonParseError ``` The default limits apply. A failure gives back the reason and its position and no value at all, so a document that is not a document cannot be mistaken for one that is — which the old shape allowed, since it answered a refused parse with `null`, and `null` is a document. Fails with any case of [`JsonParseError`](https://rux-lang.dev/docs/api/json/json-parse-error), positioned at the byte where parsing stopped. ## Parameters | Name | Type | Description | | ----------- | ----------- | ---------------------------- | | `allocator` | `Allocator` | where the value is built | | `input` | `char8[..]` | the document, as UTF-8 bytes | **Returns**: the document, or the failure that stopped it ## Related ### `DuplicateKeyPolicy` ```rux pub enum DuplicateKeyPolicy: int32 { Reject = 0, KeepFirst = 1, KeepLast = 2, KeepAll = 3 } ``` What to do about an object containing the same name twice. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Json/Src/Parser.rux#L19){rel=""nofollow""} **Cases** | Name | Value | Description | | ----------- | ----- | ------------------------------------------------------------------------------------------------------- | | `Reject` | `0` | Refuse the document. The default, and the only policy that cannot be used to make two readers disagree. | | `KeepFirst` | `1` | Keep the first occurrence and discard the rest. | | `KeepLast` | `2` | Keep the last occurrence, which is what most JavaScript-derived parsers do. | | `KeepAll` | `3` | Keep every occurrence, in order. The document is preserved exactly, and lookup finds the first. | ### `ParseWith` ```rux pub func ParseWith( allocator: Allocator, input: char8[..], limits: JsonLimits, duplicates: DuplicateKeyPolicy ) -> JsonValue ! JsonParseError ``` Parses `input` under chosen limits and a chosen duplicate-name policy. The long form of `Parse`, for a caller who needs something other than the defaults. The policy is a parameter rather than a mutable setting on a shared parser, so two documents read under different policies in the same program cannot influence one another. Fails with any case of [`JsonParseError`](https://rux-lang.dev/docs/api/json/json-parse-error), positioned at the byte where parsing stopped. A limit that the document exceeds arrives as `TooDeep` or `TooManyEntries` from the parser, or nested inside `Lexical` when it was the lexer that measured it. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Json/Src/Parser.rux#L644){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------------ | -------------------- | ------------------------------------------------------- | | `allocator` | `Allocator` | where the value is built | | `input` | `char8[..]` | the document, as UTF-8 bytes | | `limits` | `JsonLimits` | what to accept | | `duplicates` | `DuplicateKeyPolicy` | what to do about an object naming the same member twice | **Returns**: the document, or the failure that stopped it # WriteValue Writes `value` to `writer` in the given style. ```rux pub func WriteValue( writer: &var TextWriter, value: &JsonValue, style: JsonStyle ) -> ! FormatError ``` The value is borrowed and nothing is allocated: the document writes itself into the destination as it is walked. A number is written as the text it was read with, which is what keeps an identifier past 2^53 coming back as itself. Reports whatever the destination reported, unchanged, so a buffer that is merely full stays distinguishable from a stream that has died — and stops at the first refusal rather than writing the rest of a document into a destination that has already said no. Reports `ValueOutOfRange` for a number JSON cannot spell, and for a document nested past [`MaximumWriteDepth`](https://rux-lang.dev/docs/api/json/write-value#maximum-write-depth). ## Parameters | Name | Type | Description | | -------- | ----------------- | -------------------------------------------- | | `writer` | `&var TextWriter` | the destination | | `value` | `&JsonValue` | the document to write, borrowed for the call | | `style` | `JsonStyle` | compact or pretty | **Returns**: success when the whole document was accepted ## Related ### `MaximumWriteDepth` ```rux pub const MaximumWriteDepth: uint = 512; ``` How deep a document may nest before the writer refuses. The writer descends recursively, so this bounds its own stack rather than the document's shape. It is far past the parser's default depth, which is what actually decides whether a document of this size can exist: a tree built in memory rather than parsed is the only way to reach this at all. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Json/Src/Writer.rux#L25){rel=""nofollow""} ### `JsonStyle` ```rux pub struct JsonStyle { // private fields } ``` How a document should be laid out. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Json/Src/Writer.rux#L29){rel=""nofollow""} **Associated functions** #### `Compact` ```rux pub func Compact() -> JsonStyle ``` The compact style: no whitespace anywhere. What a document on a wire should be. **Returns**: a style that writes no whitespace at all [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Json/Src/Writer.rux#L40){rel=""nofollow""} #### `Pretty` ```rux pub func Pretty() -> JsonStyle ``` The readable style: two spaces per level. **Returns**: a style that indents and puts each member on its own line [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Json/Src/Writer.rux#L47){rel=""nofollow""} ### `WriteEscaped` ```rux pub func WriteEscaped( writer: &var TextWriter, text: char8[..] ) -> ! FormatError ``` Writes the escaped form of `text`, including its surrounding quotes. Escapes exactly what the standard requires: the quote, the backslash, and every control character below space. Bytes above that pass through unchanged, so a UTF-8 document stays UTF-8 rather than being expanded into escapes — which is legal but makes output several times larger for no gain. Reports whatever the destination reported, stopping at the first refusal, so a destination that has already refused something is not written to again and a partly written string is not followed by its closing quote. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Json/Src/Writer.rux#L65){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | ----------------- | ----------------------------------- | | `writer` | `&var TextWriter` | the destination | | `text` | `char8[..]` | the UTF-8 bytes to escape and write | **Returns**: success when the whole quoted string was accepted # Toml TOML parsing, serialization and streaming. ## Installation Add `Toml` to the `[Dependencies]` table of your package's `Rux.toml`: ```toml [Dependencies] Toml = { Namespace = "Rux", Version = "0.1.0" } ``` Standard packages are declared by hand: the registry does not serve them, so `rux add Rux/Toml` cannot add them. ## Dependencies - [`Allocator`](https://rux-lang.dev/docs/api/allocator) 0.1.0 - [`Collections`](https://rux-lang.dev/docs/api/collections) 0.1.0 - [`Core`](https://rux-lang.dev/docs/api/core) 0.1.0 - [`Format`](https://rux-lang.dev/docs/api/format) 0.1.0 - [`Math`](https://rux-lang.dev/docs/api/math) 0.1.0 - [`Text`](https://rux-lang.dev/docs/api/text) 0.1.0 - [`Time`](https://rux-lang.dev/docs/api/time) 0.1.0 ## Guide ### What it provides - **Lexing** — every token TOML 1.1 defines, with source spans: bare and quoted keys, the four string forms, integers in four bases, floats, booleans, and the date and time types. - **Parsing** — dotted keys, tables, arrays of tables, and the duplicate-definition rules that make TOML's table syntax unambiguous. [`TomlParse`](https://rux-lang.dev/docs/api/toml/toml-parse) returns `TomlValue ! TomlParseFailure`: a document or a reason, never both. A refusal releases whatever had been read rather than handing it back, because a program configured from half a file runs with some settings applied and some defaulted, which is a state nobody wrote down. ```rux match TomlParse(allocator, bytes) { .Success(document) => Configure(document), .Failure(failure) => Report(failure) } ``` - **Failures that name a rule and a place** — [`TomlParseError`](https://rux-lang.dev/docs/api/toml/toml-parse-failure#toml-parse-error) keeps all four table-definition cases apart, because `DuplicateKey`, `RedefinedTable`, `ExtendedInlineTable` and `ExtendedDottedTable` are four different mistakes with four different fixes. `Lexical` carries the lexer's reason and `BadValue` carries the scalar reader's, so a caller holding a failure cannot be holding half of one. [`TomlParseFailure`](https://rux-lang.dev/docs/api/toml/toml-parse-failure) adds the position three ways — a byte `offset` for a program to slice with, and `line` and `column` for a person — all naming the same byte, and `Debug` renders the lot: `TomlParseError::BadValue(TomlScalarError::Malformed(4)) at 1:12`. The position is where parsing *stopped*, which for a duplicate key is the value rather than the key, since the pair has to be read before the repeat is known. :br[`TomlEventReader::Failure`](https://rux-lang.dev/docs/api/toml/toml-event-reader#failure) answers the same [`TomlParseFailure`](https://rux-lang.dev/docs/api/toml/toml-parse-failure), so the streaming reader and the tree parser report a refusal in one vocabulary rather than two. - **A semantic DOM** — ordered, move-only tables and arrays with explicit `<-` transfers and deterministic `~Type` cleanup, and dates and times as `Rux/Time` values rather than strings. - **Scalars that say where they went wrong** — [`TomlParseInteger`](https://rux-lang.dev/docs/api/toml/scalars#toml-parse-integer), [`TomlParseFloat`](https://rux-lang.dev/docs/api/toml/scalars#toml-parse-float) and [`TomlParseDateTime`](https://rux-lang.dev/docs/api/toml/scalars#toml-parse-date-time) return `T ! TomlScalarError`, and every failure carries the byte offset into the scalar's own text, reachable through `Text::ParseFailure`. The offsets are into the text as the caller wrote it, underscores included, so `0b1_0_2` points at the `2` where checking it happened four characters earlier. [`TomlParseDateTime`](https://rux-lang.dev/docs/api/toml/scalars#toml-parse-date-time) answers a [`TomlDateTime`](https://rux-lang.dev/docs/api/toml/scalars#toml-date-time) carrying which of the four shapes it is, rather than a shape beside three fields the shape may or may not fill. :br The parser adds the two positions together — the token's place in the document, and the failure's place inside the token — so `port = 0b102` is reported at line 1, column 12, and `TomlParseOutcome::Scalar` hands the caller the scalar reader's own reason. Neither half is any use alone: the token's place points at the value rather than at what is wrong with it, and the offset is into a few characters nobody can find without it. - **Writing** — deterministic output that borrows the document without copying and chooses a valid key and string form for whatever it is given. [`TomlWriteDocument`](https://rux-lang.dev/docs/api/toml/toml-write-document) returns `! FormatError`, the same contract every writer in the workspace uses, so a document goes into anything a `TextWriter` reaches with no translation at the seam. What the destination said travels unchanged: a buffer that is merely full reports `InsufficientCapacity` and a stream that has died reports `WriterFailure`, where `TomlWriteError` had one case for both. A header path longer than [`MaximumHeaderPath`](https://rux-lang.dev/docs/api/toml/toml-write-document#maximum-header-path) is `ValueOutOfRange` — the document is good and the form asked for cannot hold it. ### What it does not do **This is not an editing library, and semantic parsing is not lossless.** A document is read into values, and everything that was not a value is gone by the time you have one. Reading a file and writing it back produces an equivalent document, not the same file. Specifically, what a read-and-write loses: - **Comments.** They are skipped by the lexer and never reach the parser, so nothing downstream could keep them even in principle. - **Blank lines, indentation and spacing.** The writer produces its own layout: one blank line before each header, one space either side of an equals sign, and nothing else. - **How a value was spelled.** `0xFF`, `0o377` and `255` are the same integer and all come back as `255`; `1e3` comes back as `1000.0`. A float is written at the fewest digits that read back as the same value, not at the digits it was written with. - **Which string form was used.** Literal and multi-line strings come back as basic strings with escapes, because the value is the same and one form is one form fewer to reason about. - **Whether a table was written inline.** `a = { b = 1 }` comes back as `[a]` with `b = 1` under it. - **Where keys sat.** Entry order within a table is preserved; a dotted key that reached into a table is written as a header instead. What is preserved is the tree: every key, every value, and the order entries were seen in. That is enough to read configuration, to generate it, and to check one document against another — and not enough to edit a file someone else wrote without churning it. For that, a format-preserving parser is a different piece of software, and this is not it. ## Index ### Types | Name | Summary | | ------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------ | | [`TomlEvent`](https://rux-lang.dev/docs/api/toml/toml-event-reader#toml-event) | What just happened in the document. | | [`TomlEventReader`](https://rux-lang.dev/docs/api/toml/toml-event-reader) | Reads a document as events, in order, without building a tree. | | [`TomlTokenKind`](https://rux-lang.dev/docs/api/toml/toml-lexer#toml-token-kind) | What kind of token this is. | | [`TomlTextForm`](https://rux-lang.dev/docs/api/toml/toml-lexer#toml-text-form) | Which of the four string forms a text token was written in. | | [`TomlLexError`](https://rux-lang.dev/docs/api/toml/toml-lexer#toml-lex-error) | Why lexing stopped. | | [`TomlToken`](https://rux-lang.dev/docs/api/toml/toml-lexer#toml-token) | One token, and where it came from. | | [`TomlLexer`](https://rux-lang.dev/docs/api/toml/toml-lexer) | A TOML lexer over a byte slice. | | [`TomlParseError`](https://rux-lang.dev/docs/api/toml/toml-parse-failure#toml-parse-error) | Why parsing stopped. | | [`TomlParseFailure`](https://rux-lang.dev/docs/api/toml/toml-parse-failure) | Why a document was refused, and where in it. | | [`TomlLimits`](https://rux-lang.dev/docs/api/toml/toml-parser#toml-limits) | What a parse will accept. | | [`TomlParser`](https://rux-lang.dev/docs/api/toml/toml-parser) | A parser over a document. | | [`TomlScalarError`](https://rux-lang.dev/docs/api/toml/toml-scalar-error) | Why a scalar could not be read, and where in it. | | [`TomlDateTimeShape`](https://rux-lang.dev/docs/api/toml/scalars#toml-date-time-shape) | Which of the four date-time shapes a token turned out to be. | | [`TomlDateTime`](https://rux-lang.dev/docs/api/toml/scalars#toml-date-time) | A date-time as TOML writes it: which of the four shapes it is, and the parts that shape carries. | | [`TomlKind`](https://rux-lang.dev/docs/api/toml/toml-value#toml-kind) | Which kind of TOML value this is. | | [`TomlEntry`](https://rux-lang.dev/docs/api/toml/toml-value#toml-entry) | One entry of a table: its key and its value. | | [`TomlValue`](https://rux-lang.dev/docs/api/toml/toml-value) | A TOML value: one of the ten kinds, owning whatever it holds. | ### Functions | Name | Summary | | -------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------- | | [`TomlDecodeText`](https://rux-lang.dev/docs/api/toml/toml-lexer#toml-decode-text) | Decodes a text token's span into an owned string, honouring the escapes its form allows. | | [`TomlParse`](https://rux-lang.dev/docs/api/toml/toml-parse) | Reads `input` into a table, or says why it could not and where. | | [`TomlParseInteger`](https://rux-lang.dev/docs/api/toml/scalars#toml-parse-integer) | Reads an integer, in any of the four bases TOML writes. | | [`TomlParseFloat`](https://rux-lang.dev/docs/api/toml/scalars#toml-parse-float) | Reads a float, including the infinities and NaN that TOML can spell and JSON cannot. | | [`TomlParseDateTime`](https://rux-lang.dev/docs/api/toml/scalars#toml-parse-date-time) | Reads any of TOML's four date-time forms, reporting which one it was. | | [`TomlWriteDocument`](https://rux-lang.dev/docs/api/toml/toml-write-document) | Writes `table` as a TOML document. | ### Constants | Name | Summary | | ------------------------------------------------------------------------------------------------- | ------------------------------------------------ | | [`MaximumHeaderPath`](https://rux-lang.dev/docs/api/toml/toml-write-document#maximum-header-path) | How long a table's header path may be, in bytes. | # TomlEventReader Reads a document as events, in order, without building a tree. ```rux pub struct TomlEventReader { // private fields } ``` ## Constructors ### `TomlEventReader` ```rux pub func TomlEventReader(input: char8[..]) -> TomlEventReader ``` A reader over `input`. | Name | Type | Description | | ------- | ----------- | ---------------- | | `input` | `char8[..]` | the text to read | **Returns**: a reader positioned before the first event [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Toml/Src/Events.rux#L93){rel=""nofollow""} ## Methods ### `Failure` ```rux pub func Failure(self: &TomlEventReader) -> TomlParseFailure? ``` Why reading stopped, positioned, or `none` while nothing has gone wrong. This is what a caller asks after [`Next`](https://rux-lang.dev/docs/api/toml/toml-event-reader#next) reports `Error`. A lexical refusal carries the lexer's own reason inside it rather than in a second call, so a caller holding the failure is holding all of it — and it is the same [`TomlParseFailure`](https://rux-lang.dev/docs/api/toml/toml-parse-failure) the tree parser answers, so the two ways of reading a document report a refusal in one vocabulary rather than two. **Returns**: the failure, positioned at the token the reader stopped on, or `none` [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Toml/Src/Events.rux#L118){rel=""nofollow""} ### `Span` ```rux pub func Span(self: &TomlEventReader) -> char8[..] ``` The bytes the current event's token spans, as written: a string is still escaped and a number is still text. **Returns**: the raw text the current event covers, borrowed from the input [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Toml/Src/Events.rux#L135){rel=""nofollow""} ### `Form` ```rux pub func Form(self: &TomlEventReader) -> TomlTextForm ``` Which string form the current text event was written in, which decoding it needs. **Returns**: which quoting form the current text was written in [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Toml/Src/Events.rux#L142){rel=""nofollow""} ### `Line` ```rux pub func Line(self: &TomlEventReader) -> uint ``` Which line the current event is on, counting from one. **Returns**: the current event's line, counting from one [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Toml/Src/Events.rux#L149){rel=""nofollow""} ### `Column` ```rux pub func Column(self: &TomlEventReader) -> uint ``` Which column the current event is at, counting from one, in bytes. **Returns**: the current event's column, counting from one [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Toml/Src/Events.rux#L156){rel=""nofollow""} ### `IsTableArray` ```rux pub func IsTableArray(self: &TomlEventReader) -> bool ``` Whether the header being read was written `[[name]]` rather than `[name]`. **Returns**: whether the current header opens an array of tables rather than a table [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Toml/Src/Events.rux#L163){rel=""nofollow""} ### `Depth` ```rux pub func Depth(self: &TomlEventReader) -> uint ``` How deep inside arrays and inline tables the reader is. **Returns**: how many tables are currently open [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Toml/Src/Events.rux#L170){rel=""nofollow""} ### `Next` ```rux pub func Next(self: &var TomlEventReader) -> TomlEvent ``` The next event, or `End` when the document is finished. After an `Error` every later call returns `End`: everything past a refusal would be read from a position the document never meant. **Returns**: the next event, or the end-of-input event [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Toml/Src/Events.rux#L252){rel=""nofollow""} ## Related ### `TomlEvent` ```rux pub enum TomlEvent: int32 { End = 0, Error = 1, HeaderStart = 2, HeaderEnd = 3, KeyStart = 4, KeyPart = 5, Text = 6, Integer = 7, Float = 8, Boolean = 9, DateTime = 10, ArrayStart = 11, ArrayEnd = 12, InlineTableStart = 13, InlineTableEnd = 14 } ``` What just happened in the document. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Toml/Src/Events.rux#L15){rel=""nofollow""} **Cases** | Name | Value | Description | | ------------------ | ----- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `End` | `0` | The document is finished. | | `Error` | `1` | Something went wrong; the reason is on the reader. | | `HeaderStart` | `2` | A `[name]` or `[[name]]` header opened; [`IsTableArray`](https://rux-lang.dev/docs/api/toml/toml-event-reader#is-table-array) says which, and the key parts follow. | | `HeaderEnd` | `3` | The header's key path is complete. | | `KeyStart` | `4` | A key-value pair began; the key parts follow, and then the value. | | `KeyPart` | `5` | One part of a key path, whose span is the key as written. | | `Text` | `6` | A string value, still escaped as it was written. | | `Integer` | `7` | An integer, as written. | | `Float` | `8` | A float, as written. | | `Boolean` | `9` | `true` or `false`. | | `DateTime` | `10` | A date-time in any of the four forms, as written. | | `ArrayStart` | `11` | An array opened. | | `ArrayEnd` | `12` | An array closed. | | `InlineTableStart` | `13` | An inline table opened. | | `InlineTableEnd` | `14` | An inline table closed. | # TomlLexer A TOML lexer over a byte slice. ```rux pub struct TomlLexer { pub line: uint; // private fields } ``` ## Fields | Name | Type | Description | | ------ | ------ | ---------------------- | | `line` | `uint` | Which line that is on. | ## Constructors ### `TomlLexer` ```rux pub func TomlLexer(input: char8[..]) -> TomlLexer ``` A lexer over `input`. | Name | Type | Description | | ------- | ----------- | ---------------- | | `input` | `char8[..]` | the text to read | **Returns**: a lexer positioned at the start of the input [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Toml/Src/Lexer.rux#L128){rel=""nofollow""} ## Methods ### `Next` ```rux pub func Next(self: &var TomlLexer) -> TomlToken ``` The next token, or `End` at the end of the input. **Returns**: the next token, or the end-of-input token [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Toml/Src/Lexer.rux#L422){rel=""nofollow""} ### `TextOf` ```rux pub func TextOf( self: &TomlLexer, token: &TomlToken ) -> char8[..] ``` The bytes a token spans, which for a text token excludes the quotes and is still escaped. | Name | Type | Description | | ------- | ------------ | ----------------- | | `token` | `&TomlToken` | the token to read | **Returns**: the token's text, borrowed from the input [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Toml/Src/Lexer.rux#L494){rel=""nofollow""} ## Related ### `TomlTokenKind` ```rux pub enum TomlTokenKind: int32 { End = 0, BareKey = 1, Text = 2, Integer = 3, Float = 4, Boolean = 5, DateTime = 6, Equals = 7, Dot = 8, Comma = 9, LeftBracket = 10, RightBracket = 11, LeftBrace = 12, RightBrace = 13, Newline = 14, Error = 15 } ``` What kind of token this is. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Toml/Src/Lexer.rux#L15){rel=""nofollow""} **Cases** | Name | Value | Description | | -------------- | ----- | ---------------------------------------------------------------------------------------------- | | `End` | `0` | The input is exhausted. | | `BareKey` | `1` | A bare key: letters, digits, underscores and hyphens. | | `Text` | `2` | A quoted key or a string value; the span excludes the quotes and the text may need unescaping. | | `Integer` | `3` | An integer, in any of the four bases. | | `Float` | `4` | A float, including the infinities and NaN that TOML — unlike JSON — can spell. | | `Boolean` | `5` | `true` or `false`. | | `DateTime` | `6` | An offset date-time, a local date-time, a local date, or a local time. | | `Equals` | `7` | `=` | | `Dot` | `8` | `.` | | `Comma` | `9` | `,` | | `LeftBracket` | `10` | `[` | | `RightBracket` | `11` | `]` | | `LeftBrace` | `12` | `{` | | `RightBrace` | `13` | `}` | | `Newline` | `14` | One or more newlines, which TOML treats as significant. | | `Error` | `15` | Something that is not TOML. | ### `TomlTextForm` ```rux pub enum TomlTextForm: int32 { NotText = 0, Basic = 1, MultiLineBasic = 2, Literal = 3, MultiLineLiteral = 4, Bare = 5 } ``` Which of the four string forms a text token was written in. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Toml/Src/Lexer.rux#L52){rel=""nofollow""} **Cases** | Name | Value | Description | | ------------------ | ----- | ------------------------------------------------------------------------------------------------------------ | | `NotText` | `0` | Not a text token. | | `Basic` | `1` | A basic string: escapes honoured, no raw newlines. | | `MultiLineBasic` | `2` | A multi-line basic string: escapes honoured, newlines allowed, a leading newline trimmed. | | `Literal` | `3` | A literal string: no escapes at all, which is what makes it right for Windows paths and regular expressions. | | `MultiLineLiteral` | `4` | A multi-line literal string: no escapes, newlines allowed. | | `Bare` | `5` | A bare key, which has no quotes and no escapes. | ### `TomlLexError` ```rux pub enum TomlLexError: int32 { None = 0, UnexpectedByte = 1, UnterminatedText = 2, BadEscape = 3, BadUnicodeEscape = 4, MalformedNumber = 5, NewlineInText = 6, UnescapedControl = 7, MalformedDateTime = 8 } ``` Why lexing stopped. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Toml/Src/Lexer.rux#L70){rel=""nofollow""} **Cases** | Name | Value | Description | | ------------------- | ----- | ---------------------------------------------------------------------------------- | | `None` | `0` | Nothing went wrong. | | `UnexpectedByte` | `1` | A byte that begins no token. | | `UnterminatedText` | `2` | A string the input ended before closing. | | `BadEscape` | `3` | An escape sequence TOML does not define. | | `BadUnicodeEscape` | `4` | A unicode escape that is not the right number of digits, or names no scalar value. | | `MalformedNumber` | `5` | A number whose shape TOML grammar does not allow. | | `NewlineInText` | `6` | A raw newline inside a single-line string. | | `UnescapedControl` | `7` | A control character appearing unescaped where TOML forbids it. | | `MalformedDateTime` | `8` | A date or time that is not the shape RFC 3339 defines. | ### `TomlToken` ```rux pub struct TomlToken { pub kind: TomlTokenKind; pub form: TomlTextForm; pub start: uint; pub end: uint; pub line: uint; pub column: uint; pub error: TomlLexError; } ``` One token, and where it came from. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Toml/Src/Lexer.rux#L93){rel=""nofollow""} **Fields** | Name | Type | Description | | -------- | --------------- | ------------------------------------------------------- | | `kind` | `TomlTokenKind` | What kind of token this is. | | `form` | `TomlTextForm` | Which string form, for a text token. | | `start` | `uint` | Where its text starts, as a byte offset. | | `end` | `uint` | Where its text ends. | | `line` | `uint` | Which line it starts on, counting from one. | | `column` | `uint` | Which column it starts at, counting from one, in bytes. | | `error` | `TomlLexError` | Why lexing stopped, when the kind is `Error`. | ### `TomlDecodeText` ```rux pub func TomlDecodeText( allocator: Allocator, span: char8[..], form: TomlTextForm, bad: *var bool ) -> String ! TextError ``` Decodes a text token's span into an owned string, honouring the escapes its form allows. A literal string is copied unchanged — that is what makes it the right form for a Windows path — while a basic string has its escapes resolved, including the line-ending backslash that lets a multi-line string be wrapped in the source without the wrapping appearing in the value. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Toml/Src/Lexer.rux#L509){rel=""nofollow""} **Parameters** | Name | Type | Description | | ----------- | -------------- | --------------------------------------------------------------- | | `allocator` | `Allocator` | where the storage comes from | | `span` | `char8[..]` | the raw text the token covers | | `form` | `TomlTextForm` | which quoting form the text was written in | | `bad` | `*var bool` | receives the offset of the first byte that could not be decoded | **Returns**: the decoded text, or why it could not be stored # TomlParseFailure Why a document was refused, and where in it. ```rux pub struct TomlParseFailure { pub reason: TomlParseError; pub offset: uint; pub line: uint; pub column: uint; } ``` Three positions for one place, because the three are wanted by different readers: `offset` is what a program slices the input with, and `line` and `column` are what a person is shown. They always name the same byte. ## Fields | Name | Type | Description | | -------- | ---------------- | -------------------------------------------------------------- | | `reason` | `TomlParseError` | Why parsing stopped. | | `offset` | `uint` | The zero-based byte offset into the document where it stopped. | | `line` | `uint` | Which line, counting from one. | | `column` | `uint` | Which column, counting from one, in bytes. | ## Implements ParseFailure `TomlParseFailure` conforms to `ParseFailure`. ### `Offset` ```rux pub func Offset(self: &TomlParseFailure) -> uint ``` Where in the document parsing stopped. Borrows the failure and leaves it untouched. Cannot fail; runs in constant time and allocates nothing. **Returns**: the zero-based byte offset into the document [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Toml/Src/Parser.rux#L81){rel=""nofollow""} ## Implements Display `TomlParseFailure` conforms to `Display`. ### `WriteDisplay` ```rux pub func WriteDisplay( self: &TomlParseFailure, writer: &var TextWriter, spec: FormatSpec ) -> ! FormatError ``` Writes the description of why parsing stopped, without the position. The line and column are numbers a caller places where it makes sense for them, so they are not written into the middle of a sentence here. `Debug` carries them. Reports whatever the writer reported, and `UnsupportedRequest` for any style or precision. | Name | Type | Description | | -------- | ----------------- | ------------------------------ | | `writer` | `&var TextWriter` | the destination | | `spec` | `FormatSpec` | what the placeholder asked for | **Returns**: success when the whole description was accepted [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Toml/Src/Parser.rux#L110){rel=""nofollow""} ## Implements Debug `TomlParseFailure` conforms to `Debug`. ### `WriteDebug` ```rux pub func WriteDebug( self: &TomlParseFailure, writer: &var TextWriter, spec: FormatSpec ) -> ! FormatError ``` Names the case and where it happened: `TomlParseError::DuplicateKey at 2:1`. A case that carries something names that too, so nothing has to be looked up elsewhere: `TomlParseError::BadValue(TomlScalarError::Malformed(4)) at 1:8`. Reports whatever the writer reported, and `UnsupportedRequest` for any style or precision. | Name | Type | Description | | -------- | ----------------- | ------------------------------ | | `writer` | `&var TextWriter` | the destination | | `spec` | `FormatSpec` | what the placeholder asked for | **Returns**: success when the whole rendering was accepted [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Toml/Src/Parser.rux#L191){rel=""nofollow""} ## Related ### `TomlParseError` ```rux pub variant TomlParseError { Lexical(TomlLexError), Unexpected, Truncated, DuplicateKey, RedefinedTable, ExtendedInlineTable, ExtendedDottedTable, NotATable, NotATableArray, BadValue(TomlScalarError), BadText, TooDeep, OutOfMemory } ``` Why parsing stopped. Failure-only: a parse that did not stop hands back a document instead. The distinctions between the four table-definition cases are the ones worth keeping — `DuplicateKey`, `RedefinedTable`, `ExtendedInlineTable` and `ExtendedDottedTable` are four different mistakes with four different fixes, and a reader told only that a key was defined twice would have to work out which rule they had met. The two cases that have something more to say carry it rather than reporting it beside themselves, so a caller holding the failure cannot be holding half of one. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Toml/Src/Parser.rux#L31){rel=""nofollow""} **Cases** | Name | Description | | --------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `Lexical(TomlLexError)` | The lexer refused the input, for the reason carried. | | `Unexpected` | A token that cannot appear where it did. | | `Truncated` | The document ended in the middle of something. | | `DuplicateKey` | A key given a value twice in the same table. | | `RedefinedTable` | A table defined by a header that had already been defined by one. | | `ExtendedInlineTable` | An attempt to add to a table that was written inline, which its closing brace ended. | | `ExtendedDottedTable` | An attempt to add to a table that a dotted key created, which its line ended. | | `NotATable` | A key path that runs through something that is not a table. | | `NotATableArray` | A `[[name]]` header naming an array that was not built from headers, or a table. | | `BadValue(TomlScalarError)` | A scalar whose text is not the number or date TOML's grammar defines, for the reason carried. The scalar failure's own offset is into the scalar's text; the failure around it is positioned in the document. | | `BadText` | A string whose escapes name no scalar value. | | `TooDeep` | Values nested deeper than the limit allowed. | | `OutOfMemory` | The allocator refused. | # TomlParser A parser over a document. ```rux pub struct TomlParser { // private fields } ``` ## Constructors ### `TomlParser` ```rux pub func TomlParser( allocator: Allocator, input: char8[..], limits: TomlLimits ) -> TomlParser ``` A parser over `input` under `limits`. | Name | Type | Description | | ----------- | ------------ | -------------------------------------- | | `allocator` | `Allocator` | where the storage comes from | | `input` | `char8[..]` | the text to read | | `limits` | `TomlLimits` | the bounds the parse refuses to exceed | **Returns**: a parser ready to read the input [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Toml/Src/Parser.rux#L310){rel=""nofollow""} ## Methods ### `Failure` ```rux pub func Failure(self: &TomlParser) -> TomlParseFailure? ``` Why parsing stopped, positioned, or `none` while nothing has gone wrong. A caller using [`Parse`](https://rux-lang.dev/docs/api/toml/toml-parser#parse) never needs this: the failure comes back in the result. **Returns**: the failure, or `none` [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Toml/Src/Parser.rux#L335){rel=""nofollow""} ### `Failed` ```rux pub func Failed(self: &TomlParser) -> bool ``` Whether parsing has failed. **Returns**: whether the parse stopped on a failure [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Toml/Src/Parser.rux#L343){rel=""nofollow""} ### `Parse` ```rux pub func Parse(self: &var TomlParser) -> TomlValue ! TomlParseFailure ``` Reads the whole document into a table. On failure the table holds whatever had been read before the refusal, and `Outcome` says what stopped it and where. A partial document is not a usable one; it is returned rather than discarded so a caller can show what was understood before the line that was not. What comes back is the values and nothing else. Comments never reach the parser, and neither does the blank line someone put between two sections or the fact that a number was written in hexadecimal. This reads configuration; it does not edit files. **Returns**: the document, or the failure and where it was found [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Toml/Src/Parser.rux#L830){rel=""nofollow""} ## Related ### `TomlLimits` ```rux pub struct TomlLimits { // private fields } ``` What a parse will accept. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Toml/Src/Parser.rux#L227){rel=""nofollow""} **Associated functions** #### `Default` ```rux pub func Default() -> TomlLimits ``` Limits that suit a configuration file: deep enough for anything written by hand, shallow enough that a document built to exhaust the stack does not. **Returns**: the limits an ordinary parse uses [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Toml/Src/Parser.rux#L237){rel=""nofollow""} #### `Unlimited` ```rux pub func Unlimited() -> TomlLimits ``` Limits that refuse nothing, for input already known to be trustworthy. **Returns**: limits that refuse nothing, for input that is already trusted [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Toml/Src/Parser.rux#L244){rel=""nofollow""} # TomlScalarError Why a scalar could not be read, and where in it. ```rux pub variant TomlScalarError { Malformed(uint), OutOfRange(uint), TooLong(uint) } ``` Failure-only: there is no case meaning nothing went wrong, because a scalar that read hands back its value instead. Every offset is a zero-based byte offset into the scalar's own text, as the caller wrote it — underscores included — and reachable through `Text::ParseFailure`. ## Cases | Name | Description | | ------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `Malformed(uint)` | The text does not have the shape TOML defines, at the byte carried. That is the first character that cannot be part of what was being read: a digit the base does not have, a point with nothing after it, an underscore that is not between two digits, or the end of the text when it stops early. | | `OutOfRange(uint)` | The value is outside what an `int64`, a `float64` or the calendar can hold. The offset is the start of the text, since it is the whole value that does not fit rather than any one character of it. | | `TooLong(uint)` | The text is longer than any TOML scalar needs. The offset is the first character past the bound. | ## Implements ParseFailure `TomlScalarError` conforms to `ParseFailure`. ### `Offset` ```rux pub func Offset(self: &TomlScalarError) -> uint ``` Where in the scalar's text the failure was found. Borrows the failure and leaves it untouched. Cannot fail; runs in constant time and allocates nothing. **Returns**: the zero-based byte offset into the scalar's own text [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Toml/Src/Scalar.rux#L43){rel=""nofollow""} ## Implements Display `TomlScalarError` conforms to `Display`. ### `WriteDisplay` ```rux pub func WriteDisplay( self: &TomlScalarError, writer: &var TextWriter, spec: FormatSpec ) -> ! FormatError ``` Writes the description of why the scalar could not be read, without the position. The offset is a number a caller places where it makes sense for them — beside a line and column, or not at all — so it is not written into the middle of a sentence here. `Debug` carries it. Reports whatever the writer reported, and `UnsupportedRequest` for any style or precision. | Name | Type | Description | | -------- | ----------------- | ------------------------------ | | `writer` | `&var TextWriter` | the destination | | `spec` | `FormatSpec` | what the placeholder asked for | **Returns**: success when the whole description was accepted [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Toml/Src/Scalar.rux#L61){rel=""nofollow""} ## Implements Debug `TomlScalarError` conforms to `Debug`. ### `WriteDebug` ```rux pub func WriteDebug( self: &TomlScalarError, writer: &var TextWriter, spec: FormatSpec ) -> ! FormatError ``` Names the case and its position: `TomlScalarError::Malformed(3)`. Reports whatever the writer reported, and `UnsupportedRequest` for any style or precision. | Name | Type | Description | | -------- | ----------------- | ------------------------------ | | `writer` | `&var TextWriter` | the destination | | `spec` | `FormatSpec` | what the placeholder asked for | **Returns**: success when the whole name was accepted [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Toml/Src/Scalar.rux#L80){rel=""nofollow""} # TomlValue A TOML value: one of the ten kinds, owning whatever it holds. ```rux pub struct TomlValue { pub kind: TomlKind; pub integer: int64; // private fields } ``` Move-only, because it owns strings and nested values. The allocator it was built with travels with it, so a subtree can be released without the caller having to remember where it came from. ## Fields | Name | Type | Description | | --------- | ---------- | ------------------------------------------------------------------------------------- | | `kind` | `TomlKind` | Which of the ten kinds this is. | | `integer` | `int64` | The payload of an [`Integer`](https://rux-lang.dev/docs/api/toml/toml-value#integer). | ## Associated functions ### `Table` ```rux pub func Table(allocator: Allocator) -> TomlValue ``` An empty table, which is also the shape every other kind is built from: TOML has no null to start from. | Name | Type | Description | | ----------- | ----------- | ---------------------------- | | `allocator` | `Allocator` | where the storage comes from | **Returns**: an empty table [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Toml/Src/Value.rux#L97){rel=""nofollow""} ### `Array` ```rux pub func Array(allocator: Allocator) -> TomlValue ``` An empty array. | Name | Type | Description | | ----------- | ----------- | ---------------------------- | | `allocator` | `Allocator` | where the storage comes from | **Returns**: an empty array [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Toml/Src/Value.rux#L121){rel=""nofollow""} ### `Text` ```rux pub func Text( allocator: Allocator, value: char8[..] ) -> TomlValue ! TextError ``` A string value, whose bytes are copied and validated as UTF-8. | Name | Type | Description | | ----------- | ----------- | ---------------------------- | | `allocator` | `Allocator` | where the storage comes from | | `value` | `char8[..]` | the value to act on | **Returns**: that text as a string value, or an empty table when the allocator refused [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Toml/Src/Value.rux#L132){rel=""nofollow""} ### `FromString` ```rux pub func FromString( allocator: Allocator, value: String ) -> TomlValue ``` A string value copying an already-built string. | Name | Type | Description | | ----------- | ----------- | ---------------------------- | | `allocator` | `Allocator` | where the storage comes from | | `value` | `String` | the value to act on | **Returns**: that owned string as a string value [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Toml/Src/Value.rux#L144){rel=""nofollow""} ### `Integer` ```rux pub func Integer( allocator: Allocator, value: int64 ) -> TomlValue ``` An integer value. | Name | Type | Description | | ----------- | ----------- | ---------------------------- | | `allocator` | `Allocator` | where the storage comes from | | `value` | `int64` | the value to act on | **Returns**: that integer as a value [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Toml/Src/Value.rux#L157){rel=""nofollow""} ### `Float` ```rux pub func Float( allocator: Allocator, value: float64 ) -> TomlValue ``` A float value, which TOML — unlike JSON — allows to be an infinity or a NaN. | Name | Type | Description | | ----------- | ----------- | ---------------------------- | | `allocator` | `Allocator` | where the storage comes from | | `value` | `float64` | the value to act on | **Returns**: that float as a value [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Toml/Src/Value.rux#L169){rel=""nofollow""} ### `Boolean` ```rux pub func Boolean( allocator: Allocator, value: bool ) -> TomlValue ``` A boolean value. | Name | Type | Description | | ----------- | ----------- | ---------------------------- | | `allocator` | `Allocator` | where the storage comes from | | `value` | `bool` | the value to act on | **Returns**: that boolean as a value [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Toml/Src/Value.rux#L181){rel=""nofollow""} ### `OffsetDateTime` ```rux pub func OffsetDateTime( allocator: Allocator, date: Date, time: TimeOfDay, offset: UtcOffset ) -> TomlValue ``` A date and time with a known offset, which names a moment on the timeline. | Name | Type | Description | | ----------- | ----------- | ---------------------------- | | `allocator` | `Allocator` | where the storage comes from | | `date` | `Date` | the calendar date | | `time` | `TimeOfDay` | the time of day | | `offset` | `UtcOffset` | the offset from UTC | **Returns**: a value carrying the date, the time and the offset from UTC [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Toml/Src/Value.rux#L195){rel=""nofollow""} ### `LocalDateTime` ```rux pub func LocalDateTime( allocator: Allocator, date: Date, time: TimeOfDay ) -> TomlValue ``` A date and time with no offset, which names a wall clock reading rather than a moment. | Name | Type | Description | | ----------- | ----------- | ---------------------------- | | `allocator` | `Allocator` | where the storage comes from | | `date` | `Date` | the calendar date | | `time` | `TimeOfDay` | the time of day | **Returns**: a value carrying the date and the time, with no offset [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Toml/Src/Value.rux#L210){rel=""nofollow""} ### `LocalDate` ```rux pub func LocalDate( allocator: Allocator, date: Date ) -> TomlValue ``` A date with no time. | Name | Type | Description | | ----------- | ----------- | ---------------------------- | | `allocator` | `Allocator` | where the storage comes from | | `date` | `Date` | the calendar date | **Returns**: a value carrying the date alone [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Toml/Src/Value.rux#L223){rel=""nofollow""} ### `LocalTime` ```rux pub func LocalTime( allocator: Allocator, time: TimeOfDay ) -> TomlValue ``` A time with no date. | Name | Type | Description | | ----------- | ----------- | ---------------------------- | | `allocator` | `Allocator` | where the storage comes from | | `time` | `TimeOfDay` | the time of day | **Returns**: a value carrying the time alone [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Toml/Src/Value.rux#L235){rel=""nofollow""} ## Methods ### `Kind` ```rux pub func Kind(self: &TomlValue) -> TomlKind ``` Which kind this value is. **Returns**: which of the TOML kinds this is [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Toml/Src/Value.rux#L245){rel=""nofollow""} ### `AsBoolean` ```rux pub func AsBoolean( self: &TomlValue, result: *var bool ) -> bool ``` The boolean payload, or `false` when this is not a boolean — which [`Kind`](https://rux-lang.dev/docs/api/toml/toml-value#kind) distinguishes from a genuine `false`. | Name | Type | Description | | -------- | ----------- | ----------------------------------------- | | `result` | `*var bool` | receives the value when this reports true | **Returns**: whether this is a boolean [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Toml/Src/Value.rux#L254){rel=""nofollow""} ### `AsInteger` ```rux pub func AsInteger( self: &TomlValue, result: *var int64 ) -> bool ``` The integer payload, or `false` when this is not an integer. A float is not converted, even when its value happens to be whole: TOML distinguishes `1` from `1.0` and collapsing them here would throw away a distinction the document was making. | Name | Type | Description | | -------- | ------------ | ----------------------------------------- | | `result` | `*var int64` | receives the value when this reports true | **Returns**: whether this is an integer [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Toml/Src/Value.rux#L266){rel=""nofollow""} ### `AsFloat` ```rux pub func AsFloat( self: &TomlValue, result: *var float64 ) -> bool ``` The float payload, or `false` when this is not a float. | Name | Type | Description | | -------- | -------------- | ----------------------------------------- | | `result` | `*var float64` | receives the value when this reports true | **Returns**: whether this is a float [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Toml/Src/Value.rux#L276){rel=""nofollow""} ### `AsText` ```rux pub func AsText(self: &TomlValue) -> StringView ``` The string payload, or an empty view when this is not a string. **Returns**: the string, or an empty view when this is not one [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Toml/Src/Value.rux#L285){rel=""nofollow""} ### `AsDate` ```rux pub func AsDate(self: &TomlValue, result: *var Date) -> bool ``` The date part, or `false` when this kind has none. | Name | Type | Description | | -------- | ----------- | ----------------------------------------- | | `result` | `*var Date` | receives the value when this reports true | **Returns**: whether this carries a date [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Toml/Src/Value.rux#L294){rel=""nofollow""} ### `AsTime` ```rux pub func AsTime( self: &TomlValue, result: *var TimeOfDay ) -> bool ``` The time part, or `false` when this kind has none. | Name | Type | Description | | -------- | ---------------- | ----------------------------------------- | | `result` | `*var TimeOfDay` | receives the value when this reports true | **Returns**: whether this carries a time [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Toml/Src/Value.rux#L307){rel=""nofollow""} ### `AsOffset` ```rux pub func AsOffset( self: &TomlValue, result: *var UtcOffset ) -> bool ``` The offset, or `false` when this is not an offset date-time. A local date-time deliberately has none: it names a wall clock reading, and inventing an offset for it is how a meeting ends up an hour out. | Name | Type | Description | | -------- | ---------------- | ----------------------------------------- | | `result` | `*var UtcOffset` | receives the value when this reports true | **Returns**: whether this carries an offset from UTC [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Toml/Src/Value.rux#L322){rel=""nofollow""} ### `Length` ```rux pub func Length(self: &TomlValue) -> uint ``` How many elements an array holds, or entries a table holds; zero for anything else. **Returns**: how many elements or entries this holds; zero for anything else [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Toml/Src/Value.rux#L331){rel=""nofollow""} ### `Push` ```rux pub func Push( self: &var TomlValue, value: TomlValue ) -> bool ``` Appends `value` to an array, taking ownership of it. Reports `false` when this is not an array or the allocator refused; `value` is consumed either way, so a caller does not have to decide who owns it on failure. | Name | Type | Description | | ------- | ----------- | ------------------- | | `value` | `TomlValue` | the value to act on | **Returns**: whether the element was appended [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Toml/Src/Value.rux#L343){rel=""nofollow""} ### `Insert` ```rux pub func Insert( self: &var TomlValue, key: String, value: TomlValue ) -> bool ``` Appends an entry to a table, copying the key and taking ownership of the value. The order entries are added in is the order they are kept and written, which is what makes a document round-trip recognisably. Nothing here rejects a repeated key — that is the parser's business, where the three different ways of repeating one can be told apart. | Name | Type | Description | | ------- | ----------- | ------------------- | | `key` | `String` | the key to look up | | `value` | `TomlValue` | the value to act on | **Returns**: whether the entry was added [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Toml/Src/Value.rux#L356){rel=""nofollow""} ### `At` ```rux pub func At(self: &TomlValue, index: uint) -> *TomlValue ``` The element at `index`, borrowed, or null when there is none. | Name | Type | Description | | ------- | ------ | ----------------------------- | | `index` | `uint` | which one, counting from zero | **Returns**: the element at `index`, or null when there is none [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Toml/Src/Value.rux#L366){rel=""nofollow""} ### `AtMutable` ```rux pub func AtMutable( self: &var TomlValue, index: uint ) -> *var TomlValue ``` The element at `index`, borrowed for modification, or null when there is none. This is how an array of tables grows: the header that opens a new one appends, and the lines under it are written into the last element in place. | Name | Type | Description | | ------- | ------ | ----------------------------- | | `index` | `uint` | which one, counting from zero | **Returns**: the element at `index` for writing, or null when there is none [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Toml/Src/Value.rux#L378){rel=""nofollow""} ### `Find` ```rux pub func Find( self: &TomlValue, key: StringView ) -> *TomlValue ``` The value under `key`, borrowed, or null when the table has none. | Name | Type | Description | | ----- | ------------ | ------------------ | | `key` | `StringView` | the key to look up | **Returns**: the entry with that key, or null when there is none [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Toml/Src/Value.rux#L388){rel=""nofollow""} ### `FindMutable` ```rux pub func FindMutable( self: &var TomlValue, key: StringView ) -> *var TomlValue ``` The value under `key`, borrowed for modification, or null when the table has none. | Name | Type | Description | | ----- | ------------ | ------------------ | | `key` | `StringView` | the key to look up | **Returns**: the entry with that key for writing, or null when there is none [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Toml/Src/Value.rux#L404){rel=""nofollow""} ### `EntryAt` ```rux pub func EntryAt( self: &TomlValue, index: uint ) -> *TomlEntry ``` The entry at `index`, borrowed, or null when there is none. | Name | Type | Description | | ------- | ------ | ----------------------------- | | `index` | `uint` | which one, counting from zero | **Returns**: the entry at `index`, or null when there is none [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Toml/Src/Value.rux#L420){rel=""nofollow""} ## Destructor ```rux func ~TomlValue(self: &var TomlValue) ``` Releases everything this value owns. Written out rather than left to the compiler, because a value owns its string and its children own theirs: the recursion here is the shape of the document, and stating it makes the ownership of a nested tree something a reader can check. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Toml/Src/Value.rux#L431){rel=""nofollow""} ## Related ### `TomlKind` ```rux pub enum TomlKind: int32 { Text = 0, Integer = 1, Float = 2, Boolean = 3, OffsetDateTime = 4, LocalDateTime = 5, LocalDate = 6, LocalTime = 7, Array = 8, Table = 9 } ``` Which kind of TOML value this is. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Toml/Src/Value.rux#L18){rel=""nofollow""} **Cases** | Name | Value | Description | | ---------------- | ----- | ---------------------------------------------------------------------- | | `Text` | `0` | A string, whichever of the four forms it was written in. | | `Integer` | `1` | A 64-bit signed integer. | | `Float` | `2` | A 64-bit float, which unlike JSON may be an infinity or a NaN. | | `Boolean` | `3` | `true` or `false`. | | `OffsetDateTime` | `4` | A date and time with a known offset from UTC, which names a moment. | | `LocalDateTime` | `5` | A date and time with no offset, which names a reading of a wall clock. | | `LocalDate` | `6` | A date with no time. | | `LocalTime` | `7` | A time with no date. | | `Array` | `8` | An ordered sequence of values. | | `Table` | `9` | A table of entries, in the order they were seen. | ### `TomlEntry` ```rux pub struct TomlEntry { pub key: String; pub value: TomlValue; } ``` One entry of a table: its key and its value. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Toml/Src/Value.rux#L43){rel=""nofollow""} **Fields** | Name | Type | Description | | ------- | ----------- | ---------------------------------------- | | `key` | `String` | The key, already unquoted and unescaped. | | `value` | `TomlValue` | The value. | **Destructor** #### `~TomlEntry` ```rux func ~TomlEntry(self: &var TomlEntry) ``` Releases the key and the value. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Toml/Src/Value.rux#L447){rel=""nofollow""} # Scalars Reading TOML integers, floats and date-times from their source text. ## `TomlParseInteger` ```rux pub func TomlParseInteger(text: char8[..]) -> int64 ! TomlScalarError ``` Reads an integer, in any of the four bases TOML writes. A leading zero is refused for a decimal integer, because `010` is eight in one language and ten in another and TOML declines to pick: it is not an integer at all. A sign is refused on a based integer for the same reason — the grammar does not offer one, so accepting it would be inventing a dialect. `Malformed` at the first character that cannot be part of the integer, `TooLong` past the length bound, and `OutOfRange` at the start when the digits are a number `int64` cannot hold. Every offset is into `text` as written, underscores included. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Toml/Src/Scalar.rux#L164){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------ | ----------- | ---------------------- | | `text` | `char8[..]` | the scalar's own bytes | **Returns**: the integer, or why it could not be read and where ## `TomlParseFloat` ```rux pub func TomlParseFloat(text: char8[..]) -> float64 ! TomlScalarError ``` Reads a float, including the infinities and NaN that TOML can spell and JSON cannot. A point needs a digit on either side of it, which is what refuses `.7` and `7.` — both of which some readers accept and some do not, so a document containing one means different things in different places. `Malformed` at the first character that cannot be part of the float, `TooLong` past the length bound, and `OutOfRange` at the start when the digits are a number `float64` cannot hold. Every offset is into `text` as written, underscores included. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Toml/Src/Scalar.rux#L244){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------ | ----------- | ---------------------- | | `text` | `char8[..]` | the scalar's own bytes | **Returns**: the float, or why it could not be read and where ## `TomlDateTimeShape` ```rux pub enum TomlDateTimeShape: int32 { Offset = 1, Local = 2, DateOnly = 3, TimeOnly = 4 } ``` Which of the four date-time shapes a token turned out to be. There is no case for "not a date-time": text that is none of the four is a failure with a position, not a fifth shape a caller has to remember to check for before reading the fields beside it. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Toml/Src/Scalar.rux#L359){rel=""nofollow""} **Cases** | Name | Value | Description | | ---------- | ----- | ------------------------------------------------------------------- | | `Offset` | `1` | A date and a time with an offset, which names a moment. | | `Local` | `2` | A date and a time with no offset, which names a wall clock reading. | | `DateOnly` | `3` | A date alone. | | `TimeOnly` | `4` | A time alone. | ## `TomlDateTime` ```rux pub struct TomlDateTime { pub shape: TomlDateTimeShape; pub date: Date; pub time: TimeOfDay; pub offset: UtcOffset; } ``` A date-time as TOML writes it: which of the four shapes it is, and the parts that shape carries. The parts that the shape does not carry are present and meaningless — a `DateOnly` has a time of midnight because the fields have to hold something — so `shape` is what decides which of them to read. That is why the shape travels with the value rather than being returned beside it. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Toml/Src/Scalar.rux#L375){rel=""nofollow""} **Fields** | Name | Type | Description | | -------- | ------------------- | ------------------------------------------------------------------------- | | `shape` | `TomlDateTimeShape` | Which of the four forms the text was. | | `date` | `Date` | The date, for every shape but `TimeOnly`. | | `time` | `TimeOfDay` | The time, for every shape but `DateOnly`. | | `offset` | `UtcOffset` | The offset, for `Offset` alone. UTC otherwise, which means nothing there. | ## `TomlParseDateTime` ```rux pub func TomlParseDateTime(text: char8[..]) -> TomlDateTime ! TomlScalarError ``` Reads any of TOML's four date-time forms, reporting which one it was. The four are genuinely different things and the difference matters: an offset date-time names a moment, and a local date-time names a reading of a wall clock that different places reach at different moments. Collapsing them by assuming UTC is how a meeting ends up an hour out, so nothing here supplies an offset that the text did not. `Malformed` at the byte where the text stops being one of the four forms — the separator that is not one, the field the calendar rejects, or the end of the text when it stops early. The calendar's own refusals arrive here too: the thirty-first of February is four correct digit pairs and not a date. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Toml/Src/Scalar.rux#L397){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------ | ----------- | ---------------------- | | `text` | `char8[..]` | the scalar's own bytes | **Returns**: the date-time and which shape it is, or why it could not be read and where # TomlParse Reads `input` into a table, or says why it could not and where. ```rux pub func TomlParse( allocator: Allocator, input: char8[..] ) -> TomlValue ! TomlParseFailure ``` A refusal gives back no document at all. Whatever had been read when the parser stopped is released here, which is the only place it can be done once — and handing it back would be worse than useless, because a program configured from half a file runs with some settings applied and some defaulted. Fails with any case of [`TomlParseError`](https://rux-lang.dev/docs/api/toml/toml-parse-failure#toml-parse-error), positioned at the byte, line and column where parsing stopped. ## Parameters | Name | Type | Description | | ----------- | ----------- | ---------------------------- | | `allocator` | `Allocator` | where the document is built | | `input` | `char8[..]` | the document, as UTF-8 bytes | **Returns**: the document, or the failure that stopped it # TomlWriteDocument Writes `table` as a TOML document. ```rux pub func TomlWriteDocument( writer: &var TextWriter, table: &TomlValue ) -> ! FormatError ``` The same tree always produces the same bytes, and a document written, read and written again produces the same bytes the second time — which is what makes this safe to run repeatedly over a file this program owns. It is not safe in the sense of preserving one it does not: comments, blank lines, indentation and the spelling of a number are not in the tree, so they cannot come out of it. The output is these values laid out by this writer, which is an equivalent document and not the same file. The document is borrowed and nothing is allocated: it writes itself into the destination as it is walked. Reports whatever the destination reported, unchanged, so a buffer that is merely full stays distinguishable from a stream that has died — and stops at the first refusal rather than writing the rest of a document into a destination that has already said no. Reports `ValueOutOfRange` for a table whose header path is longer than [`MaximumHeaderPath`](https://rux-lang.dev/docs/api/toml/toml-write-document#maximum-header-path). ## Parameters | Name | Type | Description | | -------- | ----------------- | -------------------------------------------- | | `writer` | `&var TextWriter` | the destination | | `table` | `&TomlValue` | the document to write, borrowed for the call | **Returns**: success when the whole document was accepted ## Related ### `MaximumHeaderPath` ```rux pub const MaximumHeaderPath: uint = 1024; ``` How long a table's header path may be, in bytes. A header is written as text, so the path is assembled into a fixed buffer rather than a list of names, and this is that buffer. It is far past any path a person writes: reaching it takes a nesting of tables whose names add up to a kilobyte, which a document built in memory can do and one that was parsed effectively cannot. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Toml/Src/Writer.rux#L31){rel=""nofollow""} # Uuid UUID representation, parsing, formatting and generation. ## Installation Add `Uuid` to the `[Dependencies]` table of your package's `Rux.toml`: ```toml [Dependencies] Uuid = { Namespace = "Rux", Version = "0.1.0" } ``` Standard packages are declared by hand: the registry does not serve them, so `rux add Rux/Uuid` cannot add them. ## Dependencies - [`Core`](https://rux-lang.dev/docs/api/core) 0.1.0 - [`Entropy`](https://rux-lang.dev/docs/api/entropy) 0.1.0 - [`Text`](https://rux-lang.dev/docs/api/text) 0.1.0 - [`Time`](https://rux-lang.dev/docs/api/time) 0.1.0 ## Guide ### What it provides - **A 128-bit `Copy` value** — stored as the sixteen bytes RFC 9562 orders them in, with borrowed `&Uuid` inspection and the version and variant readable from it without copying or exposing an address. - **Text** — the canonical hyphenated form and the `urn:uuid:` form, written in lower case because RFC 9562 says output should be, and read in either case because input arrives as it arrives. [`Uuid`](https://rux-lang.dev/docs/api/uuid/uuid) implements `Display` and `Debug`, so `{}` writes the canonical form and `{:urn}` the URN one; upper case is not a style, because a canonical form that varies by case is not canonical, and [`FormatUpper`](https://rux-lang.dev/docs/api/uuid/text#format-upper) remains for a format that demands it. - **Writers that refuse rather than truncate** — [`Format`](https://rux-lang.dev/docs/api/uuid/text#format), [`FormatUpper`](https://rux-lang.dev/docs/api/uuid/text#format-upper) and [`FormatUrn`](https://rux-lang.dev/docs/api/uuid/text#format-urn) return `! FormatError` and report `InsufficientCapacity` for a destination shorter than the form needs, leaving it exactly as it was. A truncated UUID is not a shorter UUID; it is a different string, and one a strict parser refuses and a lenient one might not. - **Refusals that say where** — [`Parse`](https://rux-lang.dev/docs/api/uuid/text#parse) returns `Uuid ! UuidParseError`, and every failure carries the zero-based byte offset into the text it was given: the character that is not a hexadecimal digit, the hyphen that is missing or misplaced, the misspelling in a `urn:uuid:` prefix, or the end of a text that stops short. Inside a URN the offsets are into the whole string, so a caller underlining the character does not have to know which form it was handed. - **Version 4** — random, from `Rux/Entropy`, with the version and variant bits forced whatever the source bytes said. - **Version 7** — time-ordered, so byte order is time order and a database index built on one does not fragment; with a caller-owned [`MonotonicUuid()`](https://rux-lang.dev/docs/api/uuid/monotonic-uuid) generator for identifiers minted in the same millisecond. - **Windows GUIDs** — an explicit, self-inverse byte-order conversion, because the two layouts disagree about the first three fields and a silent reinterpretation produces a valid-looking UUID with the wrong timestamp. Formatting and comparison borrow UUID values directly. Generation returns `Uuid ! EntropyError`, failing rather than producing a predictable identifier when the system has no entropy, and entropy retains raw byte buffers that transfer no ownership. ## Index ### Types | Name | Summary | | ---------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------- | | [`UuidParseError`](https://rux-lang.dev/docs/api/uuid/text#uuid-parse-error) | Why text could not be read as a UUID. | | [`MonotonicUuid`](https://rux-lang.dev/docs/api/uuid/monotonic-uuid) | A generator of version 7 UUIDs that are strictly increasing, even within one millisecond. | | [`Uuid`](https://rux-lang.dev/docs/api/uuid/uuid) | A universally unique identifier: sixteen bytes in the standard's own order. | | [`UuidVariant`](https://rux-lang.dev/docs/api/uuid/uuid#uuid-variant) | What layout a UUID's bytes follow. | ### Functions | Name | Summary | | ---------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------- | | [`Random`](https://rux-lang.dev/docs/api/uuid/random) | A version 4 UUID drawn from the operating system's entropy. | | [`RandomFromBytes`](https://rux-lang.dev/docs/api/uuid/random#random-from-bytes) | A version 4 UUID built from sixteen bytes the caller supplies. | | [`SwapGuidOrder`](https://rux-lang.dev/docs/api/uuid/uuid#swap-guid-order) | The same identifier with its first three fields byte-swapped, which is how Windows stores a GUID. | | [`Parse`](https://rux-lang.dev/docs/api/uuid/text#parse) | Reads a UUID from its canonical or URN text form. | | [`Format`](https://rux-lang.dev/docs/api/uuid/text#format) | Writes the canonical text form into `into`, in lower case. | | [`FormatUpper`](https://rux-lang.dev/docs/api/uuid/text#format-upper) | Writes the canonical text form into `into`, in upper case. | | [`FormatUrn`](https://rux-lang.dev/docs/api/uuid/text#format-urn) | Writes the URN form into `into`: the canonical form after `urn:uuid:`. | | [`TimeOrdered`](https://rux-lang.dev/docs/api/uuid/time-ordered) | A version 7 UUID: the current time in its leading bits, entropy in the rest. | | [`TimeOrderedAt`](https://rux-lang.dev/docs/api/uuid/time-ordered#time-ordered-at) | A version 7 UUID for a given millisecond, with entropy in the rest. | | [`MillisecondOf`](https://rux-lang.dev/docs/api/uuid/time-ordered#millisecond-of) | The millisecond a version 7 UUID carries. | ### Constants | Name | Summary | | ---------------------------------------------------------------------------- | ------------------------------------------------------------------------ | | [`UuidTextLength`](https://rux-lang.dev/docs/api/uuid/text#uuid-text-length) | How long the canonical text form is: thirty-two digits and four hyphens. | | [`UuidUrnLength`](https://rux-lang.dev/docs/api/uuid/text#uuid-urn-length) | How long the URN form is: the canonical form after `urn:uuid:`. | # MonotonicUuid A generator of version 7 UUIDs that are strictly increasing, even within one millisecond. ```rux pub struct MonotonicUuid { // private fields } ``` The format guarantees ordering only between milliseconds; two UUIDs made in the same one have random tails and may sort either way. This closes that by remembering the last value it produced: when the clock has not advanced, it increments the previous UUID instead of drawing a fresh one, so every value it returns is strictly greater than the last. A caller owns one of these rather than sharing a global, so two components generating identifiers do not serialize against each other or interleave into one sequence. ## Constructors ### `MonotonicUuid` ```rux pub func MonotonicUuid() -> MonotonicUuid ``` A generator that has produced nothing yet. **Returns**: the generator, which has produced nothing yet [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Uuid/Src/TimeOrdered.rux#L82){rel=""nofollow""} ## Methods ### `Next` ```rux pub func Next(self: &var MonotonicUuid) -> Uuid ! EntropyError ``` The next identifier, strictly greater than the one before it. **Returns**: the next value, which sorts after every value this generator has produced, or why entropy was unavailable [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Uuid/Src/TimeOrdered.rux#L90){rel=""nofollow""} # Uuid A universally unique identifier: sixteen bytes in the standard's own order. ```rux pub struct Uuid { pub bytes: byte[N]; } ``` ## Fields | Name | Type | Description | | ------- | --------- | ------------------------------------------ | | `bytes` | `byte[N]` | The sixteen bytes, most significant first. | ## Associated functions ### `Nil` ```rux pub func Nil() -> Uuid ``` The nil UUID: sixteen zero bytes. A defined value rather than an absence, and worth having as one — the alternative is every caller inventing a sentinel of their own. **Returns**: the all-zero value [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Uuid/Src/Uuid.rux#L39){rel=""nofollow""} ### `Max` ```rux pub func Max() -> Uuid ``` The max UUID: sixteen bytes of ones, which RFC 9562 defines as nil's counterpart. **Returns**: the all-ones value [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Uuid/Src/Uuid.rux#L47){rel=""nofollow""} ### `FromBytes` ```rux pub func FromBytes(bytes: byte[..]) -> Uuid ``` A UUID from sixteen bytes in the standard's order. Fewer than sixteen leaves the rest zero; more are ignored. No structure is imposed — the version and variant fields are whatever the bytes say, which is what lets this read a UUID from somewhere else. | Name | Type | Description | | ------- | ---------- | ------------------------------------------------------- | | `bytes` | `byte[..]` | sixteen bytes to take as the value, in big-endian order | **Returns**: those sixteen bytes as a value, with no field interpreted or corrected [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Uuid/Src/Uuid.rux#L63){rel=""nofollow""} ## Methods ### `Bytes` ```rux pub func Bytes(self: &Uuid) -> byte[..] ``` The sixteen bytes, in the standard's order. **Returns**: the sixteen bytes, in big-endian order [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Uuid/Src/Uuid.rux#L76){rel=""nofollow""} ### `IsNil` ```rux pub func IsNil(self: &Uuid) -> bool ``` Whether this is the nil UUID. **Returns**: whether every byte is zero [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Uuid/Src/Uuid.rux#L83){rel=""nofollow""} ### `IsMax` ```rux pub func IsMax(self: &Uuid) -> bool ``` Whether this is the max UUID. **Returns**: whether every byte is one [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Uuid/Src/Uuid.rux#L95){rel=""nofollow""} ### `Version` ```rux pub func Version(self: &Uuid) -> uint8 ``` The version, from the high nibble of the seventh byte. Meaningful only for the standard variant; a nil or max UUID reports a number that means nothing, which is why [`Variant`](https://rux-lang.dev/docs/api/uuid/uuid#variant) should be consulted first. **Returns**: the version nibble, 0 through 15; a value this package did not make may hold anything [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Uuid/Src/Uuid.rux#L109){rel=""nofollow""} ### `Variant` ```rux pub func Variant(self: &Uuid) -> UuidVariant ``` The variant, from the high bits of the ninth byte. The encoding is variable-length rather than two fixed bits: a leading zero means the oldest layout, `10` the standard one, `110` Microsoft's, and `111` the reserved future. **Returns**: the variant the layout declares [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Uuid/Src/Uuid.rux#L118){rel=""nofollow""} ### `Equals` ```rux pub func Equals(self: &Uuid, other: &Uuid) -> bool ``` Whether two UUIDs are the same. | Name | Type | Description | | ------- | ------- | ---------------------------- | | `other` | `&Uuid` | the value to compare against | **Returns**: whether all sixteen bytes match [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Uuid/Src/Uuid.rux#L130){rel=""nofollow""} ### `Compare` ```rux pub func Compare(self: &Uuid, other: &Uuid) -> Ordering ``` Orders two UUIDs by their bytes, most significant first. For a version 7 UUID this is chronological order, because its timestamp occupies the leading bytes in big-endian form. Reordering here — to match a platform's GUID layout, say — would destroy that, which is why the byte order is fixed rather than negotiable. | Name | Type | Description | | ------- | ------- | ---------------------------- | | `other` | `&Uuid` | the value to compare against | **Returns**: how the two order as sixteen big-endian bytes, which is lexicographic order for the text [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Uuid/Src/Uuid.rux#L146){rel=""nofollow""} ### `Hash` ```rux pub func Hash(self: &Uuid) -> uint64 ``` A hash of the sixteen bytes, for use as a table key. FNV-1a, which is not a cryptographic hash and does not need to be: a UUID is already the output of one, or of an entropy source, so what a table wants here is speed and an even spread over buckets. **Returns**: the value's hash [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Uuid/Src/Uuid.rux#L161){rel=""nofollow""} ## Implements Display `Uuid` conforms to `Display`. ### `WriteDisplay` ```rux pub func WriteDisplay( self: &Uuid, writer: &var TextWriter, spec: FormatSpec ) -> ! FormatError ``` Writes the canonical lower-case form, or the URN form under the `urn` style. The default is the hyphenated form RFC 9562 defines, in lower case, because that is the one representation the standard has and the one every other implementation writes. `hyphenated` names it explicitly and `urn` selects the `urn:uuid:` form. Upper case is not a style, since a canonical form that varies by case is not canonical; [`FormatUpper`](https://rux-lang.dev/docs/api/uuid/text#format-upper) remains for a format that demands it. Reports whatever the writer reported, and `UnsupportedRequest` for any other style or for a precision, which a value of exactly one length has nothing to apply. | Name | Type | Description | | -------- | ----------------- | ------------------------------ | | `writer` | `&var TextWriter` | the destination | | `spec` | `FormatSpec` | what the placeholder asked for | **Returns**: success when the whole form was accepted [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Uuid/Src/Uuid.rux#L266){rel=""nofollow""} ## Implements Debug `Uuid` conforms to `Debug`. ### `WriteDebug` ```rux pub func WriteDebug( self: &Uuid, writer: &var TextWriter, spec: FormatSpec ) -> ! FormatError ``` The same text as `Display`: an identifier has one reading, and quoting it would say nothing extra. The failures [`WriteDisplay`](https://rux-lang.dev/docs/api/uuid/uuid#write-display) reports. | Name | Type | Description | | -------- | ----------------- | ------------------------------ | | `writer` | `&var TextWriter` | the destination | | `spec` | `FormatSpec` | what the placeholder asked for | **Returns**: success when the whole form was accepted [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Uuid/Src/Uuid.rux#L283){rel=""nofollow""} ## Related ### `SwapGuidOrder` ```rux pub func SwapGuidOrder(value: &Uuid) -> Uuid ``` The same identifier with its first three fields byte-swapped, which is how Windows stores a GUID. The conversion is its own inverse, so one function serves both directions: a UUID becomes the GUID bytes a Windows API expects, and GUID bytes read from one become the UUID they represent. It must be called deliberately — applying it by accident, or failing to apply it when crossing the boundary, both produce a well-formed identifier that refers to something else entirely. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Uuid/Src/Random.rux#L52){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------- | ------- | ------------------- | | `value` | `&Uuid` | the value to act on | **Returns**: the same sixteen bytes with the first three fields byte-swapped ### `UuidVariant` ```rux pub enum UuidVariant: int32 { NetworkComputingSystem = 0, Standard = 1, Microsoft = 2, Future = 3 } ``` What layout a UUID's bytes follow. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Uuid/Src/Uuid.rux#L22){rel=""nofollow""} **Cases** | Name | Value | Description | | ------------------------ | ----- | ------------------------------------------------------------------------------------- | | `NetworkComputingSystem` | `0` | Apollo NCS, from before the standard — the layout the nil UUID also happens to match. | | `Standard` | `1` | The layout RFC 9562 defines, which is what essentially every UUID in use is. | | `Microsoft` | `2` | Microsoft's early variant: reserved, and rare. | | `Future` | `3` | Reserved for the future and never assigned. | # Random A version 4 UUID drawn from the operating system's entropy. ```rux pub func Random() -> Uuid ! EntropyError ``` Fails with why entropy was unavailable rather than producing a zero-filled UUID with the version bits set, which would be a valid-looking identifier that is entirely predictable. **Returns**: a version 4 value drawn from the system's generator, or why entropy was unavailable ## Related ### `RandomFromBytes` ```rux pub func RandomFromBytes(bytes: byte[..]) -> Uuid ``` A version 4 UUID built from sixteen bytes the caller supplies. For reproducing a UUID from a recorded seed, or for drawing from a generator other than the system's. The version and variant bits are set regardless of what the bytes say, so the result is always a well-formed version 4 UUID. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Uuid/Src/Random.rux#L37){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------- | ---------- | ------------------------------------------------------- | | `bytes` | `byte[..]` | sixteen bytes to take as the value, in big-endian order | **Returns**: those bytes with the version and variant fields set for version 4 # Text form Reading and writing a UUID in its canonical and URN text forms. ## `UuidTextLength` ```rux pub const UuidTextLength: uint = 36; ``` How long the canonical text form is: thirty-two digits and four hyphens. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Uuid/Src/Text.rux#L29){rel=""nofollow""} ## `UuidUrnLength` ```rux pub const UuidUrnLength: uint = 45; ``` How long the URN form is: the canonical form after `urn:uuid:`. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Uuid/Src/Text.rux#L33){rel=""nofollow""} ## `UuidParseError` ```rux pub variant UuidParseError { WrongLength(uint), Misplaced(uint), NotHexadecimal(uint), BadPrefix(uint) } ``` Why text could not be read as a UUID. Failure-only: every case is a failure, and each carries the zero-based UTF-8 byte offset into the text where it was found. Success is the other channel of `Uuid ! UuidParseError`, so there is no case here meaning nothing went wrong. Copy, carrying one offset and owning nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Uuid/Src/Text.rux#L41){rel=""nofollow""} **Cases** | Name | Description | | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `WrongLength(uint)` | The text is neither thirty-six characters nor forty-five with the URN prefix. The offset is the text's length when it is too short, which is where the missing character would have gone, and the first character the canonical form has no room for when it is too long. | | `Misplaced(uint)` | A hyphen is missing where the form puts one, or one appears where a digit belongs. The offset is that character. | | `NotHexadecimal(uint)` | A character that is not a hexadecimal digit. The offset is that character. | | `BadPrefix(uint)` | The text has the length of the URN form but its `urn:uuid:` prefix is misspelled. The offset is the first character that does not match. | **Implements ParseFailure** `UuidParseError` conforms to `ParseFailure`. ### `Offset` ```rux pub func Offset(self: &UuidParseError) -> uint ``` Where in the input the failure was found. Borrows the error and leaves it untouched. Cannot fail; runs in constant time and allocates nothing. **Returns**: the zero-based UTF-8 byte offset, which is the text's length at end of input [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Uuid/Src/Text.rux#L61){rel=""nofollow""} ## `Parse` ```rux pub func Parse(text: char8[..]) -> Uuid ! UuidParseError pub func Parse(text: StringView) -> Uuid ! UuidParseError ``` Reads a UUID from its canonical or URN text form. Both cases of the digits are accepted, because the standard says the two mean the same thing; nothing else is. The URN prefix is compared case-insensitively, which is RFC 8141's rule for a scheme name and a different rule from the digits — both are the standard's. Reports `WrongLength` for text that is neither form's length, `BadPrefix` for a misspelled `urn:uuid:`, `Misplaced` for a hyphen that is missing or one that stands where a digit belongs, and `NotHexadecimal` for any other character that is not a digit. Each carries the byte offset into `text` where it was found. A refused parse produces no value at all rather than a half-filled one. | Overload | Summary | | ----------------------------------------------------------- | -------------------------------------------------- | | `pub func Parse(text: char8[..]) -> Uuid ! UuidParseError` | Reads a UUID from its canonical or URN text form. | | `pub func Parse(text: StringView) -> Uuid ! UuidParseError` | Reads a UUID from the text a `StringView` borrows. | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Uuid/Src/Text.rux#L95){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------ | -------------------------- | ---------------- | | `text` | `char8[..]` / `StringView` | the text to read | **Returns**: the identifier, or why the text is not one ## `Format` ```rux pub func Format( value: &Uuid, into: var char8[..] ) -> ! FormatError ``` Writes the canonical text form into `into`, in lower case. Lower case because RFC 9562 says so, and because a canonical form that varies by case is not canonical — two systems comparing text would disagree about equal UUIDs. Reports `InsufficientCapacity` when `into` is shorter than [`UuidTextLength`](https://rux-lang.dev/docs/api/uuid/text#uuid-text-length), leaving it exactly as it was. A short destination is refused rather than filled with what fits, because a truncated UUID is a different string rather than a shorter one. Room past the thirty-six characters is not touched. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Uuid/Src/Text.rux#L199){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------- | --------------- | ------------------------------------------------------------------------------------------------------------ | | `value` | `&Uuid` | the identifier to write | | `into` | `var char8[..]` | the destination, at least [`UuidTextLength`](https://rux-lang.dev/docs/api/uuid/text#uuid-text-length) bytes | **Returns**: success when the whole form was written ## `FormatUpper` ```rux pub func FormatUpper( value: &Uuid, into: var char8[..] ) -> ! FormatError ``` Writes the canonical text form into `into`, in upper case. Offered because some formats demand it; [`Format`](https://rux-lang.dev/docs/api/uuid/text#format) is what a program should write when it has the choice. The failure [`Format`](https://rux-lang.dev/docs/api/uuid/text#format) reports, for the same reason and with the same guarantee. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Uuid/Src/Text.rux#L212){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------- | --------------- | ------------------------------------------------------------------------------------------------------------ | | `value` | `&Uuid` | the identifier to write | | `into` | `var char8[..]` | the destination, at least [`UuidTextLength`](https://rux-lang.dev/docs/api/uuid/text#uuid-text-length) bytes | **Returns**: success when the whole form was written ## `FormatUrn` ```rux pub func FormatUrn( value: &Uuid, into: var char8[..] ) -> ! FormatError ``` Writes the URN form into `into`: the canonical form after `urn:uuid:`. Reports `InsufficientCapacity` when `into` is shorter than [`UuidUrnLength`](https://rux-lang.dev/docs/api/uuid/text#uuid-urn-length), leaving it exactly as it was. The form is refused whole, so a destination never receives a prefix with nothing after it. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Uuid/Src/Text.rux#L233){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------- | --------------- | ---------------------------------------------------------------------------------------------------------- | | `value` | `&Uuid` | the identifier to write | | `into` | `var char8[..]` | the destination, at least [`UuidUrnLength`](https://rux-lang.dev/docs/api/uuid/text#uuid-urn-length) bytes | **Returns**: success when the whole form was written # TimeOrdered A version 7 UUID: the current time in its leading bits, entropy in the rest. ```rux pub func TimeOrdered() -> Uuid ! EntropyError ``` Fails with why entropy was unavailable rather than producing a timestamp-shaped value with no randomness — which would be guessable and would look fine. **Returns**: a version 7 value carrying the current time, or why entropy was unavailable ## Related ### `TimeOrderedAt` ```rux pub func TimeOrderedAt(milliseconds: uint64) -> Uuid ! EntropyError ``` A version 7 UUID for a given millisecond, with entropy in the rest. For reproducing an identifier from a recorded time, and for testing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Uuid/Src/TimeOrdered.rux#L32){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------------- | -------- | ------------------------------------------------------------ | | `milliseconds` | `uint64` | the timestamp to embed, in milliseconds since the Unix epoch | **Returns**: a version 7 value carrying `milliseconds`, or why entropy was unavailable ### `MillisecondOf` ```rux pub func MillisecondOf(value: &Uuid) -> uint64 ``` The millisecond a version 7 UUID carries. Meaningless for any other version, which is why the version should be checked first. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Uuid/Src/TimeOrdered.rux#L53){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------- | ------- | ------------------- | | `value` | `&Uuid` | the value to act on | **Returns**: the timestamp a version 7 value carries; meaningless for any other version # Crypto Cryptographic hashes, message authentication codes and key derivation. ## Installation Add `Crypto` to the `[Dependencies]` table of your package's `Rux.toml`: ```toml [Dependencies] Crypto = { Namespace = "Rux", Version = "0.1.0" } ``` Standard packages are declared by hand: the registry does not serve them, so `rux add Rux/Crypto` cannot add them. ## Dependencies - [`Core`](https://rux-lang.dev/docs/api/core) 0.1.0 ## Guide Cryptographic hashes, message authentication codes and key derivation. > **Not published, and not to be published until reviewed.** Every algorithm here matches its published test > vectors, but passing vectors is not the same as being safe to rely on: the things that go wrong in > cryptographic code — a comparison that leaks timing, a secret that outlives its use, a construction used > outside the assumptions it was proved under — pass vectors happily. This package is awaiting an independent > review by someone who did not write it. Until that review is recorded, treat it as unaudited. The > [review checklist](https://github.com/rux-lang/Rux/blob/main/Packages/Crypto/../../Docs/CryptoReview.md){rel=""nofollow""} says what is already established and what to look at first. ### What it provides - **SHA-2** — SHA-224, SHA-256, SHA-384, SHA-512, and the two SHA-512 truncations. - **SHA-3 and SHAKE** — the Keccak permutation, the four fixed-size hashes, and the two extendable-output functions. - **BLAKE3** — unkeyed, keyed, and derive-key modes, with extendable output. - **HMAC and HKDF** — generic over any digest, and the two-stage key derivation built on them. - **Legacy hashes** — [`LegacyMd5`](https://rux-lang.dev/docs/api/crypto/legacy-md5) and [`LegacySha1`](https://rux-lang.dev/docs/api/crypto/legacy-sha1), for reading what already exists. Both are broken; neither implements the digest interface, so nothing takes one by accident. - **Digests** — an incremental contract every algorithm implements, with one-shot forms beside it. - **Constant-time comparison** — [`Equal`](https://rux-lang.dev/docs/api/crypto/secrets#equal), which takes the same time whichever bytes differ, because the ordinary comparison leaks where the first difference is and that is enough to forge a tag one byte at a time. - **Zeroization** — [`Wipe`](https://rux-lang.dev/docs/api/crypto/secrets#wipe), written so it cannot be optimized away. ### Value and borrowing model Digest, XOF, and HMAC states are structural `Copy` values: copying a state takes an independent snapshot and owns no external resource. Safe mutation uses `&var` receivers, and read-only queries use `&`; calls borrow automatically. Construct default states with type calls such as [`Sha256()`](https://rux-lang.dev/docs/api/crypto/sha256), [`Sha512()`](https://rux-lang.dev/docs/api/crypto/sha512), and [`Blake3()`](https://rux-lang.dev/docs/api/crypto/blake3). Descriptive variants such as [`Sha256::New224()`](https://rux-lang.dev/docs/api/crypto/sha256#new-224), [`Shake::New128()`](https://rux-lang.dev/docs/api/crypto/shake#new-128), and [`Blake3::NewKeyed()`](https://rux-lang.dev/docs/api/crypto/blake3#new-keyed) retain their names. Raw pointers remain only inside compression helpers and the optimizer barrier, where contiguous word access or an opaque address is intentional. ## Index ### Interfaces | Name | Summary | | ------------------------------------------------------- | ---------------------- | | [`Digest`](https://rux-lang.dev/docs/api/crypto/digest) | An incremental digest. | ### Types | Name | Summary | | ------------------------------------------------------------------------- | ----------------------------------------------------------------------------------- | | [`Blake3Chunk`](https://rux-lang.dev/docs/api/crypto/blake3#blake3-chunk) | The state of one chunk being filled. | | [`Blake3`](https://rux-lang.dev/docs/api/crypto/blake3) | An incremental BLAKE3 hash. | | [`Hmac<D>`](https://rux-lang.dev/docs/api/crypto/hmac) | An incremental HMAC over any digest. | | [`Sha3`](https://rux-lang.dev/docs/api/crypto/sha3) | An incremental SHA-3 hash at any of its four sizes. | | [`LegacyMd5`](https://rux-lang.dev/docs/api/crypto/legacy-md5) | An incremental MD5. | | [`LegacySha1`](https://rux-lang.dev/docs/api/crypto/legacy-sha1) | An incremental SHA-1. | | [`Sha256`](https://rux-lang.dev/docs/api/crypto/sha256) | An incremental SHA-256 or SHA-224. | | [`Sha512`](https://rux-lang.dev/docs/api/crypto/sha512) | An incremental SHA-512, SHA-384, SHA-512/224 or SHA-512/256. | | [`Shake`](https://rux-lang.dev/docs/api/crypto/shake) | An extendable-output function: absorb a message, then read as many bytes as wanted. | ### Functions | Name | Summary | | ------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------ | | [`Blake3Compress`](https://rux-lang.dev/docs/api/crypto/blake3#blake3-compress) | The compression function: sixteen words of state over seven rounds, producing sixteen words of output. | | [`Blake3Of`](https://rux-lang.dev/docs/api/crypto/blake3#blake3-of) | The BLAKE3 hash of `bytes`, at whatever length `into` asks for. | | [`Blake3KeyedOf`](https://rux-lang.dev/docs/api/crypto/blake3#blake3-keyed-of) | The keyed BLAKE3 hash of `bytes` under `key`, in one call. | | [`Blake3DeriveKey`](https://rux-lang.dev/docs/api/crypto/blake3#blake3-derive-key) | A key derived from `material` under `context`, at whatever length `into` asks for. | | [`Equal`](https://rux-lang.dev/docs/api/crypto/secrets#equal) | Whether two byte sequences are equal, in time that does not depend on where they differ. | | [`Wipe`](https://rux-lang.dev/docs/api/crypto/secrets#wipe) | Overwrites `bytes` with zeros in a way the compiler may not remove. | | [`HkdfExtract<D>`](https://rux-lang.dev/docs/api/crypto/hkdf#hkdf-extract) | Extracts a pseudorandom key from `material`, salted with `salt`. | | [`HkdfExpand<D>`](https://rux-lang.dev/docs/api/crypto/hkdf#hkdf-expand) | Expands `key` into `into`, separated by `info`. | | [`Hkdf<D>`](https://rux-lang.dev/docs/api/crypto/hkdf) | Extract and expand in one call: the whole of HKDF. | | [`HmacOf<D>`](https://rux-lang.dev/docs/api/crypto/hmac#hmac-of) | The HMAC of `message` under `key`, in one call. | | [`KeccakPermute`](https://rux-lang.dev/docs/api/crypto/sha3#keccak-permute) | The Keccak-f [1600] permutation, applied in place to twenty-five lanes. | | [`Sha3Of224`](https://rux-lang.dev/docs/api/crypto/sha3#sha3-of-224) | The SHA3-224 digest of `bytes`, in one call. | | [`Sha3Of256`](https://rux-lang.dev/docs/api/crypto/sha3#sha3-of-256) | The SHA3-256 digest of `bytes`, in one call. | | [`Sha3Of384`](https://rux-lang.dev/docs/api/crypto/sha3#sha3-of-384) | The SHA3-384 digest of `bytes`, in one call. | | [`Sha3Of512`](https://rux-lang.dev/docs/api/crypto/sha3#sha3-of-512) | The SHA3-512 digest of `bytes`, in one call. | | [`LegacyMd5Of`](https://rux-lang.dev/docs/api/crypto/legacy-md5#legacy-md5-of) | The MD5 digest of `bytes`. | | [`LegacySha1Of`](https://rux-lang.dev/docs/api/crypto/legacy-sha1#legacy-sha1-of) | The SHA-1 digest of `bytes`. | | [`Sha256Of`](https://rux-lang.dev/docs/api/crypto/sha256#sha256-of) | The SHA-256 digest of `bytes`, in one call. | | [`Sha224Of`](https://rux-lang.dev/docs/api/crypto/sha256#sha224-of) | The SHA-224 digest of `bytes`, in one call. | | [`Sha512Of`](https://rux-lang.dev/docs/api/crypto/sha512#sha512-of) | The SHA-512 digest of `bytes`, in one call. | | [`Sha384Of`](https://rux-lang.dev/docs/api/crypto/sha512#sha384-of) | The SHA-384 digest of `bytes`, in one call. | | [`Sha512Trunc224Of`](https://rux-lang.dev/docs/api/crypto/sha512#sha512-trunc224-of) | The SHA-512/224 digest of `bytes`, in one call. | | [`Sha512Trunc256Of`](https://rux-lang.dev/docs/api/crypto/sha512#sha512-trunc256-of) | The SHA-512/256 digest of `bytes`, in one call. | | [`Shake128Of`](https://rux-lang.dev/docs/api/crypto/shake#shake128-of) | `into.length` bytes of SHAKE128 over `bytes`, in one call. | | [`Shake256Of`](https://rux-lang.dev/docs/api/crypto/shake#shake256-of) | `into.length` bytes of SHAKE256 over `bytes`, in one call. | ### Constants | Name | Summary | | ------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------- | | [`HkdfMaximumBlocks`](https://rux-lang.dev/docs/api/crypto/hkdf#hkdf-maximum-blocks) | The most blocks `Expand` can produce, since its counter is one byte. | | [`HmacMaximumBlock`](https://rux-lang.dev/docs/api/crypto/hmac#hmac-maximum-block) | The longest block any supported digest uses, which is what the padded key buffers are sized to. | # Digest An incremental digest. ```rux pub interface Digest { func Update(self: &var Self, bytes: char8[..]); func Finish(self: &var Self, into: var char8[..]); func DigestLength(self: &Self) -> uint; func BlockLength(self: &Self) -> uint; } ``` Take one by generic bound and mutable reference — `func Sum<D: Digest>(digest: &var D)` — so work applies to the caller's state without copying it. ## Requirements ### `Update` ```rux func Update(self: &var Self, bytes: char8[..]) ``` Adds `bytes` to what is being hashed. Any split of the same byte sequence across any number of calls gives the same digest. An empty slice is legal and changes nothing. | Name | Type | Description | | ------- | ----------- | ------------------- | | `bytes` | `char8[..]` | the bytes to absorb | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Crypto/Src/Digest.rux#L31){rel=""nofollow""} ### `Finish` ```rux func Finish(self: &var Self, into: var char8[..]) ``` Writes the digest into `into` and leaves the state unusable for further updates. `into` must be at least [`DigestLength`](https://rux-lang.dev/docs/api/crypto/digest#digest-length) bytes; anything beyond that is untouched. Finishing twice is a caller error rather than a supported operation — a digest is a one-shot summary of everything fed to it, and an implementation is free to consume its state producing one. | Name | Type | Description | | ------ | --------------- | ------------------- | | `into` | `var char8[..]` | receives the output | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Crypto/Src/Digest.rux#L39){rel=""nofollow""} ### `DigestLength` ```rux func DigestLength(self: &Self) -> uint ``` How many bytes [`Finish`](https://rux-lang.dev/docs/api/crypto/digest#finish) writes. **Returns**: how many bytes a digest occupies [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Crypto/Src/Digest.rux#L44){rel=""nofollow""} ### `BlockLength` ```rux func BlockLength(self: &Self) -> uint ``` How many bytes the algorithm processes at a time. Needed by the constructions built on digests — HMAC pads its key to exactly this — and by callers choosing a buffer size that avoids splitting work. **Returns**: how many bytes the compression function consumes at a time [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Crypto/Src/Digest.rux#L51){rel=""nofollow""} ## Implementations | Type | Summary | | ------------------------------------------------------- | ------------------------------------------------------------ | | [`Blake3`](https://rux-lang.dev/docs/api/crypto/blake3) | An incremental BLAKE3 hash. | | [`Sha3`](https://rux-lang.dev/docs/api/crypto/sha3) | An incremental SHA-3 hash at any of its four sizes. | | [`Sha256`](https://rux-lang.dev/docs/api/crypto/sha256) | An incremental SHA-256 or SHA-224. | | [`Sha512`](https://rux-lang.dev/docs/api/crypto/sha512) | An incremental SHA-512, SHA-384, SHA-512/224 or SHA-512/256. | # Blake3 An incremental BLAKE3 hash. ```rux pub struct Blake3 { // private fields } ``` Structural `Copy`; copying takes an independent snapshot of the hash tree state. ## Constructors ### `Blake3` ```rux pub func Blake3() -> Blake3 ``` An unkeyed BLAKE3 hash. **Returns**: a hasher with nothing absorbed [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Crypto/Src/Blake3.rux#L282){rel=""nofollow""} ## Associated functions ### `NewKeyed` ```rux pub func NewKeyed(key: char8[..]) -> Blake3 ``` A keyed BLAKE3 hash: a message authentication code. `key` must be exactly thirty-two bytes; a shorter one is padded with zeros, which is a caller error rather than a supported shortening — a key with less entropy than the algorithm expects is weaker than it looks, and padding it hides that rather than fixing it. Unlike SHA-2, this needs no nested construction: BLAKE3 resists length extension, so starting the tree from the key is a sound MAC on its own. | Name | Type | Description | | ----- | ----------- | ----------- | | `key` | `char8[..]` | the key | **Returns**: a hasher keyed with those thirty-two bytes [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Crypto/Src/Blake3.rux#L46){rel=""nofollow""} ### `NewDeriveKey` ```rux pub func NewDeriveKey(context: char8[..]) -> Blake3 ``` A BLAKE3 state deriving output under `context`. The context string names what the derived key is *for*, and it is hashed separately from the key material so that two derivations from the same material under different contexts are unrelated. It should be a hard-coded, globally unique string — an application name, a purpose, and a date — and it must not be a variable, since two callers who accidentally share one lose the separation entirely. | Name | Type | Description | | --------- | ----------- | ----------------------------------------------------------------- | | `context` | `char8[..]` | the application-specific context string, which must be a constant | **Returns**: a hasher in key-derivation mode for that context [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Crypto/Src/Blake3.rux#L60){rel=""nofollow""} ## Implements Digest `Blake3` conforms to [`Digest`](https://rux-lang.dev/docs/api/crypto/digest). ### `Update` ```rux pub func Update(self: &var Blake3, bytes: char8[..]) ``` Adds `bytes` to the message. | Name | Type | Description | | ------- | ----------- | ------------------- | | `bytes` | `char8[..]` | the bytes to absorb | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Crypto/Src/Blake3.rux#L334){rel=""nofollow""} ### `Finish` ```rux pub func Finish(self: &var Blake3, into: var char8[..]) ``` Writes the root output into `into`, which may be any length. BLAKE3's output is extendable like SHAKE's: the root compression repeats with an increasing counter to produce as many bytes as asked. Thirty-two is the usual choice and is what [`DigestLength`](https://rux-lang.dev/docs/api/crypto/blake3#digest-length) reports. | Name | Type | Description | | ------ | --------------- | ------------------- | | `into` | `var char8[..]` | receives the output | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Crypto/Src/Blake3.rux#L355){rel=""nofollow""} ### `DigestLength` ```rux pub func DigestLength(self: &Blake3) -> uint ``` Thirty-two bytes, the conventional length; [`Finish`](https://rux-lang.dev/docs/api/crypto/blake3#finish) writes any length asked of it. **Returns**: how many bytes a digest occupies [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Crypto/Src/Blake3.rux#L439){rel=""nofollow""} ### `BlockLength` ```rux pub func BlockLength(self: &Blake3) -> uint ``` Sixty-four bytes. **Returns**: how many bytes the compression function consumes at a time [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Crypto/Src/Blake3.rux#L446){rel=""nofollow""} ## Related ### `Blake3Compress` ```rux pub func Blake3Compress( chaining: *uint32, message: *uint32, counter: uint64, blockLength: uint32, flags: uint32, into: *var uint32 ) ``` The compression function: sixteen words of state over seven rounds, producing sixteen words of output. The first eight output words are the chaining value; all sixteen are used when the output is being extended. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Crypto/Src/Blake3.rux#L76){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------------- | ------------- | ------------------------------------- | | `chaining` | `*uint32` | the chaining value going in | | `message` | `*uint32` | the message to authenticate | | `counter` | `uint64` | the chunk counter | | `blockLength` | `uint32` | how many bytes of the block are used | | `flags` | `uint32` | the domain flags for this compression | | `into` | `*var uint32` | receives the output | ### `Blake3Chunk` ```rux pub struct Blake3Chunk { // private fields } ``` The state of one chunk being filled. Structural `Copy`; used as an independent snapshot within the enclosing hasher. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Crypto/Src/Blake3.rux#L131){rel=""nofollow""} **Methods** #### `Update` ```rux pub func Update( self: &var Blake3Chunk, bytes: char8[..] ) -> uint ``` Adds bytes to the chunk, compressing whole blocks as they complete. A block is only compressed once the *next* byte arrives, never when it merely becomes full: the last block of a chunk carries the end flag, and which block is last is not known until the chunk stops growing. Compressing eagerly is the classic way to get the flags wrong. | Name | Type | Description | | ------- | ----------- | ------------------- | | `bytes` | `char8[..]` | the bytes to absorb | **Returns**: how many bytes were absorbed [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Crypto/Src/Blake3.rux#L197){rel=""nofollow""} #### `Output` ```rux pub func Output( self: &Blake3Chunk, extraFlags: uint32, into: *var uint32 ) ``` The chunk's chaining value, with the end flag applied to its final block. `extraFlags` carries the root flag when this chunk is the whole message. | Name | Type | Description | | ------------ | ------------- | --------------------------------------- | | `extraFlags` | `uint32` | the domain flags to add for this output | | `into` | `*var uint32` | receives the output | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Crypto/Src/Blake3.rux#L226){rel=""nofollow""} ### `Blake3Of` ```rux pub func Blake3Of(bytes: char8[..], into: var char8[..]) ``` The BLAKE3 hash of `bytes`, at whatever length `into` asks for. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Crypto/Src/Blake3.rux#L455){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------- | --------------- | ------------------- | | `bytes` | `char8[..]` | the bytes to absorb | | `into` | `var char8[..]` | receives the output | ### `Blake3KeyedOf` ```rux pub func Blake3KeyedOf( key: char8[..], bytes: char8[..], into: var char8[..] ) ``` The keyed BLAKE3 hash of `bytes` under `key`, in one call. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Crypto/Src/Blake3Modes.rux#L77){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------- | --------------- | ------------------- | | `key` | `char8[..]` | the key | | `bytes` | `char8[..]` | the bytes to absorb | | `into` | `var char8[..]` | receives the output | ### `Blake3DeriveKey` ```rux pub func Blake3DeriveKey( context: char8[..], material: char8[..], into: var char8[..] ) ``` A key derived from `material` under `context`, at whatever length `into` asks for. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Crypto/Src/Blake3Modes.rux#L88){rel=""nofollow""} **Parameters** | Name | Type | Description | | ---------- | --------------- | ----------------------------------------------------------------- | | `context` | `char8[..]` | the application-specific context string, which must be a constant | | `material` | `char8[..]` | the input keying material | | `into` | `var char8[..]` | receives the output | # Hmac\<D> An incremental HMAC over any digest. ```rux pub struct Hmac<D: Digest> { // private fields } ``` `prototype` supplies both the algorithm and its parameters; it is copied rather than consumed, so one prototype can start any number of authentications. Structural `Copy` whenever `D` is copyable; copying snapshots both digest states independently. ## Type parameters | Name | Description | | ----------- | --------------- | | `D: Digest` | the digest type | ## Constructors ### `Hmac` ```rux pub func Hmac(prototype: D, key: char8[..]) -> Hmac<D> ``` An HMAC keyed with `key`. A key longer than the digest's block is replaced by its own digest, which is what the specification says and is worth knowing: two keys differing only past the block length authenticate identically, because they are the same key after this step. A shorter key is padded with zeros. | Name | Type | Description | | ----------- | ----------- | ---------------------------------------------------- | | `prototype` | `D` | any value of the digest type, read only to select it | | `key` | `char8[..]` | the key | **Returns**: an authenticator keyed with those bytes [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Crypto/Src/Hmac.rux#L50){rel=""nofollow""} ## Methods ### `Update` ```rux pub func Update<D: Digest>( self: &var Hmac<D>, bytes: char8[..] ) ``` Adds `bytes` to the message being authenticated. | Type parameter | Description | | -------------- | --------------- | | `D: Digest` | the digest type | | Name | Type | Description | | ------- | ----------- | ------------------- | | `bytes` | `char8[..]` | the bytes to absorb | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Crypto/Src/Hmac.rux#L100){rel=""nofollow""} ### `Finish` ```rux pub func Finish<D: Digest>( self: &var Hmac<D>, into: var char8[..] ) ``` Writes the authentication tag into `into`. | Type parameter | Description | | -------------- | --------------- | | `D: Digest` | the digest type | | Name | Type | Description | | ------ | --------------- | ------------------- | | `into` | `var char8[..]` | receives the output | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Crypto/Src/Hmac.rux#L108){rel=""nofollow""} ### `TagLength` ```rux pub func TagLength<D: Digest>(self: &Hmac<D>) -> uint ``` How many bytes [`Finish`](https://rux-lang.dev/docs/api/crypto/hmac#finish) writes: the underlying digest's length. | Type parameter | Description | | -------------- | --------------- | | `D: Digest` | the digest type | **Returns**: how many bytes a tag occupies, which is the digest's length [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Crypto/Src/Hmac.rux#L119){rel=""nofollow""} ## Related ### `HmacMaximumBlock` ```rux pub const HmacMaximumBlock: uint = 168; ``` The longest block any supported digest uses, which is what the padded key buffers are sized to. SHAKE128's rate is the largest at a hundred and sixty eight bytes; SHA-512's block is a hundred and twenty eight and SHA-256's sixty four. The buffers below are written as that literal because an array length must be a compile-time integer and a constant does not satisfy that yet. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Crypto/Src/Hmac.rux#L24){rel=""nofollow""} ### `HmacOf<D>` ```rux pub func HmacOf<D: Digest>( prototype: D, key: char8[..], message: char8[..], into: var char8[..] ) ``` The HMAC of `message` under `key`, in one call. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Crypto/Src/Hmac.rux#L131){rel=""nofollow""} **Type parameters** | Name | Description | | ----------- | --------------- | | `D: Digest` | the digest type | **Parameters** | Name | Type | Description | | ----------- | --------------- | ---------------------------------------------------- | | `prototype` | `D` | any value of the digest type, read only to select it | | `key` | `char8[..]` | the key | | `message` | `char8[..]` | the message to authenticate | | `into` | `var char8[..]` | receives the output | # LegacyMd5 An incremental MD5. ```rux pub struct LegacyMd5 { // private fields } ``` **Broken; see the note at the top of this file.** Structural `Copy`; copying takes an independent snapshot of the digest state. ## Constructors ### `LegacyMd5` ```rux pub func LegacyMd5() -> LegacyMd5 ``` An MD5 state. **Returns**: an MD5 hasher, which is broken and is here only to read what already exists [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Crypto/Src/Legacy.rux#L68){rel=""nofollow""} ## Methods ### `Update` ```rux pub func Update(self: &var LegacyMd5, bytes: char8[..]) ``` Adds `bytes` to the message. | Name | Type | Description | | ------- | ----------- | ------------------- | | `bytes` | `char8[..]` | the bytes to absorb | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Crypto/Src/Legacy.rux#L141){rel=""nofollow""} ### `Finish` ```rux pub func Finish(self: &var LegacyMd5, into: var char8[..]) ``` Writes the sixteen-byte digest into `into`. The length is appended little-endian, unlike the SHA family's big-endian count. | Name | Type | Description | | ------ | --------------- | ------------------- | | `into` | `var char8[..]` | receives the output | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Crypto/Src/Legacy.rux#L159){rel=""nofollow""} ## Related ### `LegacyMd5Of` ```rux pub func LegacyMd5Of(bytes: char8[..], into: var char8[..]) ``` The MD5 digest of `bytes`. **Broken; see the note at the top of this file.** [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Crypto/Src/Legacy.rux#L196){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------- | --------------- | ------------------- | | `bytes` | `char8[..]` | the bytes to absorb | | `into` | `var char8[..]` | receives the output | # LegacySha1 An incremental SHA-1. ```rux pub struct LegacySha1 { // private fields } ``` **Broken for collision resistance; see the note at the top of this file.** Structural `Copy`; copying takes an independent snapshot of the digest state. ## Constructors ### `LegacySha1` ```rux pub func LegacySha1() -> LegacySha1 ``` A SHA-1 state. **Returns**: a SHA-1 hasher, which is broken and is here only to read what already exists [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Crypto/Src/Legacy.rux#L220){rel=""nofollow""} ## Methods ### `Update` ```rux pub func Update(self: &var LegacySha1, bytes: char8[..]) ``` Adds `bytes` to the message. | Name | Type | Description | | ------- | ----------- | ------------------- | | `bytes` | `char8[..]` | the bytes to absorb | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Crypto/Src/Legacy.rux#L297){rel=""nofollow""} ### `Finish` ```rux pub func Finish(self: &var LegacySha1, into: var char8[..]) ``` Writes the twenty-byte digest into `into`. | Name | Type | Description | | ------ | --------------- | ------------------- | | `into` | `var char8[..]` | receives the output | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Crypto/Src/Legacy.rux#L314){rel=""nofollow""} ## Related ### `LegacySha1Of` ```rux pub func LegacySha1Of(bytes: char8[..], into: var char8[..]) ``` The SHA-1 digest of `bytes`. **Broken for collision resistance; see the note at the top of this file.** [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Crypto/Src/Legacy.rux#L352){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------- | --------------- | ------------------- | | `bytes` | `char8[..]` | the bytes to absorb | | `into` | `var char8[..]` | receives the output | # Sha256 An incremental SHA-256 or SHA-224. ```rux pub struct Sha256 { // private fields } ``` Structural `Copy`; copying takes an independent snapshot of the digest state. ## Constructors ### `Sha256` ```rux pub func Sha256() -> Sha256 ``` A SHA-256 state. **Returns**: a hasher producing a 256-bit digest [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Crypto/Src/Sha256.rux#L62){rel=""nofollow""} ## Associated functions ### `New224` ```rux pub func New224() -> Sha256 ``` A SHA-224 state: the same compression function from a different start, keeping seven words of the result. **Returns**: a hasher producing a 224-bit digest [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Crypto/Src/Sha256.rux#L75){rel=""nofollow""} ## Implements Digest `Sha256` conforms to [`Digest`](https://rux-lang.dev/docs/api/crypto/digest). ### `Update` ```rux pub func Update(self: &var Sha256, bytes: char8[..]) ``` Adds `bytes` to the message. Any split of the same bytes gives the same digest: whatever does not complete a block is buffered, and the buffer is only compressed once it is full. | Name | Type | Description | | ------- | ----------- | ------------------- | | `bytes` | `char8[..]` | the bytes to absorb | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Crypto/Src/Sha256.rux#L149){rel=""nofollow""} ### `Finish` ```rux pub func Finish(self: &var Sha256, into: var char8[..]) ``` Writes the digest into `into`. The padding is a one bit, then zeros, then the message length in bits as a big-endian sixty-four bit count. When fewer than nine bytes remain in the final block there is no room for that count, so the block is finished with zeros and a whole further block carries it — the case that separates a correct implementation from one that passes the short vectors. | Name | Type | Description | | ------ | --------------- | ------------------- | | `into` | `var char8[..]` | receives the output | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Crypto/Src/Sha256.rux#L182){rel=""nofollow""} ### `DigestLength` ```rux pub func DigestLength(self: &Sha256) -> uint ``` Thirty-two bytes for SHA-256, twenty-eight for SHA-224. **Returns**: how many bytes a digest occupies [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Crypto/Src/Sha256.rux#L220){rel=""nofollow""} ### `BlockLength` ```rux pub func BlockLength(self: &Sha256) -> uint ``` Sixty-four bytes, for both. **Returns**: how many bytes the compression function consumes at a time [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Crypto/Src/Sha256.rux#L227){rel=""nofollow""} ## Related ### `Sha256Of` ```rux pub func Sha256Of(bytes: char8[..], into: var char8[..]) ``` The SHA-256 digest of `bytes`, in one call. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Crypto/Src/Sha256.rux#L236){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------- | --------------- | ------------------- | | `bytes` | `char8[..]` | the bytes to absorb | | `into` | `var char8[..]` | receives the output | ### `Sha224Of` ```rux pub func Sha224Of(bytes: char8[..], into: var char8[..]) ``` The SHA-224 digest of `bytes`, in one call. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Crypto/Src/Sha256.rux#L246){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------- | --------------- | ------------------- | | `bytes` | `char8[..]` | the bytes to absorb | | `into` | `var char8[..]` | receives the output | # Sha3 An incremental SHA-3 hash at any of its four sizes. ```rux pub struct Sha3 { // private fields } ``` Structural `Copy`; copying takes an independent snapshot of the sponge state. ## Associated functions ### `New224` ```rux pub func New224() -> Sha3 ``` A SHA3-224 state. **Returns**: a hasher producing a 224-bit digest [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Crypto/Src/Keccak.rux#L138){rel=""nofollow""} ### `New256` ```rux pub func New256() -> Sha3 ``` A SHA3-256 state. **Returns**: a hasher producing a 256-bit digest [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Crypto/Src/Keccak.rux#L145){rel=""nofollow""} ### `New384` ```rux pub func New384() -> Sha3 ``` A SHA3-384 state. **Returns**: a hasher producing a 384-bit digest [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Crypto/Src/Keccak.rux#L152){rel=""nofollow""} ### `New512` ```rux pub func New512() -> Sha3 ``` A SHA3-512 state. **Returns**: a hasher producing a 512-bit digest [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Crypto/Src/Keccak.rux#L159){rel=""nofollow""} ## Implements Digest `Sha3` conforms to [`Digest`](https://rux-lang.dev/docs/api/crypto/digest). ### `Update` ```rux pub func Update(self: &var Sha3, bytes: char8[..]) ``` Absorbs `bytes` into the state. | Name | Type | Description | | ------- | ----------- | ------------------- | | `bytes` | `char8[..]` | the bytes to absorb | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Crypto/Src/Keccak.rux#L176){rel=""nofollow""} ### `Finish` ```rux pub func Finish(self: &var Sha3, into: var char8[..]) ``` Pads, permutes once more, and squeezes the digest out. The padding is the domain byte, then zeros, then a final bit at the top of the rate — so a rate with only one byte free receives both in the same byte, which is the case that separates a correct padding from one that works at every other length. | Name | Type | Description | | ------ | --------------- | ------------------- | | `into` | `var char8[..]` | receives the output | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Crypto/Src/Keccak.rux#L195){rel=""nofollow""} ### `DigestLength` ```rux pub func DigestLength(self: &Sha3) -> uint ``` Twenty-eight, thirty-two, forty-eight or sixty-four bytes. **Returns**: how many bytes a digest occupies [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Crypto/Src/Keccak.rux#L221){rel=""nofollow""} ### `BlockLength` ```rux pub func BlockLength(self: &Sha3) -> uint ``` The rate, which differs per size — unlike the SHA-2 family, whose block is fixed. **Returns**: how many bytes the compression function consumes at a time [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Crypto/Src/Keccak.rux#L228){rel=""nofollow""} ## Related ### `KeccakPermute` ```rux pub func KeccakPermute(lanes: *var uint64) ``` The Keccak-f [1600] permutation, applied in place to twenty-five lanes. Twenty-four rounds of five steps: theta mixes each column into its neighbours, rho rotates each lane by its own offset, pi moves the lanes around, chi is the only non-linear step, and iota breaks the symmetry that would otherwise make every round identical. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Crypto/Src/Keccak.rux#L46){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------- | ------------- | ------------------------------------------------ | | `lanes` | `*var uint64` | the state's twenty-five lanes, permuted in place | ### `Sha3Of224` ```rux pub func Sha3Of224(bytes: char8[..], into: var char8[..]) ``` The SHA3-224 digest of `bytes`, in one call. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Crypto/Src/Keccak.rux#L237){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------- | --------------- | ------------------- | | `bytes` | `char8[..]` | the bytes to absorb | | `into` | `var char8[..]` | receives the output | ### `Sha3Of256` ```rux pub func Sha3Of256(bytes: char8[..], into: var char8[..]) ``` The SHA3-256 digest of `bytes`, in one call. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Crypto/Src/Keccak.rux#L247){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------- | --------------- | ------------------- | | `bytes` | `char8[..]` | the bytes to absorb | | `into` | `var char8[..]` | receives the output | ### `Sha3Of384` ```rux pub func Sha3Of384(bytes: char8[..], into: var char8[..]) ``` The SHA3-384 digest of `bytes`, in one call. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Crypto/Src/Keccak.rux#L257){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------- | --------------- | ------------------- | | `bytes` | `char8[..]` | the bytes to absorb | | `into` | `var char8[..]` | receives the output | ### `Sha3Of512` ```rux pub func Sha3Of512(bytes: char8[..], into: var char8[..]) ``` The SHA3-512 digest of `bytes`, in one call. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Crypto/Src/Keccak.rux#L267){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------- | --------------- | ------------------- | | `bytes` | `char8[..]` | the bytes to absorb | | `into` | `var char8[..]` | receives the output | # Sha512 An incremental SHA-512, SHA-384, SHA-512/224 or SHA-512/256. ```rux pub struct Sha512 { // private fields } ``` Structural `Copy`; copying takes an independent snapshot of the digest state. ## Constructors ### `Sha512` ```rux pub func Sha512() -> Sha512 ``` A SHA-512 state. **Returns**: a hasher producing a 512-bit digest [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Crypto/Src/Sha512.rux#L99){rel=""nofollow""} ## Associated functions ### `New384` ```rux pub func New384() -> Sha512 ``` A SHA-384 state. **Returns**: a hasher producing a 384-bit digest [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Crypto/Src/Sha512.rux#L106){rel=""nofollow""} ### `NewTrunc224` ```rux pub func NewTrunc224() -> Sha512 ``` A SHA-512/224 state. **Returns**: a hasher producing SHA-512/224 [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Crypto/Src/Sha512.rux#L113){rel=""nofollow""} ### `NewTrunc256` ```rux pub func NewTrunc256() -> Sha512 ``` A SHA-512/256 state. **Returns**: a hasher producing SHA-512/256 [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Crypto/Src/Sha512.rux#L120){rel=""nofollow""} ## Implements Digest `Sha512` conforms to [`Digest`](https://rux-lang.dev/docs/api/crypto/digest). ### `Update` ```rux pub func Update(self: &var Sha512, bytes: char8[..]) ``` Adds `bytes` to the message. | Name | Type | Description | | ------- | ----------- | ------------------- | | `bytes` | `char8[..]` | the bytes to absorb | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Crypto/Src/Sha512.rux#L190){rel=""nofollow""} ### `Finish` ```rux pub func Finish(self: &var Sha512, into: var char8[..]) ``` Writes the digest into `into`. The padding carries a hundred and twenty eight bit length, so the final block needs seventeen free bytes rather than nine; a block with fewer takes a whole further block. | Name | Type | Description | | ------ | --------------- | ------------------- | | `into` | `var char8[..]` | receives the output | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Crypto/Src/Sha512.rux#L220){rel=""nofollow""} ### `DigestLength` ```rux pub func DigestLength(self: &Sha512) -> uint ``` Sixty-four, forty-eight, thirty-two or twenty-eight bytes, depending on which variant this is. **Returns**: how many bytes a digest occupies [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Crypto/Src/Sha512.rux#L265){rel=""nofollow""} ### `BlockLength` ```rux pub func BlockLength(self: &Sha512) -> uint ``` A hundred and twenty eight bytes, for every variant. **Returns**: how many bytes the compression function consumes at a time [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Crypto/Src/Sha512.rux#L272){rel=""nofollow""} ## Related ### `Sha512Of` ```rux pub func Sha512Of(bytes: char8[..], into: var char8[..]) ``` The SHA-512 digest of `bytes`, in one call. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Crypto/Src/Sha512.rux#L281){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------- | --------------- | ------------------- | | `bytes` | `char8[..]` | the bytes to absorb | | `into` | `var char8[..]` | receives the output | ### `Sha384Of` ```rux pub func Sha384Of(bytes: char8[..], into: var char8[..]) ``` The SHA-384 digest of `bytes`, in one call. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Crypto/Src/Sha512.rux#L291){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------- | --------------- | ------------------- | | `bytes` | `char8[..]` | the bytes to absorb | | `into` | `var char8[..]` | receives the output | ### `Sha512Trunc224Of` ```rux pub func Sha512Trunc224Of( bytes: char8[..], into: var char8[..] ) ``` The SHA-512/224 digest of `bytes`, in one call. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Crypto/Src/Sha512.rux#L301){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------- | --------------- | ------------------- | | `bytes` | `char8[..]` | the bytes to absorb | | `into` | `var char8[..]` | receives the output | ### `Sha512Trunc256Of` ```rux pub func Sha512Trunc256Of( bytes: char8[..], into: var char8[..] ) ``` The SHA-512/256 digest of `bytes`, in one call. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Crypto/Src/Sha512.rux#L311){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------- | --------------- | ------------------- | | `bytes` | `char8[..]` | the bytes to absorb | | `into` | `var char8[..]` | receives the output | # Shake An extendable-output function: absorb a message, then read as many bytes as wanted. ```rux pub struct Shake { // private fields } ``` Structural `Copy`; copying takes an independent snapshot of the sponge and read position. ## Associated functions ### `New128` ```rux pub func New128() -> Shake ``` A SHAKE128 state: 128 bits of security, absorbing 168 bytes at a time. **Returns**: a SHAKE128 sponge, which produces output of any length [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Crypto/Src/Shake.rux#L47){rel=""nofollow""} ### `New256` ```rux pub func New256() -> Shake ``` A SHAKE256 state: 256 bits of security, absorbing 136 bytes at a time. **Returns**: a SHAKE256 sponge, which produces output of any length [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Crypto/Src/Shake.rux#L54){rel=""nofollow""} ## Methods ### `Update` ```rux pub func Update(self: &var Shake, bytes: char8[..]) ``` Absorbs `bytes` into the state. Absorbing after reading has begun is a caller error: the stream is a function of everything absorbed before the first read, and adding to it afterwards would silently change what a caller already has. This ignores such a call rather than corrupting the stream. | Name | Type | Description | | ------- | ----------- | ------------------- | | `bytes` | `char8[..]` | the bytes to absorb | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Crypto/Src/Shake.rux#L64){rel=""nofollow""} ### `Read` ```rux pub func Read(self: &var Shake, into: var char8[..]) ``` Fills `into` with the next bytes of the stream. Reading is continuous: any sequence of reads totalling the same number of bytes gives the same bytes. The first read applies the padding, after which [`Update`](https://rux-lang.dev/docs/api/crypto/shake#update) does nothing. | Name | Type | Description | | ------ | --------------- | ------------------- | | `into` | `var char8[..]` | receives the output | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Crypto/Src/Shake.rux#L100){rel=""nofollow""} ### `Rate` ```rux pub func Rate(self: &Shake) -> uint ``` How many bytes the state absorbs or squeezes before permuting. **Returns**: how many bytes the sponge absorbs or squeezes per permutation [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Crypto/Src/Shake.rux#L122){rel=""nofollow""} ## Related ### `Shake128Of` ```rux pub func Shake128Of(bytes: char8[..], into: var char8[..]) ``` `into.length` bytes of SHAKE128 over `bytes`, in one call. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Crypto/Src/Shake.rux#L131){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------- | --------------- | ------------------- | | `bytes` | `char8[..]` | the bytes to absorb | | `into` | `var char8[..]` | receives the output | ### `Shake256Of` ```rux pub func Shake256Of(bytes: char8[..], into: var char8[..]) ``` `into.length` bytes of SHAKE256 over `bytes`, in one call. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Crypto/Src/Shake.rux#L141){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------- | --------------- | ------------------- | | `bytes` | `char8[..]` | the bytes to absorb | | `into` | `var char8[..]` | receives the output | # Hkdf\<D> Extract and expand in one call: the whole of HKDF. ```rux pub func Hkdf<D: Digest>( prototype: D, salt: char8[..], material: char8[..], info: char8[..], into: var char8[..] ) -> bool ``` Returns `false` for an output longer than 255 digests, exactly as [`HkdfExpand`](https://rux-lang.dev/docs/api/crypto/hkdf#hkdf-expand) does. ## Type parameters | Name | Description | | ----------- | --------------- | | `D: Digest` | the digest type | ## Parameters | Name | Type | Description | | ----------- | --------------- | ---------------------------------------------------- | | `prototype` | `D` | any value of the digest type, read only to select it | | `salt` | `char8[..]` | the salt, which may be empty | | `material` | `char8[..]` | the input keying material | | `info` | `char8[..]` | the context and application-specific information | | `into` | `var char8[..]` | receives the output | **Returns**: whether `into` was a length this construction can produce ## Related ### `HkdfMaximumBlocks` ```rux pub const HkdfMaximumBlocks: uint = 255; ``` The most blocks `Expand` can produce, since its counter is one byte. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Crypto/Src/Hkdf.rux#L17){rel=""nofollow""} ### `HkdfExtract<D>` ```rux pub func HkdfExtract<D: Digest>( prototype: D, salt: char8[..], material: char8[..], into: var char8[..] ) ``` Extracts a pseudorandom key from `material`, salted with `salt`. `into` must be exactly the digest's length. An empty salt is legal and means a string of that many zeros, which is what the specification says — so an absent salt is not the same as no salt at all. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Crypto/Src/Hkdf.rux#L28){rel=""nofollow""} **Type parameters** | Name | Description | | ----------- | --------------- | | `D: Digest` | the digest type | **Parameters** | Name | Type | Description | | ----------- | --------------- | ---------------------------------------------------- | | `prototype` | `D` | any value of the digest type, read only to select it | | `salt` | `char8[..]` | the salt, which may be empty | | `material` | `char8[..]` | the input keying material | | `into` | `var char8[..]` | receives the output | ### `HkdfExpand<D>` ```rux pub func HkdfExpand<D: Digest>( prototype: D, key: char8[..], info: char8[..], into: var char8[..] ) -> bool ``` Expands `key` into `into`, separated by `info`. Returns `false` when `into` is longer than 255 digests, which is the most the one-byte counter can address; nothing is written in that case. `info` names what the derived key is for, and two expansions of one key under different info strings are unrelated. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Crypto/Src/Hkdf.rux#L57){rel=""nofollow""} **Type parameters** | Name | Description | | ----------- | --------------- | | `D: Digest` | the digest type | **Parameters** | Name | Type | Description | | ----------- | --------------- | ---------------------------------------------------- | | `prototype` | `D` | any value of the digest type, read only to select it | | `key` | `char8[..]` | the key | | `info` | `char8[..]` | the context and application-specific information | | `into` | `var char8[..]` | receives the output | **Returns**: whether `into` was a length this construction can produce # Secrets Comparing secrets in constant time and wiping them so the compiler cannot skip it. ## `Equal` ```rux pub func Equal(left: char8[..], right: char8[..]) -> bool ``` Whether two byte sequences are equal, in time that does not depend on where they differ. The ordinary comparison returns at the first difference, so its duration reveals the length of the matching prefix. Against a message authentication tag that is enough to find the correct tag one byte at a time -- a few thousand attempts rather than the number the tag's length suggests. This reads every byte of both sequences whatever it finds, accumulating differences rather than branching on them. Sequences of different lengths are unequal, and that answer is immediate: a length is not a secret, and pretending otherwise would mean reading past one of them. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Crypto/Src/Digest.rux#L65){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------- | ----------- | ------------------------ | | `left` | `char8[..]` | one of the two byte runs | | `right` | `char8[..]` | the other | **Returns**: whether the two runs match, compared in time that does not depend on where they differ ## `Wipe` ```rux pub func Wipe(bytes: var char8[..]) ``` Overwrites `bytes` with zeros in a way the compiler may not remove. A plain loop clearing a buffer nothing reads afterwards is dead code, and an optimizer is entitled to delete it — which is how a key a program believed it had erased stays in memory, in a core dump, or in a page written to swap. The barrier below is handed the buffer's address and its body is opaque, so the writes must have happened before it runs and the call cannot be dropped. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Crypto/Src/Digest.rux#L101){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------- | --------------- | ------------------ | | `bytes` | `var char8[..]` | the bytes to clear | # C C standard library bindings. ## Installation Add `C` to the `[Dependencies]` table of your package's `Rux.toml`: ```toml [Dependencies] C = { Namespace = "Rux", Version = "0.1.0" } ``` Standard packages are declared by hand: the registry does not serve them, so `rux add Rux/C` cannot add them. ## Dependencies - [`Core`](https://rux-lang.dev/docs/api/core) 0.1.0 ## Guide C standard library bindings, for interoperating with existing native code. Nothing else in the standard packages depends on this one. [`Rux/Io`](https://github.com/rux-lang/Rux/blob/main/Packages/C/../Io){rel=""nofollow""}, [`Rux/Memory`](https://github.com/rux-lang/Rux/blob/main/Packages/C/../Memory){rel=""nofollow""}, and [`Rux/Math`](https://github.com/rux-lang/Rux/blob/main/Packages/C/../Math){rel=""nofollow""} each reach the platform directly instead, so a Rux program links no C runtime unless it asks for one by importing this package. ### What it provides | Module | Covers | | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `Types` | the C ABI's own types, `errno` access, and the opaque handles | | `String` | `<char8[..].h>` — counted memory operations and terminated byte strings | | `StdIo` | `<stdio.h>` — streams, `printf` family, [`fopen`](https://rux-lang.dev/docs/api/c/stdio#fopen)/[`fclose`](https://rux-lang.dev/docs/api/c/stdio#fclose), positioning | | `StdLib` | `<stdlib.h>` — allocation, conversion, process control, sorting, searching | | `Math` | `<math.h>` — the elementary functions in both `double` and `float` forms | | `Time` | `<time.h>` — clocks, calendar time, and [`timespec`](https://rux-lang.dev/docs/api/c/timespec) | A declaration that has to match a C interface is written against the `Types` aliases rather than Rux's own widths: [`c_int`](https://rux-lang.dev/docs/api/c/types#c-int), [`c_long`](https://rux-lang.dev/docs/api/c/types#c-long) and [`c_ulong`](https://rux-lang.dev/docs/api/c/types#c-ulong) (which the two data models disagree about), [`c_char`](https://rux-lang.dev/docs/api/c/types#c-char) and its two explicit-signedness siblings, [`size_t`](https://rux-lang.dev/docs/api/c/types#size-t), [`ssize_t`](https://rux-lang.dev/docs/api/c/types#ssize-t), [`ptrdiff_t`](https://rux-lang.dev/docs/api/c/types#ptrdiff-t), [`intptr_t`](https://rux-lang.dev/docs/api/c/types#intptr-t), [`uintptr_t`](https://rux-lang.dev/docs/api/c/types#uintptr-t) and [`wchar_t`](https://rux-lang.dev/docs/api/c/types#wchar-t). A stream is a `*FILE` and a stream position is a `*fpos_t`, both declared with no fields, so one handle cannot be passed where another was meant. [`ErrnoLocation`](https://rux-lang.dev/docs/api/c/errno#errno-location) returns the address of the calling thread's `errno` through whichever accessor the platform exports, [`Errno`](https://rux-lang.dev/docs/api/c/errno#errno) reads it, [`ErrnoLocationFor`](https://rux-lang.dev/docs/api/c/errno#errno-location-for) and [`ErrnoFor`](https://rux-lang.dev/docs/api/c/errno#errno-for) name which of the package's runtimes to read, and [`EDOM`](https://rux-lang.dev/docs/api/c/errno#edom), [`ERANGE`](https://rux-lang.dev/docs/api/c/errno#erange) and [`EILSEQ`](https://rux-lang.dev/docs/api/c/errno#eilseq) are the three values C itself mandates. ### Two C runtimes on Windows `StdLib` and `Math` bind the Universal CRT (`ucrtbase.dll`); `StdIo` and `Time` bind the legacy `msvcrt.dll`, which is the only one exporting the formatted-output family. They are two loaded modules with two distinct `_errno` entry points, and [`CRuntime`](https://rux-lang.dev/docs/api/c/errno#c-runtime) and [`StreamRuntime`](https://rux-lang.dev/docs/api/c/errno#stream-runtime) name them. [`SeparateStreamRuntime`](https://rux-lang.dev/docs/api/c/errno#separate-stream-runtime) is true here and false everywhere else, where both constants name the one runtime. `ErrnoFor(CRuntimeArea::Streams)` reads the runtime `StdIo` and `Time` are bound to and `ErrnoFor(CRuntimeArea::General)` the one `StdLib` and `Math` are bound to, so a caller reads the errno belonging to the call it actually made. Plain [`Errno`](https://rux-lang.dev/docs/api/c/errno#errno) is the `General` case. On the three Unix systems both areas name the same storage, so passing the area matching the module called is right on all four targets and needs no branch in caller code. **What was measured, on Windows 11 with the current system DLLs.** The two `_errno` functions are different exports at different addresses, and both return *the same* per-thread storage: today's `msvcrt.dll` defers to the Universal CRT rather than keeping an `errno` of its own. Separately, a failing [`fopen`](https://rux-lang.dev/docs/api/c/stdio#fopen) through `msvcrt.dll` sets no `errno` at all, in either runtime — its failure is the null `FILE*` and nothing else. So the rule to follow after a `StdIo` or `Time` call is to read the return value, not `errno`; and where `errno` is consulted anyway, [`ErrnoFor`](https://rux-lang.dev/docs/api/c/errno#errno-for) is what names the runtime rather than leaving it to whichever accessor happened to be linked. A different Windows may resolve the two differently, which is exactly why the area is passed rather than assumed. Both `StdLib` and `StdIo` are curated rather than complete, and what is left out is left out on purpose. `gets` is not declared at all: it reads a line into a buffer whose size it is never told, and C11 removed it. The `ato*` conversions are declared but each one says to prefer the `strto*` family beside it, which can report both where it stopped and a value out of range. [`sprintf`](https://rux-lang.dev/docs/api/c/stdio#sprintf) and the `scanf` family are marked as writing as much as the format says to; `tmpnam` as naming a file it does not create; `system` as running whatever the shell decides its argument means; [`rand`](https://rux-lang.dev/docs/api/c/stdlib#rand) as guaranteeing nothing about its sequence and never to be used for anything an adversary would like to predict. `String` holds two families that are not alike. The `mem*` calls take a length and touch exactly that many bytes; the `str*` calls take none and stop at the first zero byte, which means the caller has promised there is one. Where both forms exist the counted one is the one to reach for, and `Rux/Memory` and `Rux/Text` do these jobs with lengths that are checked. Each declaration records what it requires of its arguments, including the traps worth naming: [`strncpy`](https://rux-lang.dev/docs/api/c/string#strncpy) does not terminate a source that fills the count, [`strcat`](https://rux-lang.dev/docs/api/c/string#strcat) walks the destination from its start on every call, and [`strtok`](https://rux-lang.dev/docs/api/c/string#strtok) keeps its position in storage shared by the whole program. Each module selects the right declarations for the target at compile time, so the same import works across the supported platforms. `rux check --target <triple>` resolves every declaration here on all eight supported cells, and the `Layout` test checks the sizes and the runtime-filled structures on whichever one it runs. ### Values and pointers C ABI records such as [`timespec`](https://rux-lang.dev/docs/api/c/timespec) are ordinary structural values and copy by value. Safe package helpers borrow them: `TimespecGet(value, TIME_UTC)` takes a mutable reference, so callers pass the value itself. C declarations keep raw pointers where the ABI permits null, returns an address, accepts an untyped buffer, or relies on pointer arithmetic. Those calls inherit C's validity, lifetime, alignment, and overlap requirements; use `Rux/Memory`, `Rux/Text`, or `Rux/Io` when a checked interface exists. Two things are absent from `Math` on purpose. `fabsf`, `frexpf`, `ldexpf` and `hypotf` are header inlines in the Universal CRT rather than exported symbols, so declaring them would link on Unix and fail on Windows. The `nexttoward` pair takes a `long double`, which is a different type on every target — 64 bits under the Universal CRT, an 80-bit x87 value on x86-64 Unix, a 128-bit quad on AArch64 — so no one declaration is right everywhere. `Rux/Math` computes at every width without a C runtime and is the portable answer. The module names above describe where each declaration comes from; they are not part of an import path. ### Example Declarations are flat under the package, so an import names the function rather than the header it came from: ```rux import C::{ CRuntimeArea, ErrnoFor, ErrnoLocationFor, free, malloc, puts }; func Main() -> int { // A Rux literal is a `char8[..]` and a C declaration takes a `*char8`, so the address is passed explicitly. var buffer = malloc(1024); if buffer == null { puts("allocation refused".data); return 1; } puts("allocated".data); free(buffer); // Clearing before the call is how C's `errno = 0` is spelled; nothing clears it on success. `malloc` comes from // `StdLib`, so its failure is readable in the `General` area. *ErrnoLocationFor(CRuntimeArea::General) = 0i32; let refused = malloc(18446744073709551615u64); if refused == null && ErrnoFor(CRuntimeArea::General) != 0i32 { puts("and the refusal reported a reason".data); } return 0; } ``` This one compiles and runs on all eight target cells; the previous version of it did not compile at all, because it passed a literal where a `*char8` was wanted. ## Index ### Types | Name | Summary | | ---------------------------------------------------------------------- | ---------------------------------------------------------------------------------------- | | [`time_t`](https://rux-lang.dev/docs/api/c/time#time-t) | C's `time_t`: a calendar time as an arithmetic value. | | [`clock_t`](https://rux-lang.dev/docs/api/c/time#clock-t) | C's `clock_t`: processor time as an arithmetic value. | | [`tm`](https://rux-lang.dev/docs/api/c/tm) | C's `tm`: a calendar time broken into its components. | | [`timespec`](https://rux-lang.dev/docs/api/c/timespec) | The public `timespec` data layout. | | [`c_schar`](https://rux-lang.dev/docs/api/c/types#c-schar) | C's `signed char`: the smallest addressable signed integer. | | [`c_uchar`](https://rux-lang.dev/docs/api/c/types#c-uchar) | C's `unsigned char`, which is also the type a byte of arbitrary storage is read through. | | [`c_char`](https://rux-lang.dev/docs/api/c/types#c-char) | C's plain `char`, whose signedness the standard leaves to the implementation. | | [`c_short`](https://rux-lang.dev/docs/api/c/types#c-short) | C's `short`. | | [`c_ushort`](https://rux-lang.dev/docs/api/c/types#c-ushort) | C's `unsigned short`. | | [`c_int`](https://rux-lang.dev/docs/api/c/types#c-int) | C's `int`, which is 32 bits on every currently supported target. | | [`c_uint`](https://rux-lang.dev/docs/api/c/types#c-uint) | C's `unsigned int`. | | [`c_longlong`](https://rux-lang.dev/docs/api/c/types#c-longlong) | C's `long long`. | | [`c_ulonglong`](https://rux-lang.dev/docs/api/c/types#c-ulonglong) | C's `unsigned long long`. | | [`c_float`](https://rux-lang.dev/docs/api/c/types#c-float) | C's `float`. | | [`c_double`](https://rux-lang.dev/docs/api/c/types#c-double) | C's `double`. | | [`c_bool`](https://rux-lang.dev/docs/api/c/types#c-bool) | C's `_Bool`, which occupies one byte and holds zero or one. | | [`c_long`](https://rux-lang.dev/docs/api/c/types#c-long) | C's `long`, 32 bits under this target's LLP64 data model. | | [`c_ulong`](https://rux-lang.dev/docs/api/c/types#c-ulong) | C's `unsigned long`, 32 bits under this target's LLP64 data model. | | [`wchar_t`](https://rux-lang.dev/docs/api/c/types#wchar-t) | C's `wchar_t`, a 16-bit UTF-16 code unit on Windows rather than a whole scalar value. | | [`size_t`](https://rux-lang.dev/docs/api/c/types#size-t) | C's `size_t`: the type of a size, a count of bytes, and the result of `sizeof`. | | [`ssize_t`](https://rux-lang.dev/docs/api/c/types#ssize-t) | POSIX's `ssize_t`: a size that can also report `-1` for failure. | | [`ptrdiff_t`](https://rux-lang.dev/docs/api/c/types#ptrdiff-t) | C's `ptrdiff_t`: the signed difference between two pointers into one object. | | [`intptr_t`](https://rux-lang.dev/docs/api/c/types#intptr-t) | C's `intptr_t`: a signed integer wide enough to hold any pointer. | | [`uintptr_t`](https://rux-lang.dev/docs/api/c/types#uintptr-t) | C's `uintptr_t`: an unsigned integer wide enough to hold any pointer. | | [`FILE`](https://rux-lang.dev/docs/api/c/stdio#file) | C's `FILE`: a stream, whose contents belong to the C runtime. | | [`fpos_t`](https://rux-lang.dev/docs/api/c/stdio#fpos-t) | C's `fpos_t`: an opaque record of a position within a stream. | | [`CRuntimeArea`](https://rux-lang.dev/docs/api/c/errno#c-runtime-area) | Which of the package's C runtimes a call belongs to. | ### Functions | Name | Summary | | ------------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------- | | [`cbrt`](https://rux-lang.dev/docs/api/c/math#cbrt) | Computes cube root. | | [`ceil`](https://rux-lang.dev/docs/api/c/math#ceil) | Computes smallest integer not less than the given value. | | [`copysign`](https://rux-lang.dev/docs/api/c/math#copysign) | Copies the sign of a floating-point value. | | [`cos`](https://rux-lang.dev/docs/api/c/math#cos) | Computes cosine. | | [`exp`](https://rux-lang.dev/docs/api/c/math#exp) | Computes e raised to the given power. | | [`fabs`](https://rux-lang.dev/docs/api/c/math#fabs) | Computes the absolute value of a floating-point value. | | [`fdim`](https://rux-lang.dev/docs/api/c/math#fdim) | Computes positive difference of two floating-point values. | | [`floor`](https://rux-lang.dev/docs/api/c/math#floor) | Computes largest integer not greater than the given value. | | [`fmax`](https://rux-lang.dev/docs/api/c/math#fmax) | Computes larger of two floating-point values. | | [`fmin`](https://rux-lang.dev/docs/api/c/math#fmin) | Computes smaller of two floating-point values. | | [`fmod`](https://rux-lang.dev/docs/api/c/math#fmod) | Computes remainder of the floating-point division operation. | | [`hypot`](https://rux-lang.dev/docs/api/c/math#hypot) | Computes square root of the sum of the squares of two given numbers. | | [`ldexp`](https://rux-lang.dev/docs/api/c/math#ldexp) | Multiplies a number by 2 raised to an integer power. | | [`log`](https://rux-lang.dev/docs/api/c/math#log) | Computes natural (base e) logarithm. | | [`log2`](https://rux-lang.dev/docs/api/c/math#log2) | Computes base 2 logarithm. | | [`pow`](https://rux-lang.dev/docs/api/c/math#pow) | Computes a number raised to the given power. | | [`round`](https://rux-lang.dev/docs/api/c/math#round) | Rounds to nearest integer, rounding away from zero in halfway cases. | | [`scalbln`](https://rux-lang.dev/docs/api/c/math#scalbln) | Computes sine. | | [`scalblnf`](https://rux-lang.dev/docs/api/c/math#scalblnf) | Multiplies a floating-point value by an integral power of two, with a long exponent. | | [`sin`](https://rux-lang.dev/docs/api/c/math#sin) | Computes sine. | | [`sqrtf`](https://rux-lang.dev/docs/api/c/math#sqrtf) | Computes square root. | | [`sqrt`](https://rux-lang.dev/docs/api/c/math#sqrt) | Computes square root. | | [`tan`](https://rux-lang.dev/docs/api/c/math#tan) | Computes tangent. | | [`trunc`](https://rux-lang.dev/docs/api/c/math#trunc) | Rounds to nearest integer not greater in magnitude than the given value. | | [`fclose`](https://rux-lang.dev/docs/api/c/stdio#fclose) | Closes the given file stream. | | [`fgetc`](https://rux-lang.dev/docs/api/c/stdio#fgetc) | Reads the next character from the given stream. | | [`fopen`](https://rux-lang.dev/docs/api/c/stdio#fopen) | Opens a file indicated by filename with the given mode. | | [`fseek`](https://rux-lang.dev/docs/api/c/stdio#fseek) | Sets the file position indicator for the stream. | | [`ftell`](https://rux-lang.dev/docs/api/c/stdio#ftell) | Returns the current file position of the stream. | | [`fwrite`](https://rux-lang.dev/docs/api/c/stdio#fwrite) | Writes count objects of the given size from a buffer to the stream. | | [`putchar`](https://rux-lang.dev/docs/api/c/stdio#putchar) | Writes a character to stdout. | | [`puts`](https://rux-lang.dev/docs/api/c/stdio#puts) | Writes a string followed by a newline to stdout. | | [`remove`](https://rux-lang.dev/docs/api/c/stdio#remove) | Deletes the file identified by the given path. | | [`sprintf`](https://rux-lang.dev/docs/api/c/stdio#sprintf) | Prints formatted output to a string. | | [`sscanf`](https://rux-lang.dev/docs/api/c/stdio#sscanf) | Reads formatted input from a string. | | [`abs`](https://rux-lang.dev/docs/api/c/stdlib#abs) | Computes the absolute value of an integer value. | | [`atof`](https://rux-lang.dev/docs/api/c/stdlib#atof) | Converts a byte string to a floating point value. | | [`atoi`](https://rux-lang.dev/docs/api/c/stdlib#atoi) | Converts a byte string to an integer value. | | [`atol`](https://rux-lang.dev/docs/api/c/stdlib#atol) | Converts a byte string to a long integer value. | | [`atoll`](https://rux-lang.dev/docs/api/c/stdlib#atoll) | Converts a byte string to a long long integer value. | | [`calloc`](https://rux-lang.dev/docs/api/c/stdlib#calloc) | Allocates memory for an array of num objects of size and zero-initializes it. | | [`free`](https://rux-lang.dev/docs/api/c/stdlib#free) | Deallocates the memory previously allocated by malloc, calloc or realloc. | | [`labs`](https://rux-lang.dev/docs/api/c/stdlib#labs) | Computes the absolute value of a long integer value. | | [`llabs`](https://rux-lang.dev/docs/api/c/stdlib#llabs) | Computes the absolute value of a long long integer value. | | [`malloc`](https://rux-lang.dev/docs/api/c/stdlib#malloc) | Allocates size bytes of uninitialized memory. | | [`rand`](https://rux-lang.dev/docs/api/c/stdlib#rand) | Returns a pseudo-random integer value between 0 and RAND\_MAX. | | [`realloc`](https://rux-lang.dev/docs/api/c/stdlib#realloc) | Changes the size of the memory block pointed to by ptr to size bytes. | | [`srand`](https://rux-lang.dev/docs/api/c/stdlib#srand) | Seeds the pseudo-random number generator used by rand. | | [`strtol`](https://rux-lang.dev/docs/api/c/stdlib#strtol) | Converts a byte string to a long integer, reporting where it stopped. | | [`strtoul`](https://rux-lang.dev/docs/api/c/stdlib#strtoul) | Converts a byte string to an unsigned long integer, reporting where it stopped. | | [`strtoll`](https://rux-lang.dev/docs/api/c/stdlib#strtoll) | Converts a byte string to a long long integer, reporting where it stopped. | | [`strtoull`](https://rux-lang.dev/docs/api/c/stdlib#strtoull) | Converts a byte string to an unsigned long long integer, reporting where it stopped. | | [`strtod`](https://rux-lang.dev/docs/api/c/stdlib#strtod) | Converts a byte string to a double, reporting where it stopped. | | [`strtof`](https://rux-lang.dev/docs/api/c/stdlib#strtof) | Converts a byte string to a float, reporting where it stopped. | | [`qsort`](https://rux-lang.dev/docs/api/c/stdlib#qsort) | Sorts an array in place; the comparison must be a strict weak ordering and the sort is not stable. | | [`bsearch`](https://rux-lang.dev/docs/api/c/stdlib#bsearch) | Finds an element of a sorted array; the array must already be ordered by the same comparison. | | [`memchr`](https://rux-lang.dev/docs/api/c/string#memchr) | Finds the first byte equal to `ch` within the first `count` bytes. | | [`memcmp`](https://rux-lang.dev/docs/api/c/string#memcmp) | Compares the first `count` bytes of two objects. | | [`memcpy`](https://rux-lang.dev/docs/api/c/string#memcpy) | Copies `count` bytes from `src` to `dest`. | | [`memmove`](https://rux-lang.dev/docs/api/c/string#memmove) | Copies `count` bytes from `src` to `dest`, correctly even when the two overlap. | | [`memset`](https://rux-lang.dev/docs/api/c/string#memset) | Writes `ch` to each of the first `count` bytes of `dest`. | | [`strlen`](https://rux-lang.dev/docs/api/c/string#strlen) | The length of a byte string, not counting its terminator. | | [`strcmp`](https://rux-lang.dev/docs/api/c/string#strcmp) | Compares two byte strings. | | [`strncmp`](https://rux-lang.dev/docs/api/c/string#strncmp) | Compares at most `count` bytes of two byte strings. | | [`strcpy`](https://rux-lang.dev/docs/api/c/string#strcpy) | Copies a byte string, terminator included. | | [`strncpy`](https://rux-lang.dev/docs/api/c/string#strncpy) | Copies at most `count` bytes of a byte string, padding with zeros. | | [`strcat`](https://rux-lang.dev/docs/api/c/string#strcat) | Appends a byte string to the end of another. | | [`strncat`](https://rux-lang.dev/docs/api/c/string#strncat) | Appends at most `count` bytes of a byte string to the end of another. | | [`strchr`](https://rux-lang.dev/docs/api/c/string#strchr) | Finds the first occurrence of a byte in a byte string. | | [`strrchr`](https://rux-lang.dev/docs/api/c/string#strrchr) | Finds the last occurrence of a byte in a byte string. | | [`strstr`](https://rux-lang.dev/docs/api/c/string#strstr) | Finds the first occurrence of one byte string within another. | | [`strspn`](https://rux-lang.dev/docs/api/c/string#strspn) | The length of the leading run of bytes drawn only from `accept`. | | [`strcspn`](https://rux-lang.dev/docs/api/c/string#strcspn) | The length of the leading run of bytes drawn from none of `reject`. | | [`strpbrk`](https://rux-lang.dev/docs/api/c/string#strpbrk) | Finds the first byte of `str` that occurs in `accept`. | | [`strtok`](https://rux-lang.dev/docs/api/c/string#strtok) | Splits a byte string into tokens separated by any byte of `delimiters`. | | [`clock`](https://rux-lang.dev/docs/api/c/time#clock) | Returns the approximate processor time used by the program. | | [`difftime`](https://rux-lang.dev/docs/api/c/time#difftime) | Computes the difference in seconds between two calendar times. | | [`gmtime`](https://rux-lang.dev/docs/api/c/time#gmtime) | Converts a time\_t object to calendar time expressed as UTC. | | [`localtime`](https://rux-lang.dev/docs/api/c/time#localtime) | Converts a time\_t object to calendar time expressed as local time. | | [`mktime`](https://rux-lang.dev/docs/api/c/time#mktime) | Converts calendar time to a time\_t object, normalizing the tm structure. | | [`time`](https://rux-lang.dev/docs/api/c/time#time) | Returns the current calendar time since the epoch. | | [`TimespecGet`](https://rux-lang.dev/docs/api/c/time#timespec-get) | Fills `ts` with the current time on the given base. | | [`ErrnoLocationFor`](https://rux-lang.dev/docs/api/c/errno#errno-location-for) | The address of the calling thread's `errno`, in the runtime `area` names. | | [`ErrnoFor`](https://rux-lang.dev/docs/api/c/errno#errno-for) | The calling thread's current `errno` value, in the runtime `area` names. | | [`ErrnoLocation`](https://rux-lang.dev/docs/api/c/errno#errno-location) | The address of the calling thread's `errno`, in the runtime `C::StdLib` and `C::Math` are bound to. | | [`Errno`](https://rux-lang.dev/docs/api/c/errno#errno) | The calling thread's current `errno` value. | ### Constants | Name | Summary | | ---------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------- | | [`HUGE_VAL`](https://rux-lang.dev/docs/api/c/math#huge-val) | `HUGE_VAL`: what a `double` function returns when the true result is too large to express. | | [`HUGE_VALF`](https://rux-lang.dev/docs/api/c/math#huge-valf) | `HUGE_VALF`: the `float` form of [`HUGE_VAL`](https://rux-lang.dev/docs/api/c/math#huge-val). | | [`INFINITY`](https://rux-lang.dev/docs/api/c/math#infinity) | `INFINITY`: a positive infinity, for building a value rather than for testing one. | | [`NAN`](https://rux-lang.dev/docs/api/c/math#nan) | `NAN`: a quiet not-a-number, for building a value rather than for testing one. | | [`EOF`](https://rux-lang.dev/docs/api/c/stdio#eof) | `EOF`: what a character-reading call returns instead of a character when the stream has ended or failed. | | [`SEEK_SET`](https://rux-lang.dev/docs/api/c/stdio#seek-set) | `SEEK_SET`: measure the new stream position from the beginning. | | [`SEEK_CUR`](https://rux-lang.dev/docs/api/c/stdio#seek-cur) | `SEEK_CUR`: measure the new stream position from the current one. | | [`SEEK_END`](https://rux-lang.dev/docs/api/c/stdio#seek-end) | `SEEK_END`: measure the new stream position from the end. | | [`_IOFBF`](https://rux-lang.dev/docs/api/c/stdio#iofbf) | `_IOFBF`: buffer fully, flushing when the buffer fills. | | [`_IOLBF`](https://rux-lang.dev/docs/api/c/stdio#iolbf) | `_IOLBF`: buffer by line. | | [`_IONBF`](https://rux-lang.dev/docs/api/c/stdio#ionbf) | `_IONBF`: do not buffer. | | [`BUFSIZ`](https://rux-lang.dev/docs/api/c/stdio#bufsiz) | `BUFSIZ`: the buffer size `setbuf` uses. | | [`FOPEN_MAX`](https://rux-lang.dev/docs/api/c/stdio#fopen-max) | `FOPEN_MAX`: how many streams the implementation guarantees can be open at once. | | [`FILENAME_MAX`](https://rux-lang.dev/docs/api/c/stdio#filename-max) | `FILENAME_MAX`: the length of the longest file name the implementation guarantees it can open. | | [`L_tmpnam`](https://rux-lang.dev/docs/api/c/stdio#l-tmpnam) | `L_tmpnam`: the buffer size `tmpnam` needs. | | [`TMP_MAX`](https://rux-lang.dev/docs/api/c/stdio#tmp-max) | `TMP_MAX`: how many distinct names `tmpnam` guarantees before it repeats. | | [`EXIT_SUCCESS`](https://rux-lang.dev/docs/api/c/stdlib#exit-success) | `EXIT_SUCCESS`: the status a program returns to mean it did what it was asked. | | [`EXIT_FAILURE`](https://rux-lang.dev/docs/api/c/stdlib#exit-failure) | `EXIT_FAILURE`: the status a program returns to mean it did not. | | [`RAND_MAX`](https://rux-lang.dev/docs/api/c/stdlib#rand-max) | `RAND_MAX`: the largest value [`rand`](https://rux-lang.dev/docs/api/c/stdlib#rand) can return on this target. | | [`TIME_UTC`](https://rux-lang.dev/docs/api/c/time#time-utc) | `TIME_UTC`: the time base naming seconds since the epoch, the only one C defines. | | [`CLOCKS_PER_SEC`](https://rux-lang.dev/docs/api/c/time#clocks-per-sec) | `CLOCKS_PER_SEC`: how many [`clock`](https://rux-lang.dev/docs/api/c/time#clock) ticks make one second on this target. | | [`CRuntime`](https://rux-lang.dev/docs/api/c/errno#c-runtime) | The shared object this target's C runtime lives in. | | [`StreamRuntime`](https://rux-lang.dev/docs/api/c/errno#stream-runtime) | The shared object `C::StdIo` and `C::Time` are bound to, which on Windows is a different one. | | [`SeparateStreamRuntime`](https://rux-lang.dev/docs/api/c/errno#separate-stream-runtime) | Whether the two areas are really two runtimes on this target. | | [`EDOM`](https://rux-lang.dev/docs/api/c/errno#edom) | `EDOM`: an argument outside the domain over which a math function is defined. | | [`ERANGE`](https://rux-lang.dev/docs/api/c/errno#erange) | `ERANGE`: a result too large or too small for the return type to express. | | [`EILSEQ`](https://rux-lang.dev/docs/api/c/errno#eilseq) | `EILSEQ`: a byte sequence that does not form a valid character. | # timespec The public `timespec` data layout. ```rux pub struct timespec { pub tv_sec: time_t; pub tv_nsec: c_long; } ``` ## Fields | Name | Type | Description | | --------- | -------- | --------------------------------------------------- | | `tv_sec` | `time_t` | Whole seconds. | | `tv_nsec` | `c_long` | Nanoseconds within the second, in `[0, 999999999]`. | # tm C's `tm`: a calendar time broken into its components. ```rux pub struct tm { pub tm_sec: int32; pub tm_min: int32; pub tm_hour: int32; pub tm_mday: int32; pub tm_mon: int32; pub tm_year: int32; pub tm_wday: int32; pub tm_yday: int32; pub tm_isdst: int32; pub tm_gmtoff: int64; pub tm_zone: *char8; } ``` Two of the fields are traps rather than conveniences, and both are C's rather than this binding's: `tm_year` counts from 1900, so 2026 is 126, and `tm_mon` counts from zero, so December is 11. `tm_sec` reaches 60 for a leap second. Declared once per system because the field order and the trailing members differ; the nine standard fields are the same everywhere and are all this declares. **See also**: <https://en.cppreference.com/c/chrono/tm>{rel=""nofollow""} ## Fields | Name | Type | Description | | ----------- | -------- | ------------------------------------------------------------------------------------------------- | | `tm_sec` | `int32` | Seconds after the minute [0, 60]. | | `tm_min` | `int32` | Minutes after the hour [0, 59]. | | `tm_hour` | `int32` | Hours since midnight [0, 23]. | | `tm_mday` | `int32` | Day of the month [1, 31]. | | `tm_mon` | `int32` | Months since January [0, 11]. | | `tm_year` | `int32` | Years since 1900. | | `tm_wday` | `int32` | Days since Sunday [0, 6]. | | `tm_yday` | `int32` | Days since January 1 [0, 365]. | | `tm_isdst` | `int32` | Daylight saving time flag. | | `tm_gmtoff` | `int64` | Seconds east of UTC. A BSD and glibc extension, not in standard C. (Linux · macOS · FreeBSD only) | | `tm_zone` | `*char8` | The time zone's abbreviation, in storage the C runtime owns. (Linux · macOS · FreeBSD only) | # Types C's scalar types under their C names, sized for the current target. ## `c_bool` ```rux pub type c_bool = bool8 ``` C's `_Bool`, which occupies one byte and holds zero or one. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/C/Src/Types.rux#L75){rel=""nofollow""} ## `c_char` ```rux pub type c_char = int8 ``` C's plain `char`, whose signedness the standard leaves to the implementation. Signed on every currently supported target. A binding whose meaning depends on the sign should name [`c_schar`](https://rux-lang.dev/docs/api/c/types#c-schar) or [`c_uchar`](https://rux-lang.dev/docs/api/c/types#c-uchar) instead of relying on this. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/C/Src/Types.rux#L30){rel=""nofollow""} ## `c_double` ```rux pub type c_double = float64 ``` C's `double`. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/C/Src/Types.rux#L70){rel=""nofollow""} ## `c_float` ```rux pub type c_float = float32 ``` C's `float`. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/C/Src/Types.rux#L65){rel=""nofollow""} ## `c_int` ```rux pub type c_int = int32 ``` C's `int`, which is 32 bits on every currently supported target. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/C/Src/Types.rux#L45){rel=""nofollow""} ## `c_long` ```rux // Windows pub type c_long = int32 // Linux · macOS · FreeBSD pub type c_long = int64 ``` C's `long`, 32 bits under this target's LLP64 data model. | Overload | Summary | | ------------------------- | --------------------------------------------------------- | | `pub type c_long = int32` | C's `long`, 32 bits under this target's LLP64 data model. | | `pub type c_long = int64` | C's `long`, 64 bits under this target's LP64 data model. | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/C/Src/Types.rux#L85){rel=""nofollow""} ## `c_longlong` ```rux pub type c_longlong = int64 ``` C's `long long`. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/C/Src/Types.rux#L55){rel=""nofollow""} ## `c_schar` ```rux pub type c_schar = int8 ``` C's `signed char`: the smallest addressable signed integer. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/C/Src/Types.rux#L18){rel=""nofollow""} ## `c_short` ```rux pub type c_short = int16 ``` C's `short`. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/C/Src/Types.rux#L35){rel=""nofollow""} ## `c_uchar` ```rux pub type c_uchar = uint8 ``` C's `unsigned char`, which is also the type a byte of arbitrary storage is read through. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/C/Src/Types.rux#L23){rel=""nofollow""} ## `c_uint` ```rux pub type c_uint = uint32 ``` C's `unsigned int`. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/C/Src/Types.rux#L50){rel=""nofollow""} ## `c_ulong` ```rux // Windows pub type c_ulong = uint32 // Linux · macOS · FreeBSD pub type c_ulong = uint64 ``` C's `unsigned long`, 32 bits under this target's LLP64 data model. | Overload | Summary | | --------------------------- | ------------------------------------------------------------------ | | `pub type c_ulong = uint32` | C's `unsigned long`, 32 bits under this target's LLP64 data model. | | `pub type c_ulong = uint64` | C's `unsigned long`, 64 bits under this target's LP64 data model. | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/C/Src/Types.rux#L90){rel=""nofollow""} ## `c_ulonglong` ```rux pub type c_ulonglong = uint64 ``` C's `unsigned long long`. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/C/Src/Types.rux#L60){rel=""nofollow""} ## `c_ushort` ```rux pub type c_ushort = uint16 ``` C's `unsigned short`. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/C/Src/Types.rux#L40){rel=""nofollow""} ## `intptr_t` ```rux pub type intptr_t = int ``` C's `intptr_t`: a signed integer wide enough to hold any pointer. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/C/Src/Types.rux#L137){rel=""nofollow""} ## `ptrdiff_t` ```rux pub type ptrdiff_t = int ``` C's `ptrdiff_t`: the signed difference between two pointers into one object. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/C/Src/Types.rux#L132){rel=""nofollow""} ## `size_t` ```rux pub type size_t = uint ``` C's `size_t`: the type of a size, a count of bytes, and the result of `sizeof`. Pointer-sized and unsigned on every supported target. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/C/Src/Types.rux#L120){rel=""nofollow""} ## `ssize_t` ```rux pub type ssize_t = int ``` POSIX's `ssize_t`: a size that can also report `-1` for failure. Declared on every target for the sake of bindings that share a signature, though Windows has no such type of its own and its C runtime spells the same thing `int` or `__int64` depending on the call. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/C/Src/Types.rux#L127){rel=""nofollow""} ## `uintptr_t` ```rux pub type uintptr_t = uint ``` C's `uintptr_t`: an unsigned integer wide enough to hold any pointer. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/C/Src/Types.rux#L142){rel=""nofollow""} ## `wchar_t` ```rux // Windows pub type wchar_t = char16 // Linux · macOS · FreeBSD pub type wchar_t = char32 ``` C's `wchar_t`, a 16-bit UTF-16 code unit on Windows rather than a whole scalar value. | Overload | Summary | | --------------------------- | ------------------------------------------------------------------------------------- | | `pub type wchar_t = char16` | C's `wchar_t`, a 16-bit UTF-16 code unit on Windows rather than a whole scalar value. | | `pub type wchar_t = char32` | C's `wchar_t`, a 32-bit Unicode scalar value on this target. | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/C/Src/Types.rux#L95){rel=""nofollow""} # Mathematics C's `<math.h>`: the elementary functions and the special floating-point values. ## `cbrt` ```rux pub extern func cbrt(x: float64) -> float64 ``` Computes cube root. **See also**: <https://en.cppreference.com/c/numeric/math/cbrt>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/C/Src/Math.rux#L131){rel=""nofollow""} **Parameters** | Name | Type | Description | | ---- | --------- | ------------ | | `x` | `float64` | the argument | **Returns**: the computed value; the linked reference lists every special case ## `ceil` ```rux pub extern func ceil(x: float64) -> float64 ``` Computes smallest integer not less than the given value. **See also**: <https://en.cppreference.com/c/numeric/math/ceil>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/C/Src/Math.rux#L144){rel=""nofollow""} **Parameters** | Name | Type | Description | | ---- | --------- | ------------ | | `x` | `float64` | the argument | **Returns**: the computed value; the linked reference lists every special case ## `copysign` ```rux pub extern func copysign(x: float64, y: float64) -> float64 ``` Copies the sign of a floating-point value. **See also**: <https://en.cppreference.com/c/numeric/math/copysign>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/C/Src/Math.rux#L159){rel=""nofollow""} **Parameters** | Name | Type | Description | | ---- | --------- | ------------------- | | `x` | `float64` | the argument | | `y` | `float64` | the second argument | **Returns**: the computed value; the linked reference lists every special case ## `cos` ```rux pub extern func cos(x: float64) -> float64 ``` Computes cosine. **See also**: <https://en.cppreference.com/c/numeric/math/cos>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/C/Src/Math.rux#L172){rel=""nofollow""} **Parameters** | Name | Type | Description | | ---- | --------- | ------------ | | `x` | `float64` | the argument | **Returns**: the computed value; the linked reference lists every special case ## `exp` ```rux pub extern func exp(x: float64) -> float64 ``` Computes e raised to the given power. **See also**: <https://en.cppreference.com/c/numeric/math/exp>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/C/Src/Math.rux#L221){rel=""nofollow""} **Parameters** | Name | Type | Description | | ---- | --------- | ------------ | | `x` | `float64` | the argument | **Returns**: the computed value; the linked reference lists every special case ## `fabs` ```rux pub extern func fabs(x: float64) -> float64 ``` Computes the absolute value of a floating-point value. **See also**: <https://en.cppreference.com/c/numeric/math/fabs>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/C/Src/Math.rux#L252){rel=""nofollow""} **Parameters** | Name | Type | Description | | ---- | --------- | ------------ | | `x` | `float64` | the argument | **Returns**: the computed value; the linked reference lists every special case ## `fdim` ```rux pub extern func fdim(x: float64, y: float64) -> float64 ``` Computes positive difference of two floating-point values. **See also**: <https://en.cppreference.com/c/numeric/math/fdim>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/C/Src/Math.rux#L267){rel=""nofollow""} **Parameters** | Name | Type | Description | | ---- | --------- | ------------------- | | `x` | `float64` | the argument | | `y` | `float64` | the second argument | **Returns**: the computed value; the linked reference lists every special case ## `floor` ```rux pub extern func floor(x: float64) -> float64 ``` Computes largest integer not greater than the given value. **See also**: <https://en.cppreference.com/c/numeric/math/floor>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/C/Src/Math.rux#L280){rel=""nofollow""} **Parameters** | Name | Type | Description | | ---- | --------- | ------------ | | `x` | `float64` | the argument | **Returns**: the computed value; the linked reference lists every special case ## `fmax` ```rux pub extern func fmax(x: float64, y: float64) -> float64 ``` Computes larger of two floating-point values. **See also**: <https://en.cppreference.com/c/numeric/math/fmax>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/C/Src/Math.rux#L311){rel=""nofollow""} **Parameters** | Name | Type | Description | | ---- | --------- | ------------------- | | `x` | `float64` | the argument | | `y` | `float64` | the second argument | **Returns**: the computed value; the linked reference lists every special case ## `fmin` ```rux pub extern func fmin(x: float64, y: float64) -> float64 ``` Computes smaller of two floating-point values. **See also**: <https://en.cppreference.com/c/numeric/math/fmin>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/C/Src/Math.rux#L326){rel=""nofollow""} **Parameters** | Name | Type | Description | | ---- | --------- | ------------------- | | `x` | `float64` | the argument | | `y` | `float64` | the second argument | **Returns**: the computed value; the linked reference lists every special case ## `fmod` ```rux pub extern func fmod(x: float64, y: float64) -> float64 ``` Computes remainder of the floating-point division operation. **See also**: <https://en.cppreference.com/c/numeric/math/fmod>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/C/Src/Math.rux#L341){rel=""nofollow""} **Parameters** | Name | Type | Description | | ---- | --------- | ------------------- | | `x` | `float64` | the argument | | `y` | `float64` | the second argument | **Returns**: the computed value; the linked reference lists every special case ## `hypot` ```rux pub extern func hypot(x: float64, y: float64) -> float64 ``` Computes square root of the sum of the squares of two given numbers. **See also**: <https://en.cppreference.com/c/numeric/math/hypot>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/C/Src/Math.rux#L356){rel=""nofollow""} **Parameters** | Name | Type | Description | | ---- | --------- | ------------------- | | `x` | `float64` | the argument | | `y` | `float64` | the second argument | **Returns**: the computed value; the linked reference lists every special case ## `ldexp` ```rux pub extern func ldexp(x: float64, exp: int32) -> float64 ``` Multiplies a number by 2 raised to an integer power. **See also**: <https://en.cppreference.com/c/numeric/math/ldexp>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/C/Src/Math.rux#L376){rel=""nofollow""} **Parameters** | Name | Type | Description | | ----- | --------- | ------------------------------- | | `x` | `float64` | the argument | | `exp` | `int32` | the power of two to multiply by | **Returns**: the computed value; the linked reference lists every special case ## `log` ```rux pub extern func log(x: float64) -> float64 ``` Computes natural (base e) logarithm. **See also**: <https://en.cppreference.com/c/numeric/math/log>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/C/Src/Math.rux#L425){rel=""nofollow""} **Parameters** | Name | Type | Description | | ---- | --------- | ------------ | | `x` | `float64` | the argument | **Returns**: the computed value; the linked reference lists every special case ## `log2` ```rux pub extern func log2(x: float64) -> float64 ``` Computes base 2 logarithm. **See also**: <https://en.cppreference.com/c/numeric/math/log2>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/C/Src/Math.rux#L462){rel=""nofollow""} **Parameters** | Name | Type | Description | | ---- | --------- | ------------ | | `x` | `float64` | the argument | **Returns**: the computed value; the linked reference lists every special case ## `pow` ```rux pub extern func pow( base: float64, exponent: float64 ) -> float64 ``` Computes a number raised to the given power. **See also**: <https://en.cppreference.com/c/numeric/math/pow>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/C/Src/Math.rux#L565){rel=""nofollow""} **Parameters** | Name | Type | Description | | ---------- | --------- | ------------------------ | | `base` | `float64` | the value to raise | | `exponent` | `float64` | the power to raise it to | **Returns**: the computed value; the linked reference lists every special case ## `round` ```rux pub extern func round(x: float64) -> float64 ``` Rounds to nearest integer, rounding away from zero in halfway cases. **See also**: <https://en.cppreference.com/c/numeric/math/round>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/C/Src/Math.rux#L620){rel=""nofollow""} **Parameters** | Name | Type | Description | | ---- | --------- | ------------ | | `x` | `float64` | the argument | **Returns**: the computed value; the linked reference lists every special case ## `scalbln` ```rux pub extern func scalbln( arg: float64, exp: c_long ) -> float64 ``` Computes sine. <https://en.cppreference.com/c/numeric/math/sin>{rel=""nofollow""} Multiplies a floating-point value by an integral power of two, with a long exponent **See also**: <https://en.cppreference.com/c/numeric/math/scalbn>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/C/Src/Math.rux#L644){rel=""nofollow""} **Parameters** | Name | Type | Description | | ----- | --------- | -------------------- | | `arg` | `float64` | the value to convert | | `exp` | `c_long` | the exponent | **Returns**: the computed value; the linked reference lists every special case ## `scalblnf` ```rux pub extern func scalblnf( arg: float32, exp: c_long ) -> float32 ``` Multiplies a floating-point value by an integral power of two, with a long exponent. **See also**: <https://en.cppreference.com/c/numeric/math/scalbn>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/C/Src/Math.rux#L652){rel=""nofollow""} **Parameters** | Name | Type | Description | | ----- | --------- | -------------------- | | `arg` | `float32` | the value to convert | | `exp` | `c_long` | the exponent | **Returns**: the computed value; the linked reference lists every special case ## `sin` ```rux pub extern func sin(x: float64) -> float64 ``` Computes sine. **See also**: <https://en.cppreference.com/c/numeric/math/sin>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/C/Src/Math.rux#L661){rel=""nofollow""} **Parameters** | Name | Type | Description | | ---- | --------- | ------------ | | `x` | `float64` | the argument | **Returns**: the computed value; the linked reference lists every special case ## `sqrtf` ```rux pub extern func sqrtf(x: float32) -> float32 ``` Computes square root. **See also**: <https://en.cppreference.com/c/numeric/math/sqrt>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/C/Src/Math.rux#L680){rel=""nofollow""} **Parameters** | Name | Type | Description | | ---- | --------- | ------------ | | `x` | `float32` | the argument | **Returns**: the computed value; the linked reference lists every special case ## `sqrt` ```rux pub extern func sqrt(x: float64) -> float64 ``` Computes square root. **See also**: <https://en.cppreference.com/c/numeric/math/sqrt>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/C/Src/Math.rux#L687){rel=""nofollow""} **Parameters** | Name | Type | Description | | ---- | --------- | ------------ | | `x` | `float64` | the argument | **Returns**: the computed value; the linked reference lists every special case ## `tan` ```rux pub extern func tan(x: float64) -> float64 ``` Computes tangent. **See also**: <https://en.cppreference.com/c/numeric/math/tan>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/C/Src/Math.rux#L700){rel=""nofollow""} **Parameters** | Name | Type | Description | | ---- | --------- | ------------ | | `x` | `float64` | the argument | **Returns**: the computed value; the linked reference lists every special case ## `trunc` ```rux pub extern func trunc(x: float64) -> float64 ``` Rounds to nearest integer not greater in magnitude than the given value. **See also**: <https://en.cppreference.com/c/numeric/math/trunc>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/C/Src/Math.rux#L737){rel=""nofollow""} **Parameters** | Name | Type | Description | | ---- | --------- | ------------ | | `x` | `float64` | the argument | **Returns**: the computed value; the linked reference lists every special case ## `HUGE_VAL` ```rux pub const HUGE_VAL: float64 = float64::Infinity; ``` `HUGE_VAL`: what a `double` function returns when the true result is too large to express. An infinity on every supported target, which is what the standard permits and what every one of them chooses. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/C/Src/Math.rux#L747){rel=""nofollow""} ## `HUGE_VALF` ```rux pub const HUGE_VALF: float32 = float32::Infinity; ``` `HUGE_VALF`: the `float` form of [`HUGE_VAL`](https://rux-lang.dev/docs/api/c/math#huge-val). [Source](https://github.com/rux-lang/Rux/blob/main/Packages/C/Src/Math.rux#L752){rel=""nofollow""} ## `INFINITY` ```rux pub const INFINITY: float32 = float32::Infinity; ``` `INFINITY`: a positive infinity, for building a value rather than for testing one. Comparing against it is not how a caller asks whether a result overflowed; `Core::IsInfinite` answers that without naming a width. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/C/Src/Math.rux#L759){rel=""nofollow""} ## `NAN` ```rux pub const NAN: float32 = float32::NaN; ``` `NAN`: a quiet not-a-number, for building a value rather than for testing one. It equals nothing, itself included, so `value == NAN` is always false and is never the test a caller wants; `Core::IsNaN` is. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/C/Src/Math.rux#L766){rel=""nofollow""} # General utilities C's `<stdlib.h>`: allocation, number parsing, sorting, pseudo-random numbers and exit codes. ## `abs` ```rux pub extern func abs(n: c_int) -> c_int ``` Computes the absolute value of an integer value. **See also**: <https://en.cppreference.com/c/numeric/math/abs>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/C/Src/StdLib.rux#L39){rel=""nofollow""} **Parameters** | Name | Type | Description | | ---- | ------- | ------------------- | | `n` | `c_int` | the value to act on | **Returns**: the magnitude; the most negative value has none and the result is undefined ## `atof` ```rux pub extern func atof(str: *char8) -> c_double ``` Converts a byte string to a floating point value. Cannot report failure: a string that is not a number gives zero, and a value out of range is undefined rather than reported. Use strtod, which reports both. **See also**: <https://en.cppreference.com/c/string/byte/atof>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/C/Src/StdLib.rux#L48){rel=""nofollow""} **Parameters** | Name | Type | Description | | ----- | -------- | ----------------------------- | | `str` | `*char8` | a null-terminated byte string | **Returns**: the value, or zero when nothing was read; there is no way to tell the two apart ## `atoi` ```rux pub extern func atoi(str: *char8) -> c_int ``` Converts a byte string to an integer value. Cannot report failure, and a value out of range is undefined rather than reported. Use strtol. **See also**: <https://en.cppreference.com/c/string/byte/atoi>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/C/Src/StdLib.rux#L56){rel=""nofollow""} **Parameters** | Name | Type | Description | | ----- | -------- | ----------------------------- | | `str` | `*char8` | a null-terminated byte string | **Returns**: the value, or zero when nothing was read; there is no way to tell the two apart ## `atol` ```rux pub extern func atol(str: *char8) -> int64 ``` Converts a byte string to a long integer value. Cannot report failure. Use strtol. **See also**: <https://en.cppreference.com/c/string/byte/atoi>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/C/Src/StdLib.rux#L64){rel=""nofollow""} **Parameters** | Name | Type | Description | | ----- | -------- | ----------------------------- | | `str` | `*char8` | a null-terminated byte string | **Returns**: the value, or zero when nothing was read; there is no way to tell the two apart ## `atoll` ```rux pub extern func atoll(str: *char8) -> int64 ``` Converts a byte string to a long long integer value. Cannot report failure. Use strtoll. **See also**: <https://en.cppreference.com/c/string/byte/atoi>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/C/Src/StdLib.rux#L72){rel=""nofollow""} **Parameters** | Name | Type | Description | | ----- | -------- | ----------------------------- | | `str` | `*char8` | a null-terminated byte string | **Returns**: the value, or zero when nothing was read; there is no way to tell the two apart ## `calloc` ```rux pub extern func calloc( num: size_t, size: size_t ) -> *var opaque ``` Allocates memory for an array of num objects of size and zero-initializes it. **See also**: <https://en.cppreference.com/c/memory/calloc>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/C/Src/StdLib.rux#L80){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------ | -------- | ---------------------------------- | | `num` | `size_t` | how many objects | | `size` | `size_t` | how many bytes one object occupies | **Returns**: the address of the zeroed block, or null ## `free` ```rux pub extern func free(ptr: *var opaque) ``` Deallocates the memory previously allocated by malloc, calloc or realloc. **See also**: <https://en.cppreference.com/c/memory/free>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/C/Src/StdLib.rux#L91){rel=""nofollow""} **Parameters** | Name | Type | Description | | ----- | ------------- | ------------------- | | `ptr` | `*var opaque` | the block to act on | ## `labs` ```rux pub extern func labs(n: int64) -> int64 ``` Computes the absolute value of a long integer value. **See also**: <https://en.cppreference.com/c/numeric/math/abs>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/C/Src/StdLib.rux#L106){rel=""nofollow""} **Parameters** | Name | Type | Description | | ---- | ------- | ------------------- | | `n` | `int64` | the value to act on | **Returns**: the magnitude; the most negative value has none and the result is undefined ## `llabs` ```rux pub extern func llabs(n: int64) -> int64 ``` Computes the absolute value of a long long integer value. **See also**: <https://en.cppreference.com/c/numeric/math/abs>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/C/Src/StdLib.rux#L113){rel=""nofollow""} **Parameters** | Name | Type | Description | | ---- | ------- | ------------------- | | `n` | `int64` | the value to act on | **Returns**: the magnitude; the most negative value has none and the result is undefined ## `malloc` ```rux pub extern func malloc(size: size_t) -> *var opaque ``` Allocates size bytes of uninitialized memory. **See also**: <https://en.cppreference.com/c/memory/malloc>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/C/Src/StdLib.rux#L120){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------ | -------- | --------------- | | `size` | `size_t` | a size in bytes | **Returns**: the address of the block, or null ## `rand` ```rux pub extern func rand() -> c_int ``` Returns a pseudo-random integer value between 0 and RAND\_MAX. Nothing about the sequence is guaranteed, and it must never produce a key, a token, or anything an adversary would like to predict. Rux/Random names its generators; Rux/Entropy reaches the operating system. **See also**: <https://en.cppreference.com/c/numeric/random/rand>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/C/Src/StdLib.rux#L128){rel=""nofollow""} **Returns**: a value in `[0, RAND_MAX]`, from a sequence that guarantees nothing ## `realloc` ```rux pub extern func realloc( ptr: *var opaque, size: size_t ) -> *var opaque ``` Changes the size of the memory block pointed to by ptr to size bytes. **See also**: <https://en.cppreference.com/c/memory/realloc>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/C/Src/StdLib.rux#L136){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------ | ------------- | ------------------- | | `ptr` | `*var opaque` | the block to act on | | `size` | `size_t` | a size in bytes | **Returns**: the address of the resized block, or null with the original still valid ## `srand` ```rux pub extern func srand(seed: c_uint) ``` Seeds the pseudo-random number generator used by rand. **See also**: <https://en.cppreference.com/c/numeric/random/srand>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/C/Src/StdLib.rux#L142){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------ | -------- | ------------------------------------ | | `seed` | `c_uint` | the value to seed the generator with | ## `strtol` ```rux pub extern func strtol( str: *char8, endptr: *var *char8, base: c_int ) -> c_long ``` Converts a byte string to a long integer, reporting where it stopped. **See also**: <https://en.cppreference.com/c/string/byte/strtol>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/C/Src/StdLib.rux#L151){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | ------------- | ----------------------------------------------------------- | | `str` | `*char8` | a null-terminated byte string | | `endptr` | `*var *char8` | receives the address where parsing stopped, or null | | `base` | `c_int` | the radix, 2 through 36, or zero to read a C integer prefix | **Returns**: the value, zero when nothing was read, or a saturated limit with `errno` set to [`ERANGE`](https://rux-lang.dev/docs/api/c/errno#erange) ## `strtoul` ```rux pub extern func strtoul( str: *char8, endptr: *var *char8, base: c_int ) -> c_ulong ``` Converts a byte string to an unsigned long integer, reporting where it stopped. **See also**: <https://en.cppreference.com/c/string/byte/strtoul>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/C/Src/StdLib.rux#L160){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | ------------- | ----------------------------------------------------------- | | `str` | `*char8` | a null-terminated byte string | | `endptr` | `*var *char8` | receives the address where parsing stopped, or null | | `base` | `c_int` | the radix, 2 through 36, or zero to read a C integer prefix | **Returns**: the value, zero when nothing was read, or a saturated limit with `errno` set to [`ERANGE`](https://rux-lang.dev/docs/api/c/errno#erange) ## `strtoll` ```rux pub extern func strtoll( str: *char8, endptr: *var *char8, base: c_int ) -> c_longlong ``` Converts a byte string to a long long integer, reporting where it stopped. **See also**: <https://en.cppreference.com/c/string/byte/strtol>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/C/Src/StdLib.rux#L169){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | ------------- | ----------------------------------------------------------- | | `str` | `*char8` | a null-terminated byte string | | `endptr` | `*var *char8` | receives the address where parsing stopped, or null | | `base` | `c_int` | the radix, 2 through 36, or zero to read a C integer prefix | **Returns**: the value, zero when nothing was read, or a saturated limit with `errno` set to [`ERANGE`](https://rux-lang.dev/docs/api/c/errno#erange) ## `strtoull` ```rux pub extern func strtoull( str: *char8, endptr: *var *char8, base: c_int ) -> c_ulonglong ``` Converts a byte string to an unsigned long long integer, reporting where it stopped. **See also**: <https://en.cppreference.com/c/string/byte/strtoul>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/C/Src/StdLib.rux#L178){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | ------------- | ----------------------------------------------------------- | | `str` | `*char8` | a null-terminated byte string | | `endptr` | `*var *char8` | receives the address where parsing stopped, or null | | `base` | `c_int` | the radix, 2 through 36, or zero to read a C integer prefix | **Returns**: the value, zero when nothing was read, or a saturated limit with `errno` set to [`ERANGE`](https://rux-lang.dev/docs/api/c/errno#erange) ## `strtod` ```rux pub extern func strtod( str: *char8, endptr: *var *char8 ) -> c_double ``` Converts a byte string to a double, reporting where it stopped. **See also**: <https://en.cppreference.com/c/string/byte/strtof>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/C/Src/StdLib.rux#L186){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | ------------- | --------------------------------------------------- | | `str` | `*char8` | a null-terminated byte string | | `endptr` | `*var *char8` | receives the address where parsing stopped, or null | **Returns**: the value, zero when nothing was read, or a saturated value with `errno` set to [`ERANGE`](https://rux-lang.dev/docs/api/c/errno#erange) ## `strtof` ```rux pub extern func strtof( str: *char8, endptr: *var *char8 ) -> c_float ``` Converts a byte string to a float, reporting where it stopped. **See also**: <https://en.cppreference.com/c/string/byte/strtof>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/C/Src/StdLib.rux#L194){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | ------------- | --------------------------------------------------- | | `str` | `*char8` | a null-terminated byte string | | `endptr` | `*var *char8` | receives the address where parsing stopped, or null | **Returns**: the value, zero when nothing was read, or a saturated value with `errno` set to [`ERANGE`](https://rux-lang.dev/docs/api/c/errno#erange) ## `qsort` ```rux pub extern func qsort( base: *var opaque, num: size_t, size: size_t, compare: func(*opaque, *opaque) -> c_int ) ``` Sorts an array in place; the comparison must be a strict weak ordering and the sort is not stable. **See also**: <https://en.cppreference.com/c/algorithm/qsort>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/C/Src/StdLib.rux#L203){rel=""nofollow""} **Parameters** | Name | Type | Description | | --------- | --------------------------------- | ----------------------------------------- | | `base` | `*var opaque` | the first element of the array | | `num` | `size_t` | how many elements it holds | | `size` | `size_t` | how many bytes one element occupies | | `compare` | `func(*opaque, *opaque) -> c_int` | how two elements order against each other | ## `bsearch` ```rux pub extern func bsearch( key: *opaque, base: *opaque, num: size_t, size: size_t, compare: func(*opaque, *opaque) -> c_int ) -> *opaque ``` Finds an element of a sorted array; the array must already be ordered by the same comparison. **See also**: <https://en.cppreference.com/c/algorithm/bsearch>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/C/Src/StdLib.rux#L214){rel=""nofollow""} **Parameters** | Name | Type | Description | | --------- | --------------------------------- | ----------------------------------------- | | `key` | `*opaque` | the value to search for | | `base` | `*opaque` | the first element of the array | | `num` | `size_t` | how many elements it holds | | `size` | `size_t` | how many bytes one element occupies | | `compare` | `func(*opaque, *opaque) -> c_int` | how two elements order against each other | **Returns**: the address of a matching element, or null ## `EXIT_SUCCESS` ```rux pub const EXIT_SUCCESS: int32 = 0; ``` `EXIT_SUCCESS`: the status a program returns to mean it did what it was asked. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/C/Src/StdLib.rux#L271){rel=""nofollow""} ## `EXIT_FAILURE` ```rux pub const EXIT_FAILURE: int32 = 1; ``` `EXIT_FAILURE`: the status a program returns to mean it did not. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/C/Src/StdLib.rux#L276){rel=""nofollow""} ## `RAND_MAX` ```rux // Windows pub const RAND_MAX: int32 = 32767; // Linux · macOS · FreeBSD pub const RAND_MAX: int32 = 2147483647; ``` `RAND_MAX`: the largest value [`rand`](https://rux-lang.dev/docs/api/c/stdlib#rand) can return on this target. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/C/Src/StdLib.rux#L285){rel=""nofollow""} # Strings and memory C's `<string.h>`: byte-string and raw memory operations. ## `memchr` ```rux pub extern func memchr( ptr: *opaque, ch: c_int, count: size_t ) -> *opaque ``` Finds the first byte equal to `ch` within the first `count` bytes. `ptr` is borrowed for the call and `count` bytes of it are read. `ch` is converted to an `unsigned char` before comparison, so only its low eight bits matter. Returns a pointer into `ptr`, valid for as long as `ptr` is, or null when no byte matches. Runs in time proportional to `count` and allocates nothing. `ptr` must be readable for `count` bytes. A `count` larger than the object reads past it. **See also**: <https://en.cppreference.com/c/string/byte/memchr>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/C/Src/String.rux#L42){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------- | --------- | ----------------------------------------------------------------------------------------------------------------- | | `ptr` | `*opaque` | the block to act on | | `ch` | `c_int` | the character, as an `int` holding an `unsigned char` value or [`EOF`](https://rux-lang.dev/docs/api/c/stdio#eof) | | `count` | `size_t` | how many bytes to search | **Returns**: the address of the first matching byte, or null ## `memcmp` ```rux pub extern func memcmp( lhs: *opaque, rhs: *opaque, count: size_t ) -> c_int ``` Compares the first `count` bytes of two objects. Both are borrowed for the call. Returns a negative value when `lhs` orders first, zero when the two ranges are identical, and a positive value otherwise; the magnitude means nothing. Bytes are compared as `unsigned char`, so the result does not depend on whether plain `char` is signed. Runs in time proportional to `count` and allocates nothing. Not constant-time: it stops at the first difference, so it must not be used to compare secrets. Both pointers must be readable for `count` bytes. **See also**: <https://en.cppreference.com/c/string/byte/memcmp>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/C/Src/String.rux#L57){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------- | --------- | ------------------------- | | `lhs` | `*opaque` | the left operand | | `rhs` | `*opaque` | the right operand | | `count` | `size_t` | how many bytes to compare | **Returns**: negative, zero or positive as the first differing byte orders ## `memcpy` ```rux pub extern func memcpy( dest: *var opaque, src: *opaque, count: size_t ) -> *var opaque ``` Copies `count` bytes from `src` to `dest`. `src` is borrowed and read; `dest` is borrowed and written. Returns `dest`. The two ranges must not overlap -- that is what [`memmove`](https://rux-lang.dev/docs/api/c/string#memmove) is for, and overlapping them here is undefined rather than merely unpredictable. Runs in time proportional to `count` and allocates nothing. `dest` must be writable for `count` bytes, `src` readable for `count`, and the two must not overlap. **See also**: <https://en.cppreference.com/c/string/byte/memcpy>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/C/Src/String.rux#L70){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------- | ------------- | ------------------------- | | `dest` | `*var opaque` | where the bytes go | | `src` | `*opaque` | where the bytes come from | | `count` | `size_t` | how many bytes to copy | **Returns**: `dest` ## `memmove` ```rux pub extern func memmove( dest: *var opaque, src: *opaque, count: size_t ) -> *var opaque ``` Copies `count` bytes from `src` to `dest`, correctly even when the two overlap. `src` is borrowed and read; `dest` is borrowed and written. Returns `dest`. Behaves as though the source were copied to a temporary first, so sliding a range within one buffer works in either direction. Runs in time proportional to `count` and allocates nothing. `dest` must be writable for `count` bytes and `src` readable for `count`. **See also**: <https://en.cppreference.com/c/string/byte/memmove>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/C/Src/String.rux#L83){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------- | ------------- | ------------------------- | | `dest` | `*var opaque` | where the bytes go | | `src` | `*opaque` | where the bytes come from | | `count` | `size_t` | how many bytes to move | **Returns**: `dest` ## `memset` ```rux pub extern func memset( dest: *var opaque, ch: c_int, count: size_t ) -> *var opaque ``` Writes `ch` to each of the first `count` bytes of `dest`. `dest` is borrowed and written. `ch` is converted to an `unsigned char`, so only its low eight bits are stored. Returns `dest`. Runs in time proportional to `count` and allocates nothing. `dest` must be writable for `count` bytes. This is not the call for clearing a secret: a compiler is entitled to delete a write nothing reads back, and `Core::Zeroize` is the one that is not. **See also**: <https://en.cppreference.com/c/string/byte/memset>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/C/Src/String.rux#L97){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------- | ------------- | ----------------------------------------------------------------------------------------------------------------- | | `dest` | `*var opaque` | where the bytes go | | `ch` | `c_int` | the character, as an `int` holding an `unsigned char` value or [`EOF`](https://rux-lang.dev/docs/api/c/stdio#eof) | | `count` | `size_t` | how many bytes to write | **Returns**: `dest` ## `strlen` ```rux pub extern func strlen(str: *char8) -> size_t ``` The length of a byte string, not counting its terminator. `str` is borrowed and read up to and including its first zero byte. Returns the count of bytes before it. Runs in time proportional to the result and allocates nothing. `str` must be non-null and must contain a zero byte. Without one this reads until it faults or wraps. **See also**: <https://en.cppreference.com/c/string/byte/strlen>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/C/Src/String.rux#L107){rel=""nofollow""} **Parameters** | Name | Type | Description | | ----- | -------- | ----------------------------- | | `str` | `*char8` | a null-terminated byte string | **Returns**: how many bytes precede the terminator ## `strcmp` ```rux pub extern func strcmp(lhs: *char8, rhs: *char8) -> c_int ``` Compares two byte strings. Both are borrowed and read to their terminators. Returns a negative value when `lhs` orders first, zero when the two are equal, and a positive value otherwise. Bytes are compared as `unsigned char`. Runs in time proportional to the shorter string and allocates nothing. Not constant-time. Both must be non-null and terminated. **See also**: <https://en.cppreference.com/c/string/byte/strcmp>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/C/Src/String.rux#L119){rel=""nofollow""} **Parameters** | Name | Type | Description | | ----- | -------- | ----------------- | | `lhs` | `*char8` | the left operand | | `rhs` | `*char8` | the right operand | **Returns**: negative, zero or positive as the first differing byte orders ## `strncmp` ```rux pub extern func strncmp( lhs: *char8, rhs: *char8, count: size_t ) -> c_int ``` Compares at most `count` bytes of two byte strings. Both are borrowed. Stops at `count` bytes or at either terminator, whichever comes first. Returns the same three-way answer [`strcmp`](https://rux-lang.dev/docs/api/c/string#strcmp) does. Runs in time proportional to `count` and allocates nothing. Not constant-time. Both must be readable until a terminator or `count` bytes, whichever comes first. **See also**: <https://en.cppreference.com/c/string/byte/strncmp>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/C/Src/String.rux#L132){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------- | -------- | --------------------------------- | | `lhs` | `*char8` | the left operand | | `rhs` | `*char8` | the right operand | | `count` | `size_t` | how many bytes to compare at most | **Returns**: negative, zero or positive as the first differing byte orders ## `strcpy` ```rux pub extern func strcpy( dest: *var char8, src: *char8 ) -> *var char8 ``` Copies a byte string, terminator included. `src` is borrowed and read to its terminator; `dest` is borrowed and written. Returns `dest`. Runs in time proportional to the source length and allocates nothing. `dest` must have room for the source's length plus one, which this call has no way to check and does not. Getting that wrong is the classic buffer overrun; prefer [`memcpy`](https://rux-lang.dev/docs/api/c/string#memcpy) with a length the caller computed. **See also**: <https://en.cppreference.com/c/string/byte/strcpy>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/C/Src/String.rux#L144){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------ | ------------ | ------------------------- | | `dest` | `*var char8` | where the bytes go | | `src` | `*char8` | where the bytes come from | **Returns**: `dest` ## `strncpy` ```rux pub extern func strncpy( dest: *var char8, src: *char8, count: size_t ) -> *var char8 ``` Copies at most `count` bytes of a byte string, padding with zeros. `src` is borrowed; `dest` is borrowed and written. Returns `dest`. Writes exactly `count` bytes: shorter sources are zero-padded to fill them. Runs in time proportional to `count` and allocates nothing. `dest` must be writable for `count` bytes. This does **not** terminate the result when the source is `count` bytes or longer, which is the trap in its name: it is not a bounded [`strcpy`](https://rux-lang.dev/docs/api/c/string#strcpy). **See also**: <https://en.cppreference.com/c/string/byte/strncpy>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/C/Src/String.rux#L158){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------- | ------------ | -------------------------------------------- | | `dest` | `*var char8` | where the bytes go | | `src` | `*char8` | where the bytes come from | | `count` | `size_t` | how many bytes to write, terminator included | **Returns**: `dest`, which is not terminated when `src` filled the count ## `strcat` ```rux pub extern func strcat( dest: *var char8, src: *char8 ) -> *var char8 ``` Appends a byte string to the end of another. `src` is borrowed; `dest` is borrowed, read to its terminator, and then written from there. Returns `dest`. Runs in time proportional to the sum of the two lengths, since it finds the destination's end first. `dest` must be terminated and must have room for both lengths plus one. Repeated appending is quadratic and is a common accident: each call walks the destination from its start. **See also**: <https://en.cppreference.com/c/string/byte/strcat>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/C/Src/String.rux#L170){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------ | ------------ | ------------------------- | | `dest` | `*var char8` | where the bytes go | | `src` | `*char8` | where the bytes come from | **Returns**: `dest` ## `strncat` ```rux pub extern func strncat( dest: *var char8, src: *char8, count: size_t ) -> *var char8 ``` Appends at most `count` bytes of a byte string to the end of another. `src` is borrowed; `dest` is borrowed and written. Returns `dest`. Always terminates the result, so it writes up to `count + 1` bytes past the destination's existing end. Runs in time proportional to the destination's length plus `count`. `dest` must be terminated and must have room for its own length plus `count` plus one. `count` bounds what is taken from the source, not the size of the destination. **See also**: <https://en.cppreference.com/c/string/byte/strncat>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/C/Src/String.rux#L184){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------- | ------------ | ----------------------------------------- | | `dest` | `*var char8` | where the bytes go | | `src` | `*char8` | where the bytes come from | | `count` | `size_t` | how many bytes to take from `src` at most | **Returns**: `dest` ## `strchr` ```rux pub extern func strchr(str: *char8, ch: c_int) -> *char8 ``` Finds the first occurrence of a byte in a byte string. `str` is borrowed. `ch` is converted to a `char` before comparison, and a `ch` of zero finds the terminator rather than failing. Returns a pointer into `str`, or null when the byte does not occur. Runs in time proportional to the string's length and allocates nothing. `str` must be non-null and terminated. **See also**: <https://en.cppreference.com/c/string/byte/strchr>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/C/Src/String.rux#L196){rel=""nofollow""} **Parameters** | Name | Type | Description | | ----- | -------- | ----------------------------------------------------------------------------------------------------------------- | | `str` | `*char8` | a null-terminated byte string | | `ch` | `c_int` | the character, as an `int` holding an `unsigned char` value or [`EOF`](https://rux-lang.dev/docs/api/c/stdio#eof) | **Returns**: the address of the first matching byte, or null; the terminator counts as a byte ## `strrchr` ```rux pub extern func strrchr(str: *char8, ch: c_int) -> *char8 ``` Finds the last occurrence of a byte in a byte string. `str` is borrowed. A `ch` of zero finds the terminator. Returns a pointer into `str`, or null when the byte does not occur. Runs in time proportional to the string's length and allocates nothing. `str` must be non-null and terminated. **See also**: <https://en.cppreference.com/c/string/byte/strrchr>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/C/Src/String.rux#L208){rel=""nofollow""} **Parameters** | Name | Type | Description | | ----- | -------- | ----------------------------------------------------------------------------------------------------------------- | | `str` | `*char8` | a null-terminated byte string | | `ch` | `c_int` | the character, as an `int` holding an `unsigned char` value or [`EOF`](https://rux-lang.dev/docs/api/c/stdio#eof) | **Returns**: the address of the last matching byte, or null ## `strstr` ```rux pub extern func strstr( haystack: *char8, needle: *char8 ) -> *char8 ``` Finds the first occurrence of one byte string within another. Both are borrowed. An empty needle matches at the start. Returns a pointer into `haystack`, or null when the needle does not occur. Complexity is unspecified by the standard and is quadratic in the worst case on common implementations. Both must be non-null and terminated. **See also**: <https://en.cppreference.com/c/string/byte/strstr>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/C/Src/String.rux#L220){rel=""nofollow""} **Parameters** | Name | Type | Description | | ---------- | -------- | ------------------------- | | `haystack` | `*char8` | the string to search | | `needle` | `*char8` | the substring to look for | **Returns**: the address where `needle` starts in `haystack`, or null ## `strspn` ```rux pub extern func strspn( str: *char8, accept: *char8 ) -> size_t ``` The length of the leading run of bytes drawn only from `accept`. Both are borrowed. Returns the index of the first byte of `str` not present in `accept`, which is the string's length when every byte is. Runs in time proportional to the product of the two lengths on a naive implementation. Both must be non-null and terminated. **See also**: <https://en.cppreference.com/c/string/byte/strspn>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/C/Src/String.rux#L232){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | -------- | ----------------------------- | | `str` | `*char8` | a null-terminated byte string | | `accept` | `*char8` | the set of bytes to accept | **Returns**: how many leading bytes are all in `accept` ## `strcspn` ```rux pub extern func strcspn( str: *char8, reject: *char8 ) -> size_t ``` The length of the leading run of bytes drawn from none of `reject`. Both are borrowed. Returns the index of the first byte of `str` present in `reject`, which is the string's length when none is. Both must be non-null and terminated. **See also**: <https://en.cppreference.com/c/string/byte/strcspn>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/C/Src/String.rux#L243){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | -------- | ----------------------------- | | `str` | `*char8` | a null-terminated byte string | | `reject` | `*char8` | the set of bytes to reject | **Returns**: how many leading bytes are none of `reject` ## `strpbrk` ```rux pub extern func strpbrk( str: *char8, accept: *char8 ) -> *char8 ``` Finds the first byte of `str` that occurs in `accept`. Both are borrowed. Returns a pointer into `str`, or null when no byte of it occurs in `accept`. Both must be non-null and terminated. **See also**: <https://en.cppreference.com/c/string/byte/strpbrk>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/C/Src/String.rux#L253){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | -------- | ----------------------------- | | `str` | `*char8` | a null-terminated byte string | | `accept` | `*char8` | the set of bytes to accept | **Returns**: the address of the first byte that is in `accept`, or null ## `strtok` ```rux pub extern func strtok( str: *var char8, delimiters: *char8 ) -> *char8 ``` Splits a byte string into tokens separated by any byte of `delimiters`. `str` is borrowed and **modified**: a terminator is written over each delimiter found. Pass the string on the first call and null on each call after it to continue the same scan. Returns the next token, or null when none is left. The scan's position is kept in storage shared by the whole program, so two interleaved scans destroy each other and no two threads may use this at once. The string must be writable, which rules out a literal. **See also**: <https://en.cppreference.com/c/string/byte/strtok>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/C/Src/String.rux#L300){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------------ | ------------ | ------------------------------------- | | `str` | `*var char8` | a null-terminated byte string | | `delimiters` | `*char8` | the set of bytes that separate tokens | **Returns**: the next token, or null; the position is kept in storage shared by the whole program # Time C's `<time.h>`: calendar time, processor time and the conversions between them. ## `time_t` ```rux pub type time_t = int64 ``` C's `time_t`: a calendar time as an arithmetic value. What the value counts is implementation-defined by the standard, and is seconds since the Unix epoch on every supported target. `Rux/Time`'s `Timestamp` is the one that says so as a contract. **See also**: <https://en.cppreference.com/c/chrono/time_t>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/C/Src/Time.rux#L18){rel=""nofollow""} ## `clock_t` ```rux // Windows pub type clock_t = int32 // Linux · FreeBSD pub type clock_t = int64 // macOS pub type clock_t = uint64 ``` C's `clock_t`: processor time as an arithmetic value. `long` on every supported target, and `long` is not one width: the Universal CRT makes it 32 bits while every supported Unix makes it 64, and Darwin spells the same type unsigned. Declaring it as a fixed 64-bit integer, as this once did, reads four bytes of whatever followed the result on Windows. Spelled as the primitive rather than as [`c_long`](https://rux-lang.dev/docs/api/c/types#c-long), because a type alias cannot name one declared in another file of this package. The width is the same thing said twice. FreeBSD's definition is the one value here not confirmed against a running system; the eight-target fixture gate is what checks it. **See also**: <https://en.cppreference.com/c/chrono/clock_t>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/C/Src/Time.rux#L39){rel=""nofollow""} ## `clock` ```rux pub extern func clock() -> clock_t ``` Returns the approximate processor time used by the program. **See also**: <https://en.cppreference.com/c/chrono/clock>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/C/Src/Time.rux#L198){rel=""nofollow""} **Returns**: the processor time used, or -1 when it is not available ## `difftime` ```rux pub extern func difftime( time_end: time_t, time_beg: time_t ) -> float64 ``` Computes the difference in seconds between two calendar times. **See also**: <https://en.cppreference.com/c/chrono/difftime>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/C/Src/Time.rux#L212){rel=""nofollow""} **Parameters** | Name | Type | Description | | ---------- | -------- | ------------------------- | | `time_end` | `time_t` | the later clock reading | | `time_beg` | `time_t` | the earlier clock reading | **Returns**: the seconds between the two readings ## `gmtime` ```rux pub extern func gmtime(timer: *time_t) -> *tm ``` Converts a time\_t object to calendar time expressed as UTC. **See also**: <https://en.cppreference.com/c/chrono/gmtime>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/C/Src/Time.rux#L219){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------- | --------- | ----------------------- | | `timer` | `*time_t` | the time value, or null | **Returns**: a pointer to storage the C runtime owns and the next call may reuse, or null ## `localtime` ```rux pub extern func localtime(timer: *time_t) -> *tm ``` Converts a time\_t object to calendar time expressed as local time. **See also**: <https://en.cppreference.com/c/chrono/localtime>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/C/Src/Time.rux#L226){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------- | --------- | ----------------------- | | `timer` | `*time_t` | the time value, or null | **Returns**: a pointer to storage the C runtime owns and the next call may reuse, or null ## `mktime` ```rux pub extern func mktime(time_ptr: *tm) -> time_t ``` Converts calendar time to a time\_t object, normalizing the tm structure. **See also**: <https://en.cppreference.com/c/chrono/mktime>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/C/Src/Time.rux#L233){rel=""nofollow""} **Parameters** | Name | Type | Description | | ---------- | ----- | ------------------------- | | `time_ptr` | `*tm` | the time value to convert | **Returns**: the time value, or -1 when the components cannot be represented ## `time` ```rux pub extern func time(timer: *time_t) -> time_t ``` Returns the current calendar time since the epoch. **See also**: <https://en.cppreference.com/c/chrono/time>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/C/Src/Time.rux#L249){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------- | --------- | ----------------------- | | `timer` | `*time_t` | the time value, or null | **Returns**: the current time, or -1 when it is not available ## `TIME_UTC` ```rux pub const TIME_UTC: int32 = 1; ``` `TIME_UTC`: the time base naming seconds since the epoch, the only one C defines. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/C/Src/Time.rux#L288){rel=""nofollow""} ## `CLOCKS_PER_SEC` ```rux // Windows pub const CLOCKS_PER_SEC: int64 = 1000; // Linux · macOS · FreeBSD pub const CLOCKS_PER_SEC: int64 = 1000000; ``` `CLOCKS_PER_SEC`: how many [`clock`](https://rux-lang.dev/docs/api/c/time#clock) ticks make one second on this target. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/C/Src/Time.rux#L297){rel=""nofollow""} ## `TimespecGet` ```rux pub func TimespecGet( ts: &var timespec, base: c_int ) -> c_int ``` Fills `ts` with the current time on the given base. `ts` is borrowed and written, so callers pass the value directly. `base` is read by value and [`TIME_UTC`](https://rux-lang.dev/docs/api/c/time#time-utc) is the only base C defines. Returns `base` on success and zero on failure, which is the one way this reports one. Runs in constant time and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/C/Src/Time.rux#L315){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------ | --------------- | -------------------------------------------------------------------------------------------------------------- | | `ts` | `&var timespec` | receives the reading | | `base` | `c_int` | which time base to read; [`TIME_UTC`](https://rux-lang.dev/docs/api/c/time#time-utc) is the only one C defines | **Returns**: `base` on success, or zero on failure # errno Reading C's thread-local `errno`, and which C runtime it lives in. ## `CRuntime` ```rux // Windows pub const CRuntime = "ucrtbase.dll"; // Linux pub const CRuntime = "libc.so.6"; // macOS pub const CRuntime = "libSystem.B.dylib"; // FreeBSD pub const CRuntime = "libc.so.7"; ``` The shared object this target's C runtime lives in. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/C/Src/Types.rux#L210){rel=""nofollow""} ## `StreamRuntime` ```rux // Windows pub const StreamRuntime = "msvcrt.dll"; // Linux pub const StreamRuntime = "libc.so.6"; // macOS pub const StreamRuntime = "libSystem.B.dylib"; // FreeBSD pub const StreamRuntime = "libc.so.7"; ``` The shared object `C::StdIo` and `C::Time` are bound to, which on Windows is a different one. The Universal CRT does not export the formatted-output family, so those two modules bind the legacy runtime. It keeps its own `errno`, its own stream table and its own locale, so a failure reported by a call through either module is readable only through `ErrnoFor(CRuntimeArea::Streams)`. | Overload | Summary | | ------------------------------------------------ | ---------------------------------------------------------------------------------------------- | | `pub const StreamRuntime = "msvcrt.dll";` | The shared object `C::StdIo` and `C::Time` are bound to, which on Windows is a different one. | | `pub const StreamRuntime = "libc.so.6";` | The shared object `C::StdIo` and `C::Time` are bound to, which on this target is the same one. | | `pub const StreamRuntime = "libSystem.B.dylib";` | The shared object `C::StdIo` and `C::Time` are bound to, which on this target is the same one. | | `pub const StreamRuntime = "libc.so.7";` | The shared object `C::StdIo` and `C::Time` are bound to, which on this target is the same one. | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/C/Src/Types.rux#L217){rel=""nofollow""} ## `CRuntimeArea` ```rux pub enum CRuntimeArea: uint8 { General = 0, Streams = 1 } ``` Which of the package's C runtimes a call belongs to. On Windows this package spans two: `StdLib` and `Math` bind the Universal CRT, while `StdIo` and `Time` bind the legacy runtime, because the Universal CRT does not export the formatted-output family. The two keep separate `errno` storage, so reading one after a call into the other reports a value belonging to something else entirely. Everywhere else there is one runtime and both cases name it, so a caller that always passes the area matching the module it called is right on all four systems and needs no target branch of its own. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/C/Src/Types.rux#L283){rel=""nofollow""} **Cases** | Name | Value | Description | | --------- | ----- | ----------------------------------------------------------------------------------------------------------------------- | | `General` | `0` | Where `C::StdLib` and `C::Math` are bound, and what plain [`Errno`](https://rux-lang.dev/docs/api/c/errno#errno) reads. | | `Streams` | `1` | Where `C::StdIo` and `C::Time` are bound. The same runtime as `General` except on Windows. | ## `SeparateStreamRuntime` ```rux pub const SeparateStreamRuntime: bool = #target.os == OperatingSystem::Windows; ``` Whether the two areas are really two runtimes on this target. True on Windows and false everywhere else. A caller that passes the right area never needs to read this; it is here so that a program can say why it is being careful, and so that a test can assert the split exists where it is supposed to and does not where it is not. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/C/Src/Types.rux#L295){rel=""nofollow""} ## `ErrnoLocationFor` ```rux pub func ErrnoLocationFor(area: CRuntimeArea) -> *var c_int ``` The address of the calling thread's `errno`, in the runtime `area` names. Returns a pointer that runtime owns, valid for as long as the calling thread runs. Writing through it is how C's `errno = 0` is spelled, which a caller does before a call whose failure is only reported through `errno`. Pass the area matching the module whose call is being checked: `Streams` after anything from `C::StdIo` or `C::Time`, `General` after anything from `C::StdLib` or `C::Math`. Passing the wrong one is not a compile error and not a crash; it reads a different thread-local integer, which is the whole hazard this exists to remove. Cannot fail. Runs in constant time and allocates nothing. The address belongs to the calling thread and must not be handed to another one. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/C/Src/Types.rux#L308){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------ | -------------- | -------------------------------- | | `area` | `CRuntimeArea` | which runtime's storage to reach | **Returns**: the address of that runtime's `errno` for this thread ## `ErrnoFor` ```rux pub func ErrnoFor(area: CRuntimeArea) -> c_int ``` The calling thread's current `errno` value, in the runtime `area` names. Meaningful only after a call that documents setting it: no C function clears `errno` on success, so a value left over from an earlier failure is still there. Clear it through [`ErrnoLocationFor`](https://rux-lang.dev/docs/api/c/errno#errno-location-for) before the call whose failure is to be read. Cannot fail. Runs in constant time and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/C/Src/Types.rux#L325){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------ | -------------- | ------------------------------- | | `area` | `CRuntimeArea` | which runtime's storage to read | **Returns**: that runtime's `errno` for this thread ## `ErrnoLocation` ```rux pub func ErrnoLocation() -> *var c_int ``` The address of the calling thread's `errno`, in the runtime `C::StdLib` and `C::Math` are bound to. Exactly `ErrnoLocationFor(CRuntimeArea::General)`, and the spelling to use when the call being checked came from one of those two modules. After a call from `C::StdIo` or `C::Time` on Windows this reads the wrong runtime's storage, which is what [`ErrnoLocationFor`](https://rux-lang.dev/docs/api/c/errno#errno-location-for) exists to let a caller avoid. Writing through it is how C's `errno = 0` is spelled, which a caller does before a call whose failure is only reported through `errno`. Cannot fail. Runs in constant time and allocates nothing. The address belongs to the calling thread and must not be handed to another one. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/C/Src/Types.rux#L339){rel=""nofollow""} **Returns**: the address of the general runtime's `errno` for this thread ## `Errno` ```rux pub func Errno() -> c_int ``` The calling thread's current `errno` value. Takes nothing and returns the value by copy. Meaningful only after a call that documents setting it: no C function clears `errno` on success, so a value left over from an earlier failure is still there. Clear it with `*ErrnoLocation() = 0` before the call whose failure is to be read. On Windows this reads the Universal CRT's `errno`, which is the one `C::StdLib` and `C::Math` set. `C::StdIo` and `C::Time` are still bound to the legacy `msvcrt.dll`, whose `errno` is a different variable in a different runtime, so a failure reported by a call in either of those modules is not visible here. That split is a known defect: the Universal CRT does not export the formatted-output family, so moving those modules across needs the `__stdio_common_*` entry points declared first. Cannot fail. Runs in constant time and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/C/Src/Types.rux#L355){rel=""nofollow""} **Returns**: the general runtime's `errno` for this thread ## `EDOM` ```rux pub const EDOM: c_int = 33; ``` `EDOM`: an argument outside the domain over which a math function is defined. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/C/Src/Types.rux#L361){rel=""nofollow""} ## `ERANGE` ```rux pub const ERANGE: c_int = 34; ``` `ERANGE`: a result too large or too small for the return type to express. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/C/Src/Types.rux#L365){rel=""nofollow""} ## `EILSEQ` ```rux // Windows pub const EILSEQ: c_int = 42; // Linux pub const EILSEQ: c_int = 84; // macOS pub const EILSEQ: c_int = 92; // FreeBSD pub const EILSEQ: c_int = 86; ``` `EILSEQ`: a byte sequence that does not form a valid character. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/C/Src/Types.rux#L388){rel=""nofollow""} # Standard I/O C's `<stdio.h>`: streams, formatted conversion and the constants that size them. ## `fclose` ```rux pub extern func fclose(stream: *FILE) -> c_int ``` Closes the given file stream. **See also**: <https://en.cppreference.com/c/io/fclose>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/C/Src/StdIo.rux#L49){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | ------- | -------------------- | | `stream` | `*FILE` | the stream to act on | **Returns**: zero, or [`EOF`](https://rux-lang.dev/docs/api/c/stdio#eof) on failure ## `fgetc` ```rux pub extern func fgetc(stream: *FILE) -> c_int ``` Reads the next character from the given stream. **See also**: <https://en.cppreference.com/c/io/fgetc>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/C/Src/StdIo.rux#L74){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | ------- | -------------------- | | `stream` | `*FILE` | the stream to act on | **Returns**: the byte as an `unsigned char`, or [`EOF`](https://rux-lang.dev/docs/api/c/stdio#eof) at the end or on error ## `fopen` ```rux pub extern func fopen( filename: *char8, mode: *char8 ) -> *FILE ``` Opens a file indicated by filename with the given mode. **See also**: <https://en.cppreference.com/c/io/fopen>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/C/Src/StdIo.rux#L97){rel=""nofollow""} **Parameters** | Name | Type | Description | | ---------- | -------- | ------------------------------------------ | | `filename` | `*char8` | the path, as a null-terminated byte string | | `mode` | `*char8` | the open mode, such as `"rb"` | **Returns**: the stream, or null with the reason in `errno` ## `fseek` ```rux pub extern func fseek( stream: *FILE, offset: int64, origin: c_int ) -> c_int ``` Sets the file position indicator for the stream. **See also**: <https://en.cppreference.com/c/io/fseek>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/C/Src/StdIo.rux#L151){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | ------- | ------------------------------- | | `stream` | `*FILE` | the stream to act on | | `offset` | `int64` | how far to move | | `origin` | `c_int` | where the move is measured from | **Returns**: zero, or non-zero on failure ## `ftell` ```rux pub extern func ftell(stream: *FILE) -> int64 ``` Returns the current file position of the stream. **See also**: <https://en.cppreference.com/c/io/ftell>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/C/Src/StdIo.rux#L165){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | ------- | -------------------- | | `stream` | `*FILE` | the stream to act on | **Returns**: the current position, or -1 with the reason in `errno` ## `fwrite` ```rux pub extern func fwrite( buffer: *opaque, size: size_t, count: size_t, stream: *FILE ) -> size_t ``` Writes count objects of the given size from a buffer to the stream. **See also**: <https://en.cppreference.com/c/io/fwrite>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/C/Src/StdIo.rux#L175){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | --------- | ----------------------------------- | | `buffer` | `*opaque` | the bytes to write | | `size` | `size_t` | how many bytes one element occupies | | `count` | `size_t` | how many elements to write | | `stream` | `*FILE` | the stream to act on | **Returns**: how many whole elements were written, which is short only on error ## `putchar` ```rux pub extern func putchar(ch: c_int) -> c_int ``` Writes a character to stdout. **See also**: <https://en.cppreference.com/c/io/putchar>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/C/Src/StdIo.rux#L211){rel=""nofollow""} **Parameters** | Name | Type | Description | | ---- | ------- | ----------------------------------------------------------------------------------------------------------------- | | `ch` | `c_int` | the character, as an `int` holding an `unsigned char` value or [`EOF`](https://rux-lang.dev/docs/api/c/stdio#eof) | **Returns**: the byte written, or [`EOF`](https://rux-lang.dev/docs/api/c/stdio#eof) on failure ## `puts` ```rux pub extern func puts(str: *char8) -> c_int ``` Writes a string followed by a newline to stdout. **See also**: <https://en.cppreference.com/c/io/puts>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/C/Src/StdIo.rux#L218){rel=""nofollow""} **Parameters** | Name | Type | Description | | ----- | -------- | ----------------------------- | | `str` | `*char8` | a null-terminated byte string | **Returns**: a non-negative value, or [`EOF`](https://rux-lang.dev/docs/api/c/stdio#eof) on failure ## `remove` ```rux pub extern func remove(pathname: *char8) -> c_int ``` Deletes the file identified by the given path. **See also**: <https://en.cppreference.com/c/io/remove>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/C/Src/StdIo.rux#L225){rel=""nofollow""} **Parameters** | Name | Type | Description | | ---------- | -------- | ------------------------------------------ | | `pathname` | `*char8` | the path, as a null-terminated byte string | **Returns**: zero, or non-zero on failure ## `sprintf` ```rux pub extern func sprintf( buffer: *char8, format: *char8, ... ) -> c_int ``` Prints formatted output to a string. Never told the size of the buffer, so a longer result than it holds is an overrun. Rux/Format writes into a destination that knows its own length. **See also**: <https://en.cppreference.com/c/io/sprintf>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/C/Src/StdIo.rux#L270){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | -------- | ----------------- | | `buffer` | `*char8` | the bytes | | `format` | `*char8` | the format string | | `...` | | | **Returns**: how many bytes were written, not counting the terminator, or a negative value on failure ## `sscanf` ```rux pub extern func sscanf( buffer: *char8, format: *char8, ... ) -> c_int ``` Reads formatted input from a string. A '%s' conversion is never told the size of what it writes into, so a longer field than it holds is an overrun; give every string conversion an explicit width. **See also**: <https://en.cppreference.com/c/io/sscanf>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/C/Src/StdIo.rux#L280){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | -------- | ----------------- | | `buffer` | `*char8` | the bytes | | `format` | `*char8` | the format string | | `...` | | | **Returns**: how many items were assigned, which may be fewer than asked for, or [`EOF`](https://rux-lang.dev/docs/api/c/stdio#eof) before any were ## `EOF` ```rux pub const EOF: int32 = -1; ``` `EOF`: what a character-reading call returns instead of a character when the stream has ended or failed. Negative, and distinct from every `unsigned char` value, which is why those calls return a [`c_int`](https://rux-lang.dev/docs/api/c/types#c-int) rather than a character type. It does not say which of the two happened: `feof` and `ferror` do. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/C/Src/StdIo.rux#L311){rel=""nofollow""} ## `SEEK_SET` ```rux pub const SEEK_SET: int32 = 0; ``` `SEEK_SET`: measure the new stream position from the beginning. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/C/Src/StdIo.rux#L316){rel=""nofollow""} ## `SEEK_CUR` ```rux pub const SEEK_CUR: int32 = 1; ``` `SEEK_CUR`: measure the new stream position from the current one. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/C/Src/StdIo.rux#L321){rel=""nofollow""} ## `SEEK_END` ```rux pub const SEEK_END: int32 = 2; ``` `SEEK_END`: measure the new stream position from the end. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/C/Src/StdIo.rux#L326){rel=""nofollow""} ## `_IOFBF` ```rux pub const _IOFBF: int32 = 0; ``` `_IOFBF`: buffer fully, flushing when the buffer fills. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/C/Src/StdIo.rux#L335){rel=""nofollow""} ## `_IOLBF` ```rux // Windows pub const _IOLBF: int32 = 64; // Linux · macOS · FreeBSD pub const _IOLBF: int32 = 1; ``` `_IOLBF`: buffer by line. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/C/Src/StdIo.rux#L340){rel=""nofollow""} ## `_IONBF` ```rux // Windows pub const _IONBF: int32 = 4; // Linux · macOS · FreeBSD pub const _IONBF: int32 = 2; ``` `_IONBF`: do not buffer. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/C/Src/StdIo.rux#L345){rel=""nofollow""} ## `BUFSIZ` ```rux // Windows pub const BUFSIZ: int32 = 512; // Linux pub const BUFSIZ: int32 = 8192; // macOS · FreeBSD pub const BUFSIZ: int32 = 1024; ``` `BUFSIZ`: the buffer size `setbuf` uses. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/C/Src/StdIo.rux#L350){rel=""nofollow""} ## `FOPEN_MAX` ```rux // Windows · macOS · FreeBSD pub const FOPEN_MAX: int32 = 20; // Linux pub const FOPEN_MAX: int32 = 16; ``` `FOPEN_MAX`: how many streams the implementation guarantees can be open at once. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/C/Src/StdIo.rux#L355){rel=""nofollow""} ## `FILENAME_MAX` ```rux // Windows pub const FILENAME_MAX: int32 = 260; // Linux pub const FILENAME_MAX: int32 = 4096; // macOS · FreeBSD pub const FILENAME_MAX: int32 = 1024; ``` `FILENAME_MAX`: the length of the longest file name the implementation guarantees it can open. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/C/Src/StdIo.rux#L360){rel=""nofollow""} ## `L_tmpnam` ```rux // Windows pub const L_tmpnam: int32 = 260; // Linux pub const L_tmpnam: int32 = 20; // macOS · FreeBSD pub const L_tmpnam: int32 = 1024; ``` `L_tmpnam`: the buffer size `tmpnam` needs. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/C/Src/StdIo.rux#L365){rel=""nofollow""} ## `TMP_MAX` ```rux // Windows pub const TMP_MAX: int32 = 32767; // Linux pub const TMP_MAX: int32 = 238328; // macOS · FreeBSD pub const TMP_MAX: int32 = 308915776; ``` `TMP_MAX`: how many distinct names `tmpnam` guarantees before it repeats. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/C/Src/StdIo.rux#L370){rel=""nofollow""} ## `FILE` ```rux pub struct FILE {} ``` C's `FILE`: a stream, whose contents belong to the C runtime. Declared with no fields on purpose. Its layout differs by platform and by runtime version, and no binding may read it; a stream is only ever handled through `*FILE` and the calls that take one. Naming the type rather than using `*opaque` is what keeps a stream from being passed where some other handle was meant. A `*FILE` is valid only between the call that produced it and the [`fclose`](https://rux-lang.dev/docs/api/c/stdio#fclose) that ends it. Nothing here tracks that. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/C/Src/Types.rux#L151){rel=""nofollow""} ## `fpos_t` ```rux pub struct fpos_t {} ``` C's `fpos_t`: an opaque record of a position within a stream. Declared with no fields for the same reason [`FILE`](https://rux-lang.dev/docs/api/c/stdio#file) is: its contents belong to the C runtime, and it is only ever produced by `fgetpos` and consumed by `fsetpos`. It is not a byte offset and must not be arithmetic on. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/C/Src/Types.rux#L158){rel=""nofollow""} # Linux Linux platform bindings. ## Installation Add `Linux` to the `[Dependencies]` table of your package's `Rux.toml`: ```toml [Dependencies] Linux = { Namespace = "Rux", Version = "0.1.0" } ``` Standard packages are declared by hand: the registry does not serve them, so `rux add Rux/Linux` cannot add them. ## Dependencies - [`Core`](https://rux-lang.dev/docs/api/core) 0.1.0 ## Guide Linux platform bindings: the raw syscall interface, with no libc in between. ### What it provides | Module | Covers | | ------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `Types` | the kernel ABI's own types: [`ProcessId`](https://rux-lang.dev/docs/api/linux/types#process-id), [`FileDescriptor`](https://rux-lang.dev/docs/api/linux/types#file-descriptor), [`FileOffset`](https://rux-lang.dev/docs/api/linux/types#file-offset), [`FileMode`](https://rux-lang.dev/docs/api/linux/types#file-mode), [`UserId`](https://rux-lang.dev/docs/api/linux/types#user-id), [`Timespec`](https://rux-lang.dev/docs/api/linux/timespec) | | `Errors` | the errno numbers, and [`IsError`](https://rux-lang.dev/docs/api/linux/errors#is-error) / [`Errno`](https://rux-lang.dev/docs/api/linux/errors#errno) for reading a raw result | | `Syscall` | [`Syscall0`](https://rux-lang.dev/docs/api/linux/syscalls#syscall-0) through [`Syscall6`](https://rux-lang.dev/docs/api/linux/syscalls#syscall-6) as inline assembly, the call numbers, and [`SignExtendFd`](https://rux-lang.dev/docs/api/linux/syscalls#sign-extend-fd) | | `File` | [`Read`](https://rux-lang.dev/docs/api/linux/files#read), [`Write`](https://rux-lang.dev/docs/api/linux/files#write), [`Close`](https://rux-lang.dev/docs/api/linux/files#close), [`OpenAt`](https://rux-lang.dev/docs/api/linux/files#open-at), [`Lseek`](https://rux-lang.dev/docs/api/linux/files#lseek), [`Fsync`](https://rux-lang.dev/docs/api/linux/files#fsync), [`Ftruncate`](https://rux-lang.dev/docs/api/linux/files#ftruncate), [`UnlinkAt`](https://rux-lang.dev/docs/api/linux/directories#unlink-at), [`MkdirAt`](https://rux-lang.dev/docs/api/linux/directories#mkdir-at), [`RenameAt`](https://rux-lang.dev/docs/api/linux/directories#rename-at), [`Fstat`](https://rux-lang.dev/docs/api/linux/files#fstat), [`FstatAt`](https://rux-lang.dev/docs/api/linux/files#fstat-at), [`Dup3`](https://rux-lang.dev/docs/api/linux/files#dup3), [`Pipe2`](https://rux-lang.dev/docs/api/linux/files#pipe2), the open flags, and the three standard descriptors | | `Memory` | [`Mmap`](https://rux-lang.dev/docs/api/linux/memory#mmap), [`Munmap`](https://rux-lang.dev/docs/api/linux/memory#munmap), [`Brk`](https://rux-lang.dev/docs/api/linux/memory#brk), [`Mprotect`](https://rux-lang.dev/docs/api/linux/memory#mprotect), [`Madvise`](https://rux-lang.dev/docs/api/linux/memory#madvise), [`QueryPageSize`](https://rux-lang.dev/docs/api/linux/memory#query-page-size), and the protection, mapping and advice flags | | `Clock` | [`ClockGetTime`](https://rux-lang.dev/docs/api/linux/clock#clock-get-time), [`ClockGetResolution`](https://rux-lang.dev/docs/api/linux/clock#clock-get-resolution), [`Nanosleep`](https://rux-lang.dev/docs/api/linux/clock#nanosleep), [`ClockNanosleep`](https://rux-lang.dev/docs/api/linux/clock#clock-nanosleep), and the clock identifiers | | `Process` | [`Exit`](https://rux-lang.dev/docs/api/linux/process#exit) and [`GetPid`](https://rux-lang.dev/docs/api/linux/process#get-pid) | | `Entropy` | [`GetRandom`](https://rux-lang.dev/docs/api/linux/get-random), the only source here fit for a key or a token | | `Dynamic` | [`dlopen`](https://rux-lang.dev/docs/api/linux/dynamic#dlopen), [`dlsym`](https://rux-lang.dev/docs/api/linux/dynamic#dlsym), [`dlclose`](https://rux-lang.dev/docs/api/linux/dynamic#dlclose), [`dlerror`](https://rux-lang.dev/docs/api/linux/dynamic#dlerror), and the `RTLD_*` flags | | `Thread` | [`pthread_create`](https://rux-lang.dev/docs/api/linux/thread#pthread-create), [`pthread_join`](https://rux-lang.dev/docs/api/linux/thread#pthread-join), [`pthread_detach`](https://rux-lang.dev/docs/api/linux/thread#pthread-detach), the `pthread_attr_*` stack-size calls, [`sched_yield`](https://rux-lang.dev/docs/api/linux/thread#sched-yield), [`sysconf`](https://rux-lang.dev/docs/api/linux/thread#sysconf) and [`SC_NPROCESSORS_ONLN`](https://rux-lang.dev/docs/api/linux/thread#sc-nprocessors-onln), and [`gettid`](https://rux-lang.dev/docs/api/linux/thread#gettid), linked from libc | | [`Socket`](https://rux-lang.dev/docs/api/linux/socket#socket) | [`Socket`](https://rux-lang.dev/docs/api/linux/socket#socket), [`Connect`](https://rux-lang.dev/docs/api/linux/socket#connect), [`Bind`](https://rux-lang.dev/docs/api/linux/socket#bind), [`Listen`](https://rux-lang.dev/docs/api/linux/socket#listen), [`Accept4`](https://rux-lang.dev/docs/api/linux/socket#accept4), [`SendTo`](https://rux-lang.dev/docs/api/linux/socket#sendto), [`ReceiveFrom`](https://rux-lang.dev/docs/api/linux/socket#receivefrom), [`Shutdown`](https://rux-lang.dev/docs/api/linux/socket#shutdown), [`SetSocketOption`](https://rux-lang.dev/docs/api/linux/socket#setsocketoption), [`GetSocketName`](https://rux-lang.dev/docs/api/linux/socket#getsocketname) and [`GetPeerName`](https://rux-lang.dev/docs/api/linux/socket#getpeername) as system calls, with the address families, socket options and [`MSG_NOSIGNAL`](https://rux-lang.dev/docs/api/linux/socket#msg-nosignal) | | `Resolve` | [`getaddrinfo`](https://rux-lang.dev/docs/api/linux/resolve#getaddrinfo), [`freeaddrinfo`](https://rux-lang.dev/docs/api/linux/resolve#freeaddrinfo) and [`AddressInfo`](https://rux-lang.dev/docs/api/linux/resolve#address-info), linked from libc | | `Futex` | [`FutexWait`](https://rux-lang.dev/docs/api/linux/futex#futex-wait) and [`FutexWake`](https://rux-lang.dev/docs/api/linux/futex#futex-wake), the private `futex(2)` operations every lock in `Rux/Sync` sleeps on | | `Spawn` | [`posix_spawnp`](https://rux-lang.dev/docs/api/linux/spawn#posix-spawnp), the `posix_spawn_file_actions_*` calls, [`waitpid`](https://rux-lang.dev/docs/api/linux/spawn#waitpid), [`kill`](https://rux-lang.dev/docs/api/linux/spawn#kill), [`fcntl`](https://rux-lang.dev/docs/api/linux/spawn#fcntl) and [`__errno_location`](https://rux-lang.dev/docs/api/linux/spawn#errno), linked from libc | | `Poll` | [`EpollCreate1`](https://rux-lang.dev/docs/api/linux/poll#epoll-create1), [`EpollControl`](https://rux-lang.dev/docs/api/linux/poll#epoll-control) and [`EpollWait`](https://rux-lang.dev/docs/api/linux/poll#epoll-wait) as system calls, the `EPOLL*` flags, the per-architecture `epoll_event` layout, and [`FcntlInt`](https://rux-lang.dev/docs/api/linux/poll#fcntl-int) with [`F_GETFL`](https://rux-lang.dev/docs/api/linux/poll#f-getfl), [`F_SETFL`](https://rux-lang.dev/docs/api/linux/poll#f-setfl) and [`O_NONBLOCK`](https://rux-lang.dev/docs/api/linux/poll#o-nonblock) | The module names describe where each declaration comes from; they are not part of an import path. There is no `errno` here. The kernel returns the error in the result register as a small negative number, and libc is what turns that into a positive `errno` and a `-1` return. This package calls the kernel directly, so a caller tests a raw result with [`IsError`](https://rux-lang.dev/docs/api/linux/errors#is-error) and reads the number with [`Errno`](https://rux-lang.dev/docs/api/linux/errors#errno). Only `-4095` through `-1` is an error, which is what makes [`Mmap`](https://rux-lang.dev/docs/api/linux/memory#mmap) workable: a mapping address may legitimately have its top bit set. Only calls both architectures have are wrapped. AArch64 came after the directory-relative interface and never got `open`, `stat`, `unlink`, `mkdir`, `rename`, `dup2` or `pipe`, so this package offers the `*at` forms alone and [`AtFdCwd`](https://rux-lang.dev/docs/api/linux/files#at-fd-cwd) is what makes an ordinary path work through them. One wrapper is then right on both. The errno numbers and the `RTLD_*` flags keep the kernel's own spelling, because [`EINVAL`](https://rux-lang.dev/docs/api/linux/errors#einval) is what a man page names and what a reader porting code will look for. The rest of the constants use Rux names, which is what they were published under. [`QueryPageSize`](https://rux-lang.dev/docs/api/linux/memory#query-page-size) is the one wrapper here that is not a system call. Linux publishes the page size in the auxiliary vector the kernel hands to a new process, which libc captures at startup and answers from; this package captures nothing at startup, so it reads the same vector through `/proc/self/auxv`. That costs an open, a read and a close, and it reports the open's own error number when `/proc` is not there — which is ordinary in a container and is why the call is fallible rather than answering 4096 and hoping. ### The shared POSIX contract Nothing here is interchangeable with the other POSIX packages, but the three are *spelled* the same, which is a different claim and a deliberate one. An equivalent call has the same wrapper name, the same parameter names and the same parameter shapes on all three systems, so a consumer such as [`Rux/FileSystem`](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/../FileSystem){rel=""nofollow""} or [`Rux/Time`](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/../Time){rel=""nofollow""} writes one call site instead of a `when #target.os` ladder around three names for one idea. `Tests/Unit/PlatformBindingContractTests.cpp` compares the three packages' parsed sources and fails when they drift apart. The values are the opposite: every constant is this system's own, and the same file asserts that the ones a reader might carry across really do differ. ### What is tested `Tests/Packages/Linux/Descriptors` covers descriptor numbering, short reads and writes, end of file, size boundaries and the native error for each way of misusing a descriptor or a name. `Tests/Packages/Linux/Mapping` covers anonymous mappings, protection changes, advice, the requests the kernel refuses, and both edges of the reserved error-result window. `Tests/Packages/Linux/Syscall` covers the wrapper surface and the shared POSIX contract. All of it compiles for both architectures, and none of it has ever run on a host that is not Linux. Until it does, the syscall numbers, flag values and errno constants here rest on published documentation rather than on a passing test. ### Values and pointers Kernel records such as [`Timespec`](https://rux-lang.dev/docs/api/linux/timespec) are structural values and copy by value. Syscall wrappers deliberately retain raw pointers: the kernel receives untyped integer addresses, buffers carry separate byte counts, and optional outputs may be null. Callers must therefore pass explicit addresses such as `ClockGetTime(ClockMonotonic, @time)` and uphold each function's safety contract. No wrapper owns an address or descriptor; release mappings and close descriptors explicitly, or prefer the higher-level `Rux/Memory` and `Rux/Io` packages. ### Platform Linux only. Guard use behind a compile-time check, so a build for another target never resolves these declarations: ```rux import Core::{ #target }; when #target.os == .Linux { import Linux::{ StdOut, Write }; } ``` ## Index ### Types | Name | Summary | | ------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------- | | [`AddressInfo`](https://rux-lang.dev/docs/api/linux/resolve#address-info) | The C library's `addrinfo`: one result of [`getaddrinfo`](https://rux-lang.dev/docs/api/linux/resolve#getaddrinfo), linked to the next. | | [`SpawnFileActions`](https://rux-lang.dev/docs/api/linux/spawn#spawn-file-actions) | Room for a `posix_spawn_file_actions_t`, which each C library sizes its own way and none larger than this. | | [`PThread`](https://rux-lang.dev/docs/api/linux/thread#p-thread) | A thread as the C library names it, `pthread_t`. | | [`PThreadAttributes`](https://rux-lang.dev/docs/api/linux/thread#p-thread-attributes) | Room for a `pthread_attr_t`, which each C library sizes its own way and none larger than this. | | [`ProcessId`](https://rux-lang.dev/docs/api/linux/types#process-id) | A process identifier, as `getpid` and its relatives report one. | | [`FileDescriptor`](https://rux-lang.dev/docs/api/linux/types#file-descriptor) | A file descriptor, as the kernel numbers one. | | [`FileOffset`](https://rux-lang.dev/docs/api/linux/types#file-offset) | A byte offset within a file, which the 64-bit ABI makes 64 bits everywhere. | | [`FileMode`](https://rux-lang.dev/docs/api/linux/types#file-mode) | A file's type and permission bits, as `open` and `stat` carry them. | | [`UserId`](https://rux-lang.dev/docs/api/linux/types#user-id) | A user identifier. | | [`GroupId`](https://rux-lang.dev/docs/api/linux/types#group-id) | A group identifier. | | [`Timespec`](https://rux-lang.dev/docs/api/linux/timespec) | A duration or an instant, as seconds and nanoseconds. | ### Functions | Name | Summary | | ------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------ | | [`ClockGetTime`](https://rux-lang.dev/docs/api/linux/clock#clock-get-time) | Reads `clockId` into `time`. | | [`Nanosleep`](https://rux-lang.dev/docs/api/linux/clock#nanosleep) | Suspends the caller for the requested duration. | | [`ClockGetResolution`](https://rux-lang.dev/docs/api/linux/clock#clock-get-resolution) | Reads the resolution of `clockId` into `resolution`. | | [`ClockNanosleep`](https://rux-lang.dev/docs/api/linux/clock#clock-nanosleep) | Suspends the caller against a named clock, optionally until an absolute time. | | [`dlopen`](https://rux-lang.dev/docs/api/linux/dynamic#dlopen) | Loads a shared object and returns a handle to it, or null on failure. | | [`dlsym`](https://rux-lang.dev/docs/api/linux/dynamic#dlsym) | Finds a symbol in a loaded object and returns its address, or null. | | [`dlclose`](https://rux-lang.dev/docs/api/linux/dynamic#dlclose) | Drops one reference to a loaded object, unloading it when the last one goes. | | [`dlerror`](https://rux-lang.dev/docs/api/linux/dynamic#dlerror) | Reports the most recent loader error and clears it, or returns null when there is none. | | [`GetRandom`](https://rux-lang.dev/docs/api/linux/get-random) | Fills up to `length` bytes of `buffer` with unpredictable bytes. | | [`IsError`](https://rux-lang.dev/docs/api/linux/errors#is-error) | Whether a raw system-call result is one of the kernel's reserved error values. | | [`Errno`](https://rux-lang.dev/docs/api/linux/errors#errno) | The error number a raw system-call result carries, or zero when it carries none. | | [`Read`](https://rux-lang.dev/docs/api/linux/files#read) | Reads up to `count` bytes from `fd` into `buffer`. | | [`Write`](https://rux-lang.dev/docs/api/linux/files#write) | Writes up to `count` bytes from `buffer` to `fd`. | | [`Close`](https://rux-lang.dev/docs/api/linux/files#close) | Closes `fd` and releases what the kernel held for it. | | [`OpenAt`](https://rux-lang.dev/docs/api/linux/files#open-at) | Opens `path` relative to `directoryFd` and returns a descriptor, or a negative error number. | | [`Lseek`](https://rux-lang.dev/docs/api/linux/files#lseek) | Moves the file offset of `fd` and returns where it ended up, or a negative error number. | | [`Getdents64`](https://rux-lang.dev/docs/api/linux/directories#getdents64) | Reads directory entries from `fd` into `buffer`, and returns the bytes filled, zero at the end, or a negative error number. | | [`LinkAt`](https://rux-lang.dev/docs/api/linux/directories#link-at) | Creates a hard link: `newPath` becomes a second name for the file `oldPath` names. | | [`SymlinkAt`](https://rux-lang.dev/docs/api/linux/directories#symlink-at) | Creates a symbolic link at `linkPath` holding `target` as its text. | | [`FstatAt`](https://rux-lang.dev/docs/api/linux/files#fstat-at) | Fills `statBuffer` with what the kernel knows about the file `path` names. | | [`FchmodAt`](https://rux-lang.dev/docs/api/linux/files#fchmod-at) | Sets the permission bits of the file `path` names. | | [`UtimensAt`](https://rux-lang.dev/docs/api/linux/files#utimens-at) | Sets the access and modification times of the file `path` names. | | [`Getcwd`](https://rux-lang.dev/docs/api/linux/directories#getcwd) | Writes the current working directory's absolute path into `buffer`, NUL-terminated. | | [`Chdir`](https://rux-lang.dev/docs/api/linux/directories#chdir) | Makes `path` the process's working directory. | | [`ReadlinkAt`](https://rux-lang.dev/docs/api/linux/directories#readlink-at) | Reads the text a symbolic link holds into `buffer`. | | [`Fsync`](https://rux-lang.dev/docs/api/linux/files#fsync) | Flushes everything written to `fd` through to the storage device. | | [`Ftruncate`](https://rux-lang.dev/docs/api/linux/files#ftruncate) | Sets the length of the file behind `fd` to `length`. | | [`UnlinkAt`](https://rux-lang.dev/docs/api/linux/directories#unlink-at) | Removes the name `path` from its directory. | | [`MkdirAt`](https://rux-lang.dev/docs/api/linux/directories#mkdir-at) | Creates a directory named `path` with permission bits `mode`. | | [`RenameAt`](https://rux-lang.dev/docs/api/linux/directories#rename-at) | Renames `oldPath` to `newPath`, each resolved against its own directory descriptor. | | [`Fstat`](https://rux-lang.dev/docs/api/linux/files#fstat) | Fills `statBuffer` with what the kernel knows about the file behind `fd`. | | [`Dup3`](https://rux-lang.dev/docs/api/linux/files#dup3) | Makes `newFd` a copy of `oldFd`, closing whatever `newFd` was. | | [`Pipe2`](https://rux-lang.dev/docs/api/linux/files#pipe2) | Creates a pipe and writes its two descriptors into `descriptors`. | | [`FutexWait`](https://rux-lang.dev/docs/api/linux/futex#futex-wait) | Sleeps while `*address` equals `expected`, until a wake, a signal or the timeout. | | [`FutexWake`](https://rux-lang.dev/docs/api/linux/futex#futex-wake) | Wakes up to `count` threads sleeping on `address`. | | [`Mmap`](https://rux-lang.dev/docs/api/linux/memory#mmap) | Creates a mapping and returns its address, or a negative error number. | | [`Munmap`](https://rux-lang.dev/docs/api/linux/memory#munmap) | Releases the mapping that begins at `address` and spans `length` bytes. | | [`Brk`](https://rux-lang.dev/docs/api/linux/memory#brk) | Sets the program break and returns where it ended up. | | [`Mprotect`](https://rux-lang.dev/docs/api/linux/memory#mprotect) | Changes what may be done with the pages covering `address` through `address + length`. | | [`Madvise`](https://rux-lang.dev/docs/api/linux/memory#madvise) | Tells the kernel how the pages covering a range are about to be used. | | [`QueryPageSize`](https://rux-lang.dev/docs/api/linux/memory#query-page-size) | The size of a page, read out of this process's auxiliary vector. | | [`FcntlInt`](https://rux-lang.dev/docs/api/linux/poll#fcntl-int) | Performs `command` on a descriptor with an integer argument. | | [`EpollCreate1`](https://rux-lang.dev/docs/api/linux/poll#epoll-create1) | Opens an epoll instance. | | [`EpollControl`](https://rux-lang.dev/docs/api/linux/poll#epoll-control) | Adds, changes or removes the registration of `fd` with an epoll instance. | | [`EpollWait`](https://rux-lang.dev/docs/api/linux/poll#epoll-wait) | Waits until a registered descriptor is ready or `timeout` milliseconds pass, filling `events` with what is ready. | | [`Exit`](https://rux-lang.dev/docs/api/linux/process#exit) | Ends the calling thread's process with `code`. | | [`GetPid`](https://rux-lang.dev/docs/api/linux/process#get-pid) | The calling process's own identifier. | | [`getaddrinfo`](https://rux-lang.dev/docs/api/linux/resolve#getaddrinfo) | Looks up the addresses of a host and service. | | [`freeaddrinfo`](https://rux-lang.dev/docs/api/linux/resolve#freeaddrinfo) | Frees the results of [`getaddrinfo`](https://rux-lang.dev/docs/api/linux/resolve#getaddrinfo). | | [`Socket`](https://rux-lang.dev/docs/api/linux/socket#socket) | Opens a socket. | | [`Connect`](https://rux-lang.dev/docs/api/linux/socket#connect) | Connects a socket to `address`, waiting for a stream connection to be made. | | [`Bind`](https://rux-lang.dev/docs/api/linux/socket#bind) | Gives a socket its local address. | | [`Listen`](https://rux-lang.dev/docs/api/linux/socket#listen) | Makes a bound stream socket accept connections. | | [`Accept4`](https://rux-lang.dev/docs/api/linux/socket#accept4) | Accepts a waiting connection as a new socket. | | [`SendTo`](https://rux-lang.dev/docs/api/linux/socket#sendto) | Sends bytes on a socket, to `address` when it is not connected. | | [`ReceiveFrom`](https://rux-lang.dev/docs/api/linux/socket#receivefrom) | Receives bytes from a socket, and where they came from. | | [`Shutdown`](https://rux-lang.dev/docs/api/linux/socket#shutdown) | Ends one or both directions of a connection. | | [`SetSocketOption`](https://rux-lang.dev/docs/api/linux/socket#setsocketoption) | Sets a socket option. | | [`GetSocketName`](https://rux-lang.dev/docs/api/linux/socket#getsocketname) | Reads a socket's local address. | | [`GetPeerName`](https://rux-lang.dev/docs/api/linux/socket#getpeername) | Reads the address of a connected socket's peer. | | [`posix_spawnp`](https://rux-lang.dev/docs/api/linux/spawn#posix-spawnp) | Starts `file`, found through `PATH` when it has no slash, as a child process. | | [`posix_spawn_file_actions_init`](https://rux-lang.dev/docs/api/linux/spawn#posix-spawn-file-actions-init) | Initializes an empty list of file actions. | | [`posix_spawn_file_actions_destroy`](https://rux-lang.dev/docs/api/linux/spawn#posix-spawn-file-actions-destroy) | Releases what [`posix_spawn_file_actions_init`](https://rux-lang.dev/docs/api/linux/spawn#posix-spawn-file-actions-init) and the actions added since set up. | | [`posix_spawn_file_actions_adddup2`](https://rux-lang.dev/docs/api/linux/spawn#posix-spawn-file-actions-adddup2) | Adds an action duplicating `fd` onto `newFd` in the child. | | [`posix_spawn_file_actions_addopen`](https://rux-lang.dev/docs/api/linux/spawn#posix-spawn-file-actions-addopen) | Adds an action opening `path` as `fd` in the child. | | [`posix_spawn_file_actions_addchdir_np`](https://rux-lang.dev/docs/api/linux/spawn#posix-spawn-file-actions-addchdir-np) | Adds an action changing the child's working directory to `path`. | | [`waitpid`](https://rux-lang.dev/docs/api/linux/spawn#waitpid) | Waits for a child to change state, and reports how it finished. | | [`kill`](https://rux-lang.dev/docs/api/linux/spawn#kill) | Sends a signal to a process. | | [`fcntl`](https://rux-lang.dev/docs/api/linux/spawn#fcntl) | Performs a control operation on a descriptor, such as setting its flags with [`F_SETFD`](https://rux-lang.dev/docs/api/linux/spawn#f-setfd). | | [`__errno_location`](https://rux-lang.dev/docs/api/linux/spawn#errno) | Returns the address of the calling thread's errno, where the C library calls above leave their reason. | | [`Syscall0`](https://rux-lang.dev/docs/api/linux/syscalls#syscall-0) | Executes a raw Linux system call without arguments. | | [`Syscall6`](https://rux-lang.dev/docs/api/linux/syscalls#syscall-6) | Executes a raw Linux system call with six arguments. | | [`SignExtendFd`](https://rux-lang.dev/docs/api/linux/syscalls#sign-extend-fd) | Widens a file descriptor to the register width a system call takes it in. | | [`pthread_create`](https://rux-lang.dev/docs/api/linux/thread#pthread-create) | Starts a thread running `start(argument)`. | | [`pthread_join`](https://rux-lang.dev/docs/api/linux/thread#pthread-join) | Waits for a thread to finish and releases it. | | [`pthread_detach`](https://rux-lang.dev/docs/api/linux/thread#pthread-detach) | Lets a thread release itself when it finishes, so nothing has to join it. | | [`pthread_attr_init`](https://rux-lang.dev/docs/api/linux/thread#pthread-attr-init) | Initializes thread attributes to the defaults. | | [`pthread_attr_setstacksize`](https://rux-lang.dev/docs/api/linux/thread#pthread-attr-setstacksize) | Sets the stack size a thread started with these attributes gets. | | [`pthread_attr_destroy`](https://rux-lang.dev/docs/api/linux/thread#pthread-attr-destroy) | Releases what [`pthread_attr_init`](https://rux-lang.dev/docs/api/linux/thread#pthread-attr-init) set up. | | [`gettid`](https://rux-lang.dev/docs/api/linux/thread#gettid) | Returns the kernel's identifier for the calling thread, which is the process identifier on its first thread. | | [`sched_yield`](https://rux-lang.dev/docs/api/linux/thread#sched-yield) | Gives up the processor so another ready thread can run. | | [`sysconf`](https://rux-lang.dev/docs/api/linux/thread#sysconf) | Reads a system configuration value. | ### Constants | Name | Summary | | ------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | [`ClockRealtime`](https://rux-lang.dev/docs/api/linux/clock#clock-realtime) | `CLOCK_REALTIME`: wall-clock time, which can jump when the system clock is set. | | [`ClockMonotonic`](https://rux-lang.dev/docs/api/linux/clock#clock-monotonic) | `CLOCK_MONOTONIC`: time since an unspecified point, which never goes backwards. | | [`ClockProcessCpuTime`](https://rux-lang.dev/docs/api/linux/clock#clock-process-cpu-time) | `CLOCK_PROCESS_CPUTIME_ID`: processor time this process has used. | | [`ClockThreadCpuTime`](https://rux-lang.dev/docs/api/linux/clock#clock-thread-cpu-time) | `CLOCK_THREAD_CPUTIME_ID`: processor time this thread has used. | | [`ClockMonotonicRaw`](https://rux-lang.dev/docs/api/linux/clock#clock-monotonic-raw) | `CLOCK_MONOTONIC_RAW`: like [`ClockMonotonic`](https://rux-lang.dev/docs/api/linux/clock#clock-monotonic), but not adjusted by time synchronization. | | [`TimerAbsolute`](https://rux-lang.dev/docs/api/linux/clock#timer-absolute) | `TIMER_ABSTIME`: [`ClockNanosleep`](https://rux-lang.dev/docs/api/linux/clock#clock-nanosleep) should treat its time as an absolute deadline. | | [`RTLD_LAZY`](https://rux-lang.dev/docs/api/linux/dynamic#rtld-lazy) | `RTLD_LAZY`: resolve a function symbol the first time it is called rather than at load. | | [`RTLD_NOW`](https://rux-lang.dev/docs/api/linux/dynamic#rtld-now) | `RTLD_NOW`: resolve every symbol before [`dlopen`](https://rux-lang.dev/docs/api/linux/dynamic#dlopen) returns, so a missing one is reported there. | | [`RTLD_GLOBAL`](https://rux-lang.dev/docs/api/linux/dynamic#rtld-global) | `RTLD_GLOBAL`: make this object's symbols available to objects loaded afterwards. | | [`RTLD_LOCAL`](https://rux-lang.dev/docs/api/linux/dynamic#rtld-local) | `RTLD_LOCAL`: keep this object's symbols to itself, which is the default. | | [`RTLD_NODELETE`](https://rux-lang.dev/docs/api/linux/dynamic#rtld-nodelete) | `RTLD_NODELETE`: do not unload the object when its last reference goes, so its storage stays valid. | | [`RandomNonBlocking`](https://rux-lang.dev/docs/api/linux/get-random#random-non-blocking) | `GRND_NONBLOCK`: report [`EAGAIN`](https://rux-lang.dev/docs/api/linux/errors#eagain) rather than waiting for the pool to be seeded. | | [`RandomBlockingPool`](https://rux-lang.dev/docs/api/linux/get-random#random-blocking-pool) | `GRND_RANDOM`: draw from the blocking pool, which is almost never what a caller wants. | | [`EPERM`](https://rux-lang.dev/docs/api/linux/errors#eperm) | `EPERM`: the operation is not permitted to this caller. | | [`ENOENT`](https://rux-lang.dev/docs/api/linux/errors#enoent) | `ENOENT`: no such file or directory. | | [`ESRCH`](https://rux-lang.dev/docs/api/linux/errors#esrch) | `ESRCH`: no such process. | | [`EINTR`](https://rux-lang.dev/docs/api/linux/errors#eintr) | `EINTR`: the call was interrupted by a signal before it did anything. | | [`EIO`](https://rux-lang.dev/docs/api/linux/errors#eio) | `EIO`: a low-level input or output error. | | [`ENXIO`](https://rux-lang.dev/docs/api/linux/errors#enxio) | `ENXIO`: no such device or address. | | [`EBADF`](https://rux-lang.dev/docs/api/linux/errors#ebadf) | `EBADF`: the file descriptor is not open, or is not open for what was asked. | | [`EAGAIN`](https://rux-lang.dev/docs/api/linux/errors#eagain) | `EAGAIN`: the operation would block, and the descriptor was set not to. | | [`ENOMEM`](https://rux-lang.dev/docs/api/linux/errors#enomem) | `ENOMEM`: not enough memory to satisfy the request. | | [`EACCES`](https://rux-lang.dev/docs/api/linux/errors#eacces) | `EACCES`: permission denied. | | [`EFAULT`](https://rux-lang.dev/docs/api/linux/errors#efault) | `EFAULT`: an address the call was given is outside the caller's address space. | | [`EBUSY`](https://rux-lang.dev/docs/api/linux/errors#ebusy) | `EBUSY`: the resource is in use. | | [`EEXIST`](https://rux-lang.dev/docs/api/linux/errors#eexist) | `EEXIST`: the file already exists. | | [`EXDEV`](https://rux-lang.dev/docs/api/linux/errors#exdev) | `EXDEV`: the two paths are on different file systems. | | [`ENOTDIR`](https://rux-lang.dev/docs/api/linux/errors#enotdir) | `ENOTDIR`: a path component that had to be a directory is not one. | | [`EISDIR`](https://rux-lang.dev/docs/api/linux/errors#eisdir) | `EISDIR`: the target is a directory and the operation is not one a directory accepts. | | [`EINVAL`](https://rux-lang.dev/docs/api/linux/errors#einval) | `EINVAL`: an argument is not valid. | | [`EMFILE`](https://rux-lang.dev/docs/api/linux/errors#emfile) | `EMFILE`: this process has too many descriptors open. | | [`ENOSPC`](https://rux-lang.dev/docs/api/linux/errors#enospc) | `ENOSPC`: the device has no room left. | | [`ESPIPE`](https://rux-lang.dev/docs/api/linux/errors#espipe) | `ESPIPE`: the descriptor is a pipe or socket and cannot be seeked. | | [`EROFS`](https://rux-lang.dev/docs/api/linux/errors#erofs) | `EROFS`: the file system is mounted read-only. | | [`EPIPE`](https://rux-lang.dev/docs/api/linux/errors#epipe) | `EPIPE`: the reading end of the pipe is closed. | | [`ENAMETOOLONG`](https://rux-lang.dev/docs/api/linux/errors#enametoolong) | `ENAMETOOLONG`: the path or a component of it is too long. | | [`ENOSYS`](https://rux-lang.dev/docs/api/linux/errors#enosys) | `ENOSYS`: the kernel does not implement this call. | | [`ELOOP`](https://rux-lang.dev/docs/api/linux/errors#eloop) | `ELOOP`: too many symbolic links were followed resolving the path. | | [`EOVERFLOW`](https://rux-lang.dev/docs/api/linux/errors#eoverflow) | `EOVERFLOW`: a value is too large for the type the call reports it in. | | [`ETIMEDOUT`](https://rux-lang.dev/docs/api/linux/errors#etimedout) | `ETIMEDOUT`: the operation timed out. | | [`MaximumErrno`](https://rux-lang.dev/docs/api/linux/errors#maximum-errno) | The largest error number the kernel's reserved range holds. | | [`StdIn`](https://rux-lang.dev/docs/api/linux/files#std-in) | The descriptor a process reads its input from, unless something reassigned it. | | [`StdOut`](https://rux-lang.dev/docs/api/linux/files#std-out) | The descriptor a process writes its output to. | | [`StdErr`](https://rux-lang.dev/docs/api/linux/files#std-err) | The descriptor a process writes its diagnostics to, which is separate so it survives a redirected output. | | [`AtFdCwd`](https://rux-lang.dev/docs/api/linux/files#at-fd-cwd) | `AT_FDCWD`: resolve a relative path against the current directory rather than a descriptor. | | [`OpenReadOnly`](https://rux-lang.dev/docs/api/linux/files#open-read-only) | `O_RDONLY`: open for reading only. | | [`OpenWriteOnly`](https://rux-lang.dev/docs/api/linux/files#open-write-only) | `O_WRONLY`: open for writing only. | | [`OpenReadWrite`](https://rux-lang.dev/docs/api/linux/files#open-read-write) | `O_RDWR`: open for both reading and writing. | | [`OpenCreate`](https://rux-lang.dev/docs/api/linux/files#open-create) | `O_CREAT`: create the file when it does not exist, which is when the mode argument is read. | | [`OpenExclusive`](https://rux-lang.dev/docs/api/linux/files#open-exclusive) | `O_EXCL`: with [`OpenCreate`](https://rux-lang.dev/docs/api/linux/files#open-create), fail rather than open a file that already exists. | | [`OpenTruncate`](https://rux-lang.dev/docs/api/linux/files#open-truncate) | `O_TRUNC`: truncate the file to nothing when opening it for writing. | | [`OpenAppend`](https://rux-lang.dev/docs/api/linux/files#open-append) | `O_APPEND`: every write goes to the end, atomically with respect to other appenders. | | [`OpenNonBlocking`](https://rux-lang.dev/docs/api/linux/files#open-non-blocking) | [`O_NONBLOCK`](https://rux-lang.dev/docs/api/linux/poll#o-nonblock): reads and writes report [`EAGAIN`](https://rux-lang.dev/docs/api/linux/errors#eagain) rather than waiting. | | [`OpenCloseOnExec`](https://rux-lang.dev/docs/api/linux/files#open-close-on-exec) | `O_CLOEXEC`: close this descriptor automatically when the process executes a new program. | | [`OpenDirectory`](https://rux-lang.dev/docs/api/linux/files#open-directory) | `O_DIRECTORY`: fail unless the target is a directory. | | [`SeekSet`](https://rux-lang.dev/docs/api/linux/files#seek-set) | `SEEK_SET`: measure the new offset from the start of the file. | | [`SeekCurrent`](https://rux-lang.dev/docs/api/linux/files#seek-current) | `SEEK_CUR`: measure the new offset from the current one. | | [`SeekEnd`](https://rux-lang.dev/docs/api/linux/files#seek-end) | `SEEK_END`: measure the new offset from the end of the file. | | [`FollowSymlinks`](https://rux-lang.dev/docs/api/linux/directories#follow-symlinks) | `AT_SYMLINK_FOLLOW`: make [`LinkAt`](https://rux-lang.dev/docs/api/linux/directories#link-at) link a symbolic link's target rather than the link. | | [`SymlinkNoFollow`](https://rux-lang.dev/docs/api/linux/directories#symlink-no-follow) | `AT_SYMLINK_NOFOLLOW`: act on a symbolic link itself rather than on what it points at. | | [`RemoveDirectory`](https://rux-lang.dev/docs/api/linux/directories#remove-directory) | `AT_REMOVEDIR`: make [`UnlinkAt`](https://rux-lang.dev/docs/api/linux/directories#unlink-at) remove a directory rather than a file. | | [`FutexWaitPrivate`](https://rux-lang.dev/docs/api/linux/futex#futex-wait-private) | `FUTEX_WAIT_PRIVATE`: sleep while the word holds the expected value. | | [`FutexWakePrivate`](https://rux-lang.dev/docs/api/linux/futex#futex-wake-private) | `FUTEX_WAKE_PRIVATE`: wake threads sleeping on the word. | | [`ProtectionNone`](https://rux-lang.dev/docs/api/linux/memory#protection-none) | `PROT_NONE`: the pages may not be touched at all. | | [`ProtectionRead`](https://rux-lang.dev/docs/api/linux/memory#protection-read) | `PROT_READ`: the pages may be read. | | [`ProtectionWrite`](https://rux-lang.dev/docs/api/linux/memory#protection-write) | `PROT_WRITE`: the pages may be written. | | [`ProtectionExecute`](https://rux-lang.dev/docs/api/linux/memory#protection-execute) | `PROT_EXEC`: the pages may be executed. | | [`MapShared`](https://rux-lang.dev/docs/api/linux/memory#map-shared) | `MAP_SHARED`: writes are visible to other mappings of the same object and reach it. | | [`MapPrivate`](https://rux-lang.dev/docs/api/linux/memory#map-private) | `MAP_PRIVATE`: writes are private to this mapping and never reach the object. | | [`MapFixed`](https://rux-lang.dev/docs/api/linux/memory#map-fixed) | `MAP_FIXED`: place the mapping exactly at the requested address, replacing whatever was there. | | [`MapAnonymous`](https://rux-lang.dev/docs/api/linux/memory#map-anonymous) | `MAP_ANONYMOUS`: the mapping is backed by zeroed pages rather than by a file. | | [`AdviseDontNeed`](https://rux-lang.dev/docs/api/linux/memory#advise-dont-need) | `MADV_DONTNEED`: the pages are not needed, and the kernel may discard them. | | [`AdviseWillNeed`](https://rux-lang.dev/docs/api/linux/memory#advise-will-need) | `MADV_WILLNEED`: the pages will be read soon, so reading them ahead is worthwhile. | | [`AdviseRandom`](https://rux-lang.dev/docs/api/linux/memory#advise-random) | `MADV_RANDOM`: the pages will be touched in no useful order, so reading ahead is not. | | [`AdviseSequential`](https://rux-lang.dev/docs/api/linux/memory#advise-sequential) | `MADV_SEQUENTIAL`: the pages will be touched in order. | | [`AuxPageSize`](https://rux-lang.dev/docs/api/linux/memory#aux-page-size) | `AT_PAGESZ`: the auxiliary-vector entry holding the page size, in bytes. | | [`AuxNull`](https://rux-lang.dev/docs/api/linux/memory#aux-null) | `AT_NULL`: the entry that ends the auxiliary vector. | | [`EpollEventBytes`](https://rux-lang.dev/docs/api/linux/poll#epoll-event-bytes) | The size of one `epoll_event` in bytes: its four-byte event mask, padding, and eight-byte word. | | [`EpollEventWordOffset`](https://rux-lang.dev/docs/api/linux/poll#epoll-event-word-offset) | Where the caller's word starts in an `epoll_event`. | | [`F_GETFL`](https://rux-lang.dev/docs/api/linux/poll#f-getfl) | `F_GETFL`: the [`fcntl`](https://rux-lang.dev/docs/api/linux/spawn#fcntl) command that reads a descriptor's status flags. | | [`F_SETFL`](https://rux-lang.dev/docs/api/linux/poll#f-setfl) | `F_SETFL`: the [`fcntl`](https://rux-lang.dev/docs/api/linux/spawn#fcntl) command that sets a descriptor's status flags. | | [`O_NONBLOCK`](https://rux-lang.dev/docs/api/linux/poll#o-nonblock) | `O_NONBLOCK`: the status flag that makes a call fail with [`EAGAIN`](https://rux-lang.dev/docs/api/linux/errors#eagain) rather than wait. | | [`EPOLL_CLOEXEC`](https://rux-lang.dev/docs/api/linux/poll#epoll-cloexec) | `EPOLL_CLOEXEC`: close the epoll descriptor when the process starts another program. | | [`EPOLL_CTL_ADD`](https://rux-lang.dev/docs/api/linux/poll#epoll-ctl-add) | `EPOLL_CTL_ADD`: register a descriptor. | | [`EPOLL_CTL_DEL`](https://rux-lang.dev/docs/api/linux/poll#epoll-ctl-del) | `EPOLL_CTL_DEL`: remove a descriptor's registration. | | [`EPOLL_CTL_MOD`](https://rux-lang.dev/docs/api/linux/poll#epoll-ctl-mod) | `EPOLL_CTL_MOD`: change a registered descriptor's events and word. | | [`EPOLLIN`](https://rux-lang.dev/docs/api/linux/poll#epollin) | `EPOLLIN`: there is something to read, or a connection to accept. | | [`EPOLLOUT`](https://rux-lang.dev/docs/api/linux/poll#epollout) | `EPOLLOUT`: a write would not wait. | | [`EPOLLERR`](https://rux-lang.dev/docs/api/linux/poll#epollerr) | `EPOLLERR`: the descriptor has an error pending; always reported. | | [`EPOLLHUP`](https://rux-lang.dev/docs/api/linux/poll#epollhup) | `EPOLLHUP`: the peer has closed the connection; always reported. | | [`EPOLLRDHUP`](https://rux-lang.dev/docs/api/linux/poll#epollrdhup) | `EPOLLRDHUP`: the peer has shut down its writing side. | | [`AF_INET`](https://rux-lang.dev/docs/api/linux/socket#af-inet) | `AF_INET`: the IPv4 address family. | | [`AF_INET6`](https://rux-lang.dev/docs/api/linux/socket#af-inet6) | `AF_INET6`: the IPv6 address family. | | [`SOCK_STREAM`](https://rux-lang.dev/docs/api/linux/socket#sock-stream) | `SOCK_STREAM`: a connected byte stream. | | [`SOCK_DGRAM`](https://rux-lang.dev/docs/api/linux/socket#sock-dgram) | `SOCK_DGRAM`: individual datagrams. | | [`SOCK_CLOEXEC`](https://rux-lang.dev/docs/api/linux/socket#sock-cloexec) | `SOCK_CLOEXEC`: close the socket when the process starts another program. | | [`SOL_SOCKET`](https://rux-lang.dev/docs/api/linux/socket#sol-socket) | `SOL_SOCKET`: the level of the options every socket has. | | [`SO_REUSEADDR`](https://rux-lang.dev/docs/api/linux/socket#so-reuseaddr) | `SO_REUSEADDR`: let a listening address be bound again while old connections to it wind down. | | [`SO_RCVTIMEO`](https://rux-lang.dev/docs/api/linux/socket#so-rcvtimeo) | `SO_RCVTIMEO`: how long a receive waits. | | [`SO_SNDTIMEO`](https://rux-lang.dev/docs/api/linux/socket#so-sndtimeo) | `SO_SNDTIMEO`: how long a send waits. | | [`IPPROTO_TCP`](https://rux-lang.dev/docs/api/linux/socket#ipproto-tcp) | `IPPROTO_TCP`: the level of TCP's options. | | [`TCP_NODELAY`](https://rux-lang.dev/docs/api/linux/socket#tcp-nodelay) | `TCP_NODELAY`: send small writes at once rather than gathering them. | | [`IPPROTO_IPV6`](https://rux-lang.dev/docs/api/linux/socket#ipproto-ipv6) | `IPPROTO_IPV6`: the level of IPv6's options. | | [`IPV6_V6ONLY`](https://rux-lang.dev/docs/api/linux/socket#ipv6-v6only) | `IPV6_V6ONLY`: accept only IPv6 on an IPv6 socket. | | [`MSG_NOSIGNAL`](https://rux-lang.dev/docs/api/linux/socket#msg-nosignal) | `MSG_NOSIGNAL`: report a closed peer as an error rather than with `SIGPIPE`. | | [`F_SETFD`](https://rux-lang.dev/docs/api/linux/spawn#f-setfd) | `F_SETFD`: the [`fcntl`](https://rux-lang.dev/docs/api/linux/spawn#fcntl) command that sets a descriptor's flags. | | [`FD_CLOEXEC`](https://rux-lang.dev/docs/api/linux/spawn#fd-cloexec) | `FD_CLOEXEC`: close the descriptor when the process starts another program. | | [`WNOHANG`](https://rux-lang.dev/docs/api/linux/spawn#wnohang) | `WNOHANG`: have [`waitpid`](https://rux-lang.dev/docs/api/linux/spawn#waitpid) return at once when the child has not finished. | | [`SIGKILL`](https://rux-lang.dev/docs/api/linux/spawn#sigkill) | `SIGKILL`: the signal that ends a process at once and cannot be caught. | | [`SysMmap`](https://rux-lang.dev/docs/api/linux/syscalls#sys-mmap) | `mmap(2)`'s system-call number. | | [`SysGetPid`](https://rux-lang.dev/docs/api/linux/syscalls#sys-get-pid) | `getpid(2)`'s system-call number. | | [`SC_NPROCESSORS_ONLN`](https://rux-lang.dev/docs/api/linux/thread#sc-nprocessors-onln) | `_SC_NPROCESSORS_ONLN`: the [`sysconf`](https://rux-lang.dev/docs/api/linux/thread#sysconf) name for the number of processors currently online. | # Timespec A duration or an instant, as seconds and nanoseconds. ```rux pub struct Timespec { pub seconds: int64; pub nanoseconds: int64; } ``` Both fields are 64 bits under the kernel's 64-bit ABI, whichever architecture. `nanoseconds` is in `[0, 999999999]` for a value the kernel produced; a value the caller builds must normalize it, since a call given more than a second's worth of nanoseconds reports [`EINVAL`](https://rux-lang.dev/docs/api/linux/errors#einval) rather than carrying. Passed by address to every call that reads or fills one. ## Fields | Name | Type | Description | | ------------- | ------- | --------------------------------------------------- | | `seconds` | `int64` | Whole seconds. | | `nanoseconds` | `int64` | Nanoseconds within the second, in `[0, 999999999]`. | # Types Linux's scalar types for process, file and user identifiers. ## `FileDescriptor` ```rux pub type FileDescriptor = int32 ``` A file descriptor, as the kernel numbers one. Signed and small. A syscall taking one receives it sign-extended to a full register, which [`SignExtendFd`](https://rux-lang.dev/docs/api/linux/syscalls#sign-extend-fd) does. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Types.rux#L15){rel=""nofollow""} ## `FileMode` ```rux pub type FileMode = uint32 ``` A file's type and permission bits, as `open` and `stat` carry them. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Types.rux#L23){rel=""nofollow""} ## `FileOffset` ```rux pub type FileOffset = int64 ``` A byte offset within a file, which the 64-bit ABI makes 64 bits everywhere. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Types.rux#L19){rel=""nofollow""} ## `GroupId` ```rux pub type GroupId = uint32 ``` A group identifier. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Types.rux#L31){rel=""nofollow""} ## `ProcessId` ```rux pub type ProcessId = int32 ``` A process identifier, as `getpid` and its relatives report one. Signed, because several calls overload the negative range to mean a process group. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Types.rux#L10){rel=""nofollow""} ## `UserId` ```rux pub type UserId = uint32 ``` A user identifier. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Types.rux#L27){rel=""nofollow""} # Directories and links The working directory, directory entries, removal, renaming and links. ## `Getdents64` ```rux pub func Getdents64( fd: FileDescriptor, buffer: *var opaque, count: uint ) -> int64 ``` Reads directory entries from `fd` into `buffer`, and returns the bytes filled, zero at the end, or a negative error number. The buffer holds packed `linux_dirent64` records: inode at offset 0 (8 bytes), a seek cookie at 8 (8 bytes), the record's length at 16 (2 bytes), the entry type at 18 (1 byte), and the NUL-terminated name from 19. The kernel writes as many whole records as fit; call again for the rest. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/File.rux#L184){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | ---------------- | ------------------------------------- | | `fd` | `FileDescriptor` | an open descriptor | | `buffer` | `*var opaque` | receives the packed directory records | | `count` | `uint` | how many bytes `buffer` holds | **Returns**: the bytes filled, zero at the end of the directory, or a negative error number ## `LinkAt` ```rux pub func LinkAt( oldDirectoryFd: FileDescriptor, oldPath: *char8, newDirectoryFd: FileDescriptor, newPath: *char8, flags: int32 ) -> int64 ``` Creates a hard link: `newPath` becomes a second name for the file `oldPath` names. Returns zero, or a negative error number. `flags` is zero to leave a symbolic link at `oldPath` unfollowed, or [`FollowSymlinks`](https://rux-lang.dev/docs/api/linux/directories#follow-symlinks) to link what it points at. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/File.rux#L198){rel=""nofollow""} **Parameters** | Name | Type | Description | | ---------------- | ---------------- | -------------------------------------------------------------------------------------------------------------------------------- | | `oldDirectoryFd` | `FileDescriptor` | the directory `oldPath` is relative to | | `oldPath` | `*char8` | the existing name | | `newDirectoryFd` | `FileDescriptor` | the directory `newPath` is relative to | | `newPath` | `*char8` | the new name for the same file | | `flags` | `int32` | zero, or [`FollowSymlinks`](https://rux-lang.dev/docs/api/linux/directories#follow-symlinks) to link what a final link points at | **Returns**: zero, or a negative error number ## `FollowSymlinks` ```rux pub const FollowSymlinks: int32 = 0x0400; ``` `AT_SYMLINK_FOLLOW`: make [`LinkAt`](https://rux-lang.dev/docs/api/linux/directories#link-at) link a symbolic link's target rather than the link. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/File.rux#L206){rel=""nofollow""} ## `SymlinkAt` ```rux pub func SymlinkAt( target: *char8, newDirectoryFd: FileDescriptor, linkPath: *char8 ) -> int64 ``` Creates a symbolic link at `linkPath` holding `target` as its text. Returns zero, or a negative error number. The target is stored, not checked: a dangling link is created as readily as a good one, which is a property callers rely on. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/File.rux#L216){rel=""nofollow""} **Parameters** | Name | Type | Description | | ---------------- | ---------------- | ------------------------------------------------- | | `target` | `*char8` | the text the link will hold, which need not exist | | `newDirectoryFd` | `FileDescriptor` | the directory `linkPath` is relative to | | `linkPath` | `*char8` | the link to create | **Returns**: zero, or a negative error number ## `SymlinkNoFollow` ```rux pub const SymlinkNoFollow: int32 = 0x0100; ``` `AT_SYMLINK_NOFOLLOW`: act on a symbolic link itself rather than on what it points at. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/File.rux#L222){rel=""nofollow""} ## `Getcwd` ```rux pub func Getcwd(buffer: *var char8, size: uint) -> int64 ``` Writes the current working directory's absolute path into `buffer`, NUL-terminated. Returns the length written including the terminator, or a negative error number; `ERANGE` where the buffer is too small for the answer. `buffer` must be writable for `size` bytes. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/File.rux#L277){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | ------------ | -------------------------------------------------------- | | `buffer` | `*var char8` | receives the working directory as a null-terminated path | | `size` | `uint` | how many bytes `buffer` holds | **Returns**: the bytes written including the terminator, or a negative error number ## `Chdir` ```rux pub func Chdir(path: *char8) -> int64 ``` Makes `path` the process's working directory. Returns zero, or a negative error number. The change is process-wide and immediately visible to every thread, which is why nothing above this should call it casually. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/File.rux#L287){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------ | -------- | ------------------------ | | `path` | `*char8` | the directory to move to | **Returns**: zero, or a negative error number ## `ReadlinkAt` ```rux pub func ReadlinkAt( directoryFd: FileDescriptor, path: *char8, buffer: *var char8, size: uint ) -> int64 ``` Reads the text a symbolic link holds into `buffer`. `directoryFd` is [`AtFdCwd`](https://rux-lang.dev/docs/api/linux/files#at-fd-cwd) for an ordinary path. Returns the number of bytes written, or a negative error number. The text is **not** NUL-terminated, and is silently truncated where it does not fit, so a caller that filled the buffer exactly cannot tell truncation from a perfect fit and should retry with more room. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/File.rux#L301){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------------- | ---------------- | ----------------------------------------------------------------------------------------------------------------------------- | | `directoryFd` | `FileDescriptor` | the directory `path` is relative to, or [`AtFdCwd`](https://rux-lang.dev/docs/api/linux/files#at-fd-cwd) for an ordinary path | | `path` | `*char8` | the symbolic link to read | | `buffer` | `*var char8` | receives the link's text, without a terminator | | `size` | `uint` | how many bytes `buffer` holds | **Returns**: the bytes written, which equals `size` when the text was truncated, or a negative error number ## `UnlinkAt` ```rux pub func UnlinkAt( directoryFd: FileDescriptor, path: *char8, flags: int32 ) -> int64 ``` Removes the name `path` from its directory. `flags` is zero to remove a file, or [`RemoveDirectory`](https://rux-lang.dev/docs/api/linux/directories#remove-directory) to remove an empty directory. Returns zero, or a negative error number. Removing a name does not free the file: anything still holding it open keeps reading and writing it, and the storage goes only when the last descriptor closes. `path` must be non-null and terminated. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/File.rux#L337){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------------- | ---------------- | ----------------------------------------------------------------------------------------------------------------------------- | | `directoryFd` | `FileDescriptor` | the directory `path` is relative to, or [`AtFdCwd`](https://rux-lang.dev/docs/api/linux/files#at-fd-cwd) for an ordinary path | | `path` | `*char8` | the name to remove | | `flags` | `int32` | zero for a file, or [`RemoveDirectory`](https://rux-lang.dev/docs/api/linux/directories#remove-directory) for a directory | **Returns**: zero, or a negative error number ## `RemoveDirectory` ```rux pub const RemoveDirectory: int32 = 512; ``` `AT_REMOVEDIR`: make [`UnlinkAt`](https://rux-lang.dev/docs/api/linux/directories#unlink-at) remove a directory rather than a file. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/File.rux#L343){rel=""nofollow""} ## `MkdirAt` ```rux pub func MkdirAt( directoryFd: FileDescriptor, path: *char8, mode: FileMode ) -> int64 ``` Creates a directory named `path` with permission bits `mode`. Returns zero, or a negative error number — [`EEXIST`](https://rux-lang.dev/docs/api/linux/errors#eexist) when the name is taken, which is how this is used as a lock. `path` must be non-null and terminated. The mode is masked by the process umask. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/File.rux#L353){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------------- | ---------------- | ----------------------------------------------------------------------------------------------------------------------------- | | `directoryFd` | `FileDescriptor` | the directory `path` is relative to, or [`AtFdCwd`](https://rux-lang.dev/docs/api/linux/files#at-fd-cwd) for an ordinary path | | `path` | `*char8` | the directory to create | | `mode` | `FileMode` | the permission bits for it | **Returns**: zero, or a negative error number ## `RenameAt` ```rux pub func RenameAt( oldDirectoryFd: FileDescriptor, oldPath: *char8, newDirectoryFd: FileDescriptor, newPath: *char8 ) -> int64 ``` Renames `oldPath` to `newPath`, each resolved against its own directory descriptor. Returns zero, or a negative error number. Within one file system this replaces any existing `newPath` atomically, which is what makes it the way to publish a file that was written under a temporary name. Across file systems it reports [`EXDEV`](https://rux-lang.dev/docs/api/linux/errors#exdev) rather than copying. Both paths must be non-null and terminated. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/File.rux#L368){rel=""nofollow""} **Parameters** | Name | Type | Description | | ---------------- | ---------------- | -------------------------------------- | | `oldDirectoryFd` | `FileDescriptor` | the directory `oldPath` is relative to | | `oldPath` | `*char8` | the name to move | | `newDirectoryFd` | `FileDescriptor` | the directory `newPath` is relative to | | `newPath` | `*char8` | the name to move it to | **Returns**: zero, or a negative error number # GetRandom Fills up to `length` bytes of `buffer` with unpredictable bytes. ```rux pub func GetRandom( buffer: *var opaque, length: uint, flags: uint32 ) -> int64 ``` `buffer` is borrowed and written; `length` and `flags` are read by value. Returns the number of bytes actually written, or a negative error number. A short count is ordinary rather than a failure: a request over 256 bytes can be cut short by a signal, and a caller needing the whole buffer must call again for the rest. Without [`RandomNonBlocking`](https://rux-lang.dev/docs/api/linux/get-random#random-non-blocking) the first call in the life of a system may wait for the pool to be seeded; after that it does not wait at all. Runs in time proportional to `length` and allocates nothing. `buffer` must be writable for `length` bytes. Treat a short count as bytes obtained, not as failure, or the unwritten tail stays whatever it held — which for a key is the worst possible outcome. ## Parameters | Name | Type | Description | | -------- | ------------- | ------------------------------------ | | `buffer` | `*var opaque` | receives the bytes | | `length` | `uint` | how many bytes to ask for | | `flags` | `uint32` | zero, or one of the `Random*` values | **Returns**: the bytes written, which may be fewer than asked for, or a negative error number ## Related ### `RandomNonBlocking` ```rux pub const RandomNonBlocking: uint32 = 1; ``` `GRND_NONBLOCK`: report [`EAGAIN`](https://rux-lang.dev/docs/api/linux/errors#eagain) rather than waiting for the pool to be seeded. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Entropy.rux#L12){rel=""nofollow""} ### `RandomBlockingPool` ```rux pub const RandomBlockingPool: uint32 = 2; ``` `GRND_RANDOM`: draw from the blocking pool, which is almost never what a caller wants. Kept for completeness. The default source is as unpredictable and does not stall. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Entropy.rux#L17){rel=""nofollow""} # Process Ending the process and asking its identifier. ## `Exit` ```rux pub func Exit(code: int32) ``` Ends the calling thread's process with `code`. `code` is read by value; only its low eight bits reach a waiting parent, which is the kernel's rule rather than this binding's. Does not return. Nothing is flushed, unwound, or destroyed on the way out: the kernel reclaims the address space and the descriptors, and anything the program was holding elsewhere is simply gone. This ends the whole process rather than one thread: it is `exit_group`, not `exit`, which on Linux stops only the calling thread and would leave the others running. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Process.rux#L17){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------ | ------- | ---------------------------------- | | `code` | `int32` | the status to report to the parent | ## `GetPid` ```rux pub func GetPid() -> ProcessId ``` The calling process's own identifier. Takes nothing and returns the identifier by copy. Cannot fail: every process has one, and the call has no way to be given a bad argument. Runs in constant time and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Process.rux#L27){rel=""nofollow""} **Returns**: the calling process's identifier # Name resolution [`getaddrinfo`](https://rux-lang.dev/docs/api/linux/resolve#getaddrinfo) and the list of addresses it returns. ## `AddressInfo` ```rux pub struct AddressInfo { pub flags: int32; pub family: int32; pub socketType: int32; pub protocol: int32; pub addressLength: uint32; pub address: *opaque; pub canonicalName: *char8; pub next: *var AddressInfo; } ``` The C library's `addrinfo`: one result of [`getaddrinfo`](https://rux-lang.dev/docs/api/linux/resolve#getaddrinfo), linked to the next. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Resolve.rux#L10){rel=""nofollow""} **Fields** | Name | Type | Description | | --------------- | ------------------ | ---------------------------------------- | | `flags` | `int32` | Flags such as `AI_PASSIVE`. | | `family` | `int32` | The address family, or zero for any. | | `socketType` | `int32` | The socket type, or zero for any. | | `protocol` | `int32` | The protocol, or zero for any. | | `addressLength` | `uint32` | The size of `address` in bytes. | | `address` | `*opaque` | The address, a `sockaddr`. | | `canonicalName` | `*char8` | The host's canonical name, or null. | | `next` | `*var AddressInfo` | The next result, or null after the last. | ## `getaddrinfo` ```rux pub extern func getaddrinfo( node: *char8, service: *char8, hints: *AddressInfo, result: *var *var AddressInfo ) -> int32 ``` Looks up the addresses of a host and service. **See also**: <https://man7.org/linux/man-pages/man3/getaddrinfo.3.html>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Resolve.rux#L39){rel=""nofollow""} **Parameters** | Name | Type | Description | | --------- | ----------------------- | ---------------------------------------------------------------------------------------------------------------- | | `node` | `*char8` | the host name or numeric address, NUL-terminated, or null | | `service` | `*char8` | the service name or port number, NUL-terminated, or null | | `hints` | `*AddressInfo` | what kind of results are wanted, or null for every kind | | `result` | `*var *var AddressInfo` | receives the first result, freed with [`freeaddrinfo`](https://rux-lang.dev/docs/api/linux/resolve#freeaddrinfo) | **Returns**: zero, or an `EAI_*` code ## `freeaddrinfo` ```rux pub extern func freeaddrinfo(info: *var AddressInfo) ``` Frees the results of [`getaddrinfo`](https://rux-lang.dev/docs/api/linux/resolve#getaddrinfo). **See also**: <https://man7.org/linux/man-pages/man3/freeaddrinfo.3.html>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Resolve.rux#L45){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------ | ------------------ | ---------------- | | `info` | `*var AddressInfo` | the first result | # Starting processes `posix_spawn` and its file actions, and waiting for and signalling a child. ## `SpawnFileActions` ```rux pub struct SpawnFileActions { // private fields } ``` Room for a `posix_spawn_file_actions_t`, which each C library sizes its own way and none larger than this. Only ever passed by address to the `posix_spawn_file_actions_*` calls, which initialize and read it. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Spawn.rux#L14){rel=""nofollow""} **Constructors** ### `SpawnFileActions` ```rux pub func SpawnFileActions() -> SpawnFileActions ``` Zeroed storage for [`posix_spawn_file_actions_init`](https://rux-lang.dev/docs/api/linux/spawn#posix-spawn-file-actions-init) to initialize. **Returns**: the storage [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Spawn.rux#L22){rel=""nofollow""} ## `F_SETFD` ```rux pub const F_SETFD: int32 = 2; ``` `F_SETFD`: the [`fcntl`](https://rux-lang.dev/docs/api/linux/spawn#fcntl) command that sets a descriptor's flags. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Spawn.rux#L30){rel=""nofollow""} ## `FD_CLOEXEC` ```rux pub const FD_CLOEXEC: int32 = 1; ``` `FD_CLOEXEC`: close the descriptor when the process starts another program. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Spawn.rux#L35){rel=""nofollow""} ## `WNOHANG` ```rux pub const WNOHANG: int32 = 1; ``` `WNOHANG`: have [`waitpid`](https://rux-lang.dev/docs/api/linux/spawn#waitpid) return at once when the child has not finished. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Spawn.rux#L40){rel=""nofollow""} ## `SIGKILL` ```rux pub const SIGKILL: int32 = 9; ``` `SIGKILL`: the signal that ends a process at once and cannot be caught. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Spawn.rux#L45){rel=""nofollow""} ## `posix_spawnp` ```rux pub extern func posix_spawnp( pid: *var int32, file: *char8, fileActions: *SpawnFileActions, attributes: *opaque, arguments: **char8, environment: **char8 ) -> int32 ``` Starts `file`, found through `PATH` when it has no slash, as a child process. **See also**: <https://man7.org/linux/man-pages/man3/posix_spawn.3.html>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Spawn.rux#L59){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------------- | ------------------- | ---------------------------------------------------------------------- | | `pid` | `*var int32` | receives the child's process identifier | | `file` | `*char8` | the program, NUL-terminated | | `fileActions` | `*SpawnFileActions` | the descriptor and directory setup to run in the child first, or null | | `attributes` | `*opaque` | spawn attributes, or null for the defaults | | `arguments` | `**char8` | the argument vector, its first entry the program's name, ended by null | | `environment` | `**char8` | the environment, `NAME=VALUE` entries ended by null | **Returns**: zero, or an error number ## `posix_spawn_file_actions_init` ```rux pub extern func posix_spawn_file_actions_init(actions: *var SpawnFileActions) -> int32 ``` Initializes an empty list of file actions. **See also**: <https://man7.org/linux/man-pages/man3/posix_spawn_file_actions_init.3.html>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Spawn.rux#L67){rel=""nofollow""} **Parameters** | Name | Type | Description | | --------- | ----------------------- | ------------------------- | | `actions` | `*var SpawnFileActions` | the storage to initialize | **Returns**: zero, or an error number ## `posix_spawn_file_actions_destroy` ```rux pub extern func posix_spawn_file_actions_destroy(actions: *var SpawnFileActions) -> int32 ``` Releases what [`posix_spawn_file_actions_init`](https://rux-lang.dev/docs/api/linux/spawn#posix-spawn-file-actions-init) and the actions added since set up. **See also**: <https://man7.org/linux/man-pages/man3/posix_spawn_file_actions_destroy.3.html>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Spawn.rux#L74){rel=""nofollow""} **Parameters** | Name | Type | Description | | --------- | ----------------------- | ------------------------ | | `actions` | `*var SpawnFileActions` | initialized file actions | **Returns**: zero, or an error number ## `posix_spawn_file_actions_adddup2` ```rux pub extern func posix_spawn_file_actions_adddup2( actions: *var SpawnFileActions, fd: int32, newFd: int32 ) -> int32 ``` Adds an action duplicating `fd` onto `newFd` in the child. **See also**: <https://man7.org/linux/man-pages/man3/posix_spawn_file_actions_adddup2.3.html>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Spawn.rux#L83){rel=""nofollow""} **Parameters** | Name | Type | Description | | --------- | ----------------------- | --------------------------- | | `actions` | `*var SpawnFileActions` | initialized file actions | | `fd` | `int32` | the descriptor to duplicate | | `newFd` | `int32` | the descriptor it becomes | **Returns**: zero, or an error number ## `posix_spawn_file_actions_addopen` ```rux pub extern func posix_spawn_file_actions_addopen( actions: *var SpawnFileActions, fd: int32, path: *char8, flags: int32, mode: FileMode ) -> int32 ``` Adds an action opening `path` as `fd` in the child. **See also**: <https://man7.org/linux/man-pages/man3/posix_spawn_file_actions_addopen.3.html>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Spawn.rux#L94){rel=""nofollow""} **Parameters** | Name | Type | Description | | --------- | ----------------------- | ------------------------------------------ | | `actions` | `*var SpawnFileActions` | initialized file actions | | `fd` | `int32` | the descriptor the file becomes | | `path` | `*char8` | the file, NUL-terminated | | `flags` | `int32` | the open flags | | `mode` | `FileMode` | the permissions of a file the open creates | **Returns**: zero, or an error number ## `posix_spawn_file_actions_addchdir_np` ```rux pub extern func posix_spawn_file_actions_addchdir_np( actions: *var SpawnFileActions, path: *char8 ) -> int32 ``` Adds an action changing the child's working directory to `path`. **See also**: <https://man7.org/linux/man-pages/man3/posix_spawn_file_actions_addchdir_np.3.html>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Spawn.rux#L103){rel=""nofollow""} **Parameters** | Name | Type | Description | | --------- | ----------------------- | ----------------------------- | | `actions` | `*var SpawnFileActions` | initialized file actions | | `path` | `*char8` | the directory, NUL-terminated | **Returns**: zero, or an error number ## `waitpid` ```rux pub extern func waitpid( pid: int32, status: *var int32, options: int32 ) -> int32 ``` Waits for a child to change state, and reports how it finished. **See also**: <https://man7.org/linux/man-pages/man2/waitpid.2.html>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Spawn.rux#L112){rel=""nofollow""} **Parameters** | Name | Type | Description | | --------- | ------------ | --------------------------------------------------------------------------------------------------------------------------------- | | `pid` | `int32` | the child's process identifier | | `status` | `*var int32` | receives the encoded status | | `options` | `int32` | zero to wait, or [`WNOHANG`](https://rux-lang.dev/docs/api/linux/spawn#wnohang) to return at once when the child is still running | **Returns**: the child's identifier, zero with [`WNOHANG`](https://rux-lang.dev/docs/api/linux/spawn#wnohang) when it is still running, or -1 with the reason in errno ## `kill` ```rux pub extern func kill(pid: int32, signal: int32) -> int32 ``` Sends a signal to a process. **See also**: <https://man7.org/linux/man-pages/man2/kill.2.html>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Spawn.rux#L120){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | ------- | ----------------------------------------------------------------------------------------- | | `pid` | `int32` | the process | | `signal` | `int32` | the signal number, such as [`SIGKILL`](https://rux-lang.dev/docs/api/linux/spawn#sigkill) | **Returns**: zero, or -1 with the reason in errno ## `fcntl` ```rux pub extern func fcntl( fd: int32, command: int32, ... ) -> int32 ``` Performs a control operation on a descriptor, such as setting its flags with [`F_SETFD`](https://rux-lang.dev/docs/api/linux/spawn#f-setfd). **See also**: <https://man7.org/linux/man-pages/man2/fcntl.2.html>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Spawn.rux#L128){rel=""nofollow""} **Parameters** | Name | Type | Description | | --------- | ------- | -------------- | | `fd` | `int32` | the descriptor | | `command` | `int32` | the operation | | `...` | | | **Returns**: the operation's result, or -1 with the reason in errno ## `__errno_location` ```rux pub extern func __errno_location() -> *var int32 ``` Returns the address of the calling thread's errno, where the C library calls above leave their reason. **See also**: <https://man7.org/linux/man-pages/man3/errno.3.html>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Spawn.rux#L134){rel=""nofollow""} **Returns**: the errno's address # System calls The raw system-call entry points and the call numbers they take. ## `SysMmap` ```rux // x86-64 pub const SysMmap: uint64 = 9; // AArch64 pub const SysMmap: uint64 = 222; ``` `mmap(2)`'s system-call number. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Syscall.rux#L26){rel=""nofollow""} ## `SysGetPid` ```rux // x86-64 pub const SysGetPid: uint64 = 39; // AArch64 pub const SysGetPid: uint64 = 172; ``` `getpid(2)`'s system-call number. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Syscall.rux#L32){rel=""nofollow""} ## `Syscall0` ```rux pub func Syscall0(number: uint64) -> int64 ``` Executes a raw Linux system call without arguments. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Syscall.rux#L121){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | -------- | ----------------------- | | `number` | `uint64` | the system call to make | **Returns**: the kernel's raw result ## `Syscall6` ```rux pub func Syscall6( number: uint64, arg0: uint64, arg1: uint64, arg2: uint64, arg3: uint64, arg4: uint64, arg5: uint64 ) -> int64 ``` Executes a raw Linux system call with six arguments. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Syscall.rux#L188){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | -------- | -------------------------- | | `number` | `uint64` | the system call to make | | `arg0` | `uint64` | the call's first argument | | `arg1` | `uint64` | the call's second argument | | `arg2` | `uint64` | the call's third argument | | `arg3` | `uint64` | the call's fourth argument | | `arg4` | `uint64` | the call's fifth argument | | `arg5` | `uint64` | the call's sixth argument | **Returns**: the kernel's raw result ## `SignExtendFd` ```rux pub func SignExtendFd(fd: int32) -> uint64 ``` Widens a file descriptor to the register width a system call takes it in. `fd` is read by value; the widened value is returned by copy. Sign extension is what matters: `-1` has to arrive as all ones rather than as a small positive number, which is how `mmap` is told it has no backing descriptor. Cannot fail. Runs in constant time and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Syscall.rux#L295){rel=""nofollow""} **Parameters** | Name | Type | Description | | ---- | ------- | ----------------------- | | `fd` | `int32` | the descriptor to widen | **Returns**: it sign-extended, so a negative one stays negative # Threads POSIX threads: starting, joining and detaching them, their stack size, and the processor count. ## `PThread` ```rux pub type PThread = uint64 ``` A thread as the C library names it, `pthread_t`. Every system this package family binds keeps it in one word. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Thread.rux#L14){rel=""nofollow""} ## `PThreadAttributes` ```rux pub struct PThreadAttributes { // private fields } ``` Room for a `pthread_attr_t`, which each C library sizes its own way and none larger than this. Only ever passed by address to the `pthread_attr_*` calls, which initialize and read it. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Thread.rux#L19){rel=""nofollow""} **Constructors** ### `PThreadAttributes` ```rux pub func PThreadAttributes() -> PThreadAttributes ``` Zeroed storage for [`pthread_attr_init`](https://rux-lang.dev/docs/api/linux/thread#pthread-attr-init) to initialize. **Returns**: the storage [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Thread.rux#L27){rel=""nofollow""} ## `SC_NPROCESSORS_ONLN` ```rux pub const SC_NPROCESSORS_ONLN: int32 = 84; ``` `_SC_NPROCESSORS_ONLN`: the [`sysconf`](https://rux-lang.dev/docs/api/linux/thread#sysconf) name for the number of processors currently online. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Thread.rux#L35){rel=""nofollow""} ## `pthread_create` ```rux pub extern func pthread_create( thread: *var PThread, attributes: *PThreadAttributes, start: *opaque, argument: *var opaque ) -> int32 ``` Starts a thread running `start(argument)`. **See also**: <https://man7.org/linux/man-pages/man3/pthread_create.3.html>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Thread.rux#L47){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------------ | -------------------- | --------------------------------------------------------------------- | | `thread` | `*var PThread` | receives the new thread | | `attributes` | `*PThreadAttributes` | initialized attributes, or null for the defaults | | `start` | `*opaque` | the thread's entry point, a function taking and returning one pointer | | `argument` | `*var opaque` | the value handed to the entry point | **Returns**: zero, or an error number ## `pthread_join` ```rux pub extern func pthread_join( thread: PThread, result: *var *var opaque ) -> int32 ``` Waits for a thread to finish and releases it. **See also**: <https://man7.org/linux/man-pages/man3/pthread_join.3.html>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Thread.rux#L56){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | ------------------ | ----------------------------------------------------------------- | | `thread` | `PThread` | a thread nothing has joined or detached | | `result` | `*var *var opaque` | receives the value its entry point returned, or null to ignore it | **Returns**: zero, or an error number ## `pthread_detach` ```rux pub extern func pthread_detach(thread: PThread) -> int32 ``` Lets a thread release itself when it finishes, so nothing has to join it. **See also**: <https://man7.org/linux/man-pages/man3/pthread_detach.3.html>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Thread.rux#L63){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | --------- | --------------------------------------- | | `thread` | `PThread` | a thread nothing has joined or detached | **Returns**: zero, or an error number ## `pthread_attr_init` ```rux pub extern func pthread_attr_init(attributes: *var PThreadAttributes) -> int32 ``` Initializes thread attributes to the defaults. **See also**: <https://man7.org/linux/man-pages/man3/pthread_attr_init.3.html>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Thread.rux#L70){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------------ | ------------------------ | ------------------------- | | `attributes` | `*var PThreadAttributes` | the storage to initialize | **Returns**: zero, or an error number ## `pthread_attr_setstacksize` ```rux pub extern func pthread_attr_setstacksize( attributes: *var PThreadAttributes, size: uint ) -> int32 ``` Sets the stack size a thread started with these attributes gets. **See also**: <https://man7.org/linux/man-pages/man3/pthread_attr_setstacksize.3.html>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Thread.rux#L78){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------------ | ------------------------ | ------------------------------------------------------ | | `attributes` | `*var PThreadAttributes` | initialized attributes | | `size` | `uint` | the stack size in bytes, at least the system's minimum | **Returns**: zero, or an error number ## `pthread_attr_destroy` ```rux pub extern func pthread_attr_destroy(attributes: *var PThreadAttributes) -> int32 ``` Releases what [`pthread_attr_init`](https://rux-lang.dev/docs/api/linux/thread#pthread-attr-init) set up. **See also**: <https://man7.org/linux/man-pages/man3/pthread_attr_destroy.3.html>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Thread.rux#L85){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------------ | ------------------------ | ---------------------- | | `attributes` | `*var PThreadAttributes` | initialized attributes | **Returns**: zero, or an error number ## `gettid` ```rux pub extern func gettid() -> int32 ``` Returns the kernel's identifier for the calling thread, which is the process identifier on its first thread. **See also**: <https://man7.org/linux/man-pages/man2/gettid.2.html>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Thread.rux#L91){rel=""nofollow""} **Returns**: the calling thread's identifier ## `sched_yield` ```rux pub extern func sched_yield() -> int32 ``` Gives up the processor so another ready thread can run. **See also**: <https://man7.org/linux/man-pages/man2/sched_yield.2.html>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Thread.rux#L97){rel=""nofollow""} **Returns**: zero, or -1 with the reason in errno ## `sysconf` ```rux pub extern func sysconf(name: int32) -> int64 ``` Reads a system configuration value. **See also**: <https://man7.org/linux/man-pages/man3/sysconf.3.html>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Thread.rux#L104){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------ | ------- | ------------------------------------------------------------------------------------------------------------------ | | `name` | `int32` | the value to read, such as [`SC_NPROCESSORS_ONLN`](https://rux-lang.dev/docs/api/linux/thread#sc-nprocessors-onln) | **Returns**: the value, or -1 when the system has no limit or does not know the name # Clocks Reading clocks and sleeping. ## `ClockRealtime` ```rux pub const ClockRealtime: int32 = 0; ``` `CLOCK_REALTIME`: wall-clock time, which can jump when the system clock is set. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Clock.rux#L10){rel=""nofollow""} ## `ClockMonotonic` ```rux pub const ClockMonotonic: int32 = 1; ``` `CLOCK_MONOTONIC`: time since an unspecified point, which never goes backwards. Not comparable between boots, and not the clock to record a timestamp with. It is the one to measure a duration with, because setting the system clock cannot affect it. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Clock.rux#L16){rel=""nofollow""} ## `ClockGetTime` ```rux pub func ClockGetTime( clockId: int32, time: *var Timespec ) -> int64 ``` Reads `clockId` into `time`. `clockId` is read by value; `time` is borrowed and written. Returns zero, or a negative error number — [`EINVAL`](https://rux-lang.dev/docs/api/linux/errors#einval) for a clock this kernel does not have. `time` must be non-null and writable. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Clock.rux#L26){rel=""nofollow""} **Parameters** | Name | Type | Description | | --------- | --------------- | -------------------- | | `clockId` | `int32` | which clock to read | | `time` | `*var Timespec` | receives the reading | **Returns**: zero, or a negative error number ## `Nanosleep` ```rux pub func Nanosleep( request: *Timespec, remaining: *var Timespec ) -> int64 ``` Suspends the caller for the requested duration. `request` is borrowed and read; `remaining` is borrowed and written when the wait was cut short, and may be null when the caller does not care. Returns zero, or a negative error number. A signal interrupts the wait and reports [`EINTR`](https://rux-lang.dev/docs/api/linux/errors#eintr) with the unslept time in `remaining`, which is what makes the second argument worth passing: resuming means calling again with what came back, not with the original request. The wait is against [`ClockRealtime`](https://rux-lang.dev/docs/api/linux/clock#clock-realtime) but is not affected by the clock being set. `request` must be non-null, and its nanoseconds must be under one second or the call reports [`EINVAL`](https://rux-lang.dev/docs/api/linux/errors#einval). [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Clock.rux#L41){rel=""nofollow""} **Parameters** | Name | Type | Description | | ----------- | --------------- | --------------------------------------------------------------------------- | | `request` | `*Timespec` | how long to wait | | `remaining` | `*var Timespec` | receives the unslept time when a signal cut the wait short, and may be null | **Returns**: zero, or a negative error number ## `ClockProcessCpuTime` ```rux pub const ClockProcessCpuTime: int32 = 2; ``` `CLOCK_PROCESS_CPUTIME_ID`: processor time this process has used. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Clock.rux#L47){rel=""nofollow""} ## `ClockThreadCpuTime` ```rux pub const ClockThreadCpuTime: int32 = 3; ``` `CLOCK_THREAD_CPUTIME_ID`: processor time this thread has used. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Clock.rux#L51){rel=""nofollow""} ## `ClockMonotonicRaw` ```rux pub const ClockMonotonicRaw: int32 = 4; ``` `CLOCK_MONOTONIC_RAW`: like [`ClockMonotonic`](https://rux-lang.dev/docs/api/linux/clock#clock-monotonic), but not adjusted by time synchronization. Ticks at the hardware's own rate rather than a corrected one, which makes it the wrong clock for measuring a duration anyone will compare against a wall clock, and the right one for measuring the hardware. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Clock.rux#L57){rel=""nofollow""} ## `TimerAbsolute` ```rux pub const TimerAbsolute: int32 = 1; ``` `TIMER_ABSTIME`: [`ClockNanosleep`](https://rux-lang.dev/docs/api/linux/clock#clock-nanosleep) should treat its time as an absolute deadline. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Clock.rux#L61){rel=""nofollow""} ## `ClockGetResolution` ```rux pub func ClockGetResolution( clockId: int32, resolution: *var Timespec ) -> int64 ``` Reads the resolution of `clockId` into `resolution`. Returns zero, or a negative error number. The resolution is the granularity the clock advances by, which is not the cost of reading it and not a promise about accuracy. `resolution` must be non-null and writable. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Clock.rux#L71){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------------ | --------------- | ------------------------ | | `clockId` | `int32` | which clock to describe | | `resolution` | `*var Timespec` | receives the granularity | **Returns**: zero, or a negative error number ## `ClockNanosleep` ```rux pub func ClockNanosleep( clockId: int32, flags: int32, request: *Timespec, remaining: *var Timespec ) -> int64 ``` Suspends the caller against a named clock, optionally until an absolute time. `flags` is zero for a relative wait or [`TimerAbsolute`](https://rux-lang.dev/docs/api/linux/clock#timer-absolute) for a deadline. `remaining` is written only for a relative wait that a signal cut short, and may be null. Returns zero, or a positive error number — this one call reports its error positively rather than negatively, which is the kernel's inconsistency and not this binding's. An absolute wait is what a loop should use: a relative wait restarted after a signal drifts, because the time spent handling the signal is not counted. `request` must be non-null. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Clock.rux#L88){rel=""nofollow""} **Parameters** | Name | Type | Description | | ----------- | --------------- | ----------------------------------------------------------------------------------------------------------------------- | | `clockId` | `int32` | which clock to wait against | | `flags` | `int32` | zero for a relative wait, or [`TimerAbsolute`](https://rux-lang.dev/docs/api/linux/clock#timer-absolute) for a deadline | | `request` | `*Timespec` | how long to wait, or when to wake | | `remaining` | `*var Timespec` | receives the unslept time for a relative wait, and may be null | **Returns**: zero, or a positive error number # Dynamic loading The mode flags [`dlopen`](https://rux-lang.dev/docs/api/linux/dynamic#dlopen) takes. ## `RTLD_LAZY` ```rux pub const RTLD_LAZY: int32 = 1; ``` `RTLD_LAZY`: resolve a function symbol the first time it is called rather than at load. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Dynamic.rux#L15){rel=""nofollow""} ## `RTLD_NOW` ```rux pub const RTLD_NOW: int32 = 2; ``` `RTLD_NOW`: resolve every symbol before [`dlopen`](https://rux-lang.dev/docs/api/linux/dynamic#dlopen) returns, so a missing one is reported there. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Dynamic.rux#L20){rel=""nofollow""} ## `RTLD_GLOBAL` ```rux pub const RTLD_GLOBAL: int32 = 256; ``` `RTLD_GLOBAL`: make this object's symbols available to objects loaded afterwards. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Dynamic.rux#L25){rel=""nofollow""} ## `RTLD_LOCAL` ```rux pub const RTLD_LOCAL: int32 = 0; ``` `RTLD_LOCAL`: keep this object's symbols to itself, which is the default. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Dynamic.rux#L30){rel=""nofollow""} ## `RTLD_NODELETE` ```rux pub const RTLD_NODELETE: int32 = 4096; ``` `RTLD_NODELETE`: do not unload the object when its last reference goes, so its storage stays valid. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Dynamic.rux#L35){rel=""nofollow""} ## `dlopen` ```rux pub extern func dlopen( filename: *char8, flags: int32 ) -> *var opaque ``` Loads a shared object and returns a handle to it, or null on failure. A name without a slash is resolved by the loader's own search rules, and one with a slash as a path. A second call for an object already loaded returns the same handle and raises its reference count rather than loading it twice. Failure is reported through [`dlerror`](https://rux-lang.dev/docs/api/linux/dynamic#dlerror), not errno. **See also**: <https://man7.org/linux/man-pages/man3/dlopen.3.html>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Dynamic.rux#L48){rel=""nofollow""} **Parameters** | Name | Type | Description | | ---------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `filename` | `*char8` | a NUL-terminated name or path, or null for the main program | | `flags` | `int32` | [`RTLD_LAZY`](https://rux-lang.dev/docs/api/linux/dynamic#rtld-lazy) or [`RTLD_NOW`](https://rux-lang.dev/docs/api/linux/dynamic#rtld-now), combined with the other `RTLD_*` flags | **Returns**: a handle for [`dlsym`](https://rux-lang.dev/docs/api/linux/dynamic#dlsym) and [`dlclose`](https://rux-lang.dev/docs/api/linux/dynamic#dlclose), or null with the reason in [`dlerror`](https://rux-lang.dev/docs/api/linux/dynamic#dlerror) ## `dlsym` ```rux pub extern func dlsym( handle: *var opaque, symbol: *char8 ) -> *var opaque ``` Finds a symbol in a loaded object and returns its address, or null. A null return is ambiguous, since a symbol whose address is legitimately zero exists. Clear [`dlerror`](https://rux-lang.dev/docs/api/linux/dynamic#dlerror) by calling it, then call this, then read [`dlerror`](https://rux-lang.dev/docs/api/linux/dynamic#dlerror) again to tell the two apart. **See also**: <https://man7.org/linux/man-pages/man3/dlsym.3.html>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Dynamic.rux#L58){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | ------------- | ---------------------------------------------------------------------------- | | `handle` | `*var opaque` | a handle from [`dlopen`](https://rux-lang.dev/docs/api/linux/dynamic#dlopen) | | `symbol` | `*char8` | the NUL-terminated symbol name | **Returns**: the symbol's address, or null ## `dlclose` ```rux pub extern func dlclose(handle: *var opaque) -> int32 ``` Drops one reference to a loaded object, unloading it when the last one goes. Every address obtained from the object through [`dlsym`](https://rux-lang.dev/docs/api/linux/dynamic#dlsym) becomes invalid once it is actually unloaded, which this gives no way to observe. **See also**: <https://man7.org/linux/man-pages/man3/dlclose.3.html>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Dynamic.rux#L67){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | ------------- | ---------------------------------------------------------------------------- | | `handle` | `*var opaque` | a handle from [`dlopen`](https://rux-lang.dev/docs/api/linux/dynamic#dlopen) | **Returns**: zero on success, and non-zero with the reason in [`dlerror`](https://rux-lang.dev/docs/api/linux/dynamic#dlerror) ## `dlerror` ```rux pub extern func dlerror() -> *char8 ``` Reports the most recent loader error and clears it, or returns null when there is none. The message points at storage the loader owns and a later call may reuse. Reading it clears the error, so two calls in a row report the second as no error at all. **See also**: <https://man7.org/linux/man-pages/man3/dlerror.3.html>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Dynamic.rux#L75){rel=""nofollow""} **Returns**: a NUL-terminated message, or null # Errors The error numbers, and telling a raw result from an error. ## `EPERM` ```rux pub const EPERM: int64 = 1; ``` `EPERM`: the operation is not permitted to this caller. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Errors.rux#L15){rel=""nofollow""} ## `ENOENT` ```rux pub const ENOENT: int64 = 2; ``` `ENOENT`: no such file or directory. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Errors.rux#L20){rel=""nofollow""} ## `ESRCH` ```rux pub const ESRCH: int64 = 3; ``` `ESRCH`: no such process. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Errors.rux#L25){rel=""nofollow""} ## `EINTR` ```rux pub const EINTR: int64 = 4; ``` `EINTR`: the call was interrupted by a signal before it did anything. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Errors.rux#L30){rel=""nofollow""} ## `EIO` ```rux pub const EIO: int64 = 5; ``` `EIO`: a low-level input or output error. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Errors.rux#L35){rel=""nofollow""} ## `ENXIO` ```rux pub const ENXIO: int64 = 6; ``` `ENXIO`: no such device or address. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Errors.rux#L40){rel=""nofollow""} ## `EBADF` ```rux pub const EBADF: int64 = 9; ``` `EBADF`: the file descriptor is not open, or is not open for what was asked. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Errors.rux#L45){rel=""nofollow""} ## `EAGAIN` ```rux pub const EAGAIN: int64 = 11; ``` `EAGAIN`: the operation would block, and the descriptor was set not to. Spelled `EWOULDBLOCK` in some interfaces; on Linux the two are one value. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Errors.rux#L51){rel=""nofollow""} ## `ENOMEM` ```rux pub const ENOMEM: int64 = 12; ``` `ENOMEM`: not enough memory to satisfy the request. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Errors.rux#L56){rel=""nofollow""} ## `EACCES` ```rux pub const EACCES: int64 = 13; ``` `EACCES`: permission denied. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Errors.rux#L61){rel=""nofollow""} ## `EFAULT` ```rux pub const EFAULT: int64 = 14; ``` `EFAULT`: an address the call was given is outside the caller's address space. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Errors.rux#L66){rel=""nofollow""} ## `EBUSY` ```rux pub const EBUSY: int64 = 16; ``` `EBUSY`: the resource is in use. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Errors.rux#L71){rel=""nofollow""} ## `EEXIST` ```rux pub const EEXIST: int64 = 17; ``` `EEXIST`: the file already exists. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Errors.rux#L76){rel=""nofollow""} ## `EXDEV` ```rux pub const EXDEV: int64 = 18; ``` `EXDEV`: the two paths are on different file systems. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Errors.rux#L81){rel=""nofollow""} ## `ENOTDIR` ```rux pub const ENOTDIR: int64 = 20; ``` `ENOTDIR`: a path component that had to be a directory is not one. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Errors.rux#L86){rel=""nofollow""} ## `EISDIR` ```rux pub const EISDIR: int64 = 21; ``` `EISDIR`: the target is a directory and the operation is not one a directory accepts. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Errors.rux#L91){rel=""nofollow""} ## `EINVAL` ```rux pub const EINVAL: int64 = 22; ``` `EINVAL`: an argument is not valid. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Errors.rux#L96){rel=""nofollow""} ## `EMFILE` ```rux pub const EMFILE: int64 = 24; ``` `EMFILE`: this process has too many descriptors open. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Errors.rux#L101){rel=""nofollow""} ## `ENOSPC` ```rux pub const ENOSPC: int64 = 28; ``` `ENOSPC`: the device has no room left. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Errors.rux#L106){rel=""nofollow""} ## `ESPIPE` ```rux pub const ESPIPE: int64 = 29; ``` `ESPIPE`: the descriptor is a pipe or socket and cannot be seeked. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Errors.rux#L111){rel=""nofollow""} ## `EROFS` ```rux pub const EROFS: int64 = 30; ``` `EROFS`: the file system is mounted read-only. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Errors.rux#L116){rel=""nofollow""} ## `EPIPE` ```rux pub const EPIPE: int64 = 32; ``` `EPIPE`: the reading end of the pipe is closed. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Errors.rux#L121){rel=""nofollow""} ## `ENAMETOOLONG` ```rux pub const ENAMETOOLONG: int64 = 36; ``` `ENAMETOOLONG`: the path or a component of it is too long. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Errors.rux#L126){rel=""nofollow""} ## `ENOSYS` ```rux pub const ENOSYS: int64 = 38; ``` `ENOSYS`: the kernel does not implement this call. What an architecture that lacks a call reports, which is how a caller falls back to another. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Errors.rux#L132){rel=""nofollow""} ## `ELOOP` ```rux pub const ELOOP: int64 = 40; ``` `ELOOP`: too many symbolic links were followed resolving the path. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Errors.rux#L137){rel=""nofollow""} ## `EOVERFLOW` ```rux pub const EOVERFLOW: int64 = 75; ``` `EOVERFLOW`: a value is too large for the type the call reports it in. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Errors.rux#L142){rel=""nofollow""} ## `ETIMEDOUT` ```rux pub const ETIMEDOUT: int64 = 110; ``` `ETIMEDOUT`: the operation timed out. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Errors.rux#L147){rel=""nofollow""} ## `MaximumErrno` ```rux pub const MaximumErrno: int64 = 4095; ``` The largest error number the kernel's reserved range holds. A raw result below `-MaximumErrno` is a value, not an error. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Errors.rux#L152){rel=""nofollow""} ## `IsError` ```rux pub func IsError(result: int64) -> bool ``` Whether a raw system-call result is one of the kernel's reserved error values. `result` is read by value. True for `-4095` through `-1`, and false for everything else, including every valid mapping address a memory call returns. Cannot fail. Runs in constant time and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Errors.rux#L161){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | ------- | ---------------------- | | `result` | `int64` | the raw result to test | **Returns**: whether it is one of the reserved error values ## `Errno` ```rux pub func Errno(result: int64) -> int64 ``` The error number a raw system-call result carries, or zero when it carries none. `result` is read by value; the number is returned by copy, positive, as a man page names it. A successful result gives zero, which is not an error number and never collides with one. Cannot fail. Runs in constant time and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Errors.rux#L172){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | ------- | ---------------------- | | `result` | `int64` | the raw result to read | **Returns**: the error number, positive, or zero when the result carries none # Files Opening, reading, writing and inspecting files through descriptors. ## `StdIn` ```rux pub const StdIn: int32 = 0; ``` The descriptor a process reads its input from, unless something reassigned it. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/File.rux#L14){rel=""nofollow""} ## `StdOut` ```rux pub const StdOut: int32 = 1; ``` The descriptor a process writes its output to. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/File.rux#L18){rel=""nofollow""} ## `StdErr` ```rux pub const StdErr: int32 = 2; ``` The descriptor a process writes its diagnostics to, which is separate so it survives a redirected output. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/File.rux#L22){rel=""nofollow""} ## `Read` ```rux pub func Read( fd: FileDescriptor, buffer: *var opaque, count: uint ) -> int64 ``` Reads up to `count` bytes from `fd` into `buffer`. `fd` and `count` are read by value; `buffer` is borrowed and written. Returns the number of bytes actually read, zero at end of file, or a negative error number. A count smaller than `count` is ordinary and is not an end of file: a pipe, a terminal, or a signal can each cut a read short. Only zero means the source has ended. `buffer` must be writable for `count` bytes. The kernel checks the address and reports [`EFAULT`](https://rux-lang.dev/docs/api/linux/errors#efault) rather than faulting, but it does not check the length against anything the caller knows. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/File.rux#L36){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | ---------------- | ------------------------- | | `fd` | `FileDescriptor` | an open descriptor | | `buffer` | `*var opaque` | receives the bytes | | `count` | `uint` | how many bytes to ask for | **Returns**: the bytes read, zero at end of file, or a negative error number ## `Write` ```rux pub func Write( fd: FileDescriptor, buffer: *opaque, count: uint ) -> int64 ``` Writes up to `count` bytes from `buffer` to `fd`. `fd` and `count` are read by value; `buffer` is borrowed and read. Returns the number of bytes actually written, or a negative error number. A count smaller than `count` is ordinary, and the rest has to be written by calling again from where this stopped. Writing to a pipe whose reader has closed raises `SIGPIPE` before this can report [`EPIPE`](https://rux-lang.dev/docs/api/linux/errors#epipe). `buffer` must be readable for `count` bytes. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/File.rux#L51){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | ---------------- | ----------------------- | | `fd` | `FileDescriptor` | an open descriptor | | `buffer` | `*opaque` | the bytes to write | | `count` | `uint` | how many bytes to offer | **Returns**: the bytes written, or a negative error number ## `Close` ```rux pub func Close(fd: FileDescriptor) -> int64 ``` Closes `fd` and releases what the kernel held for it. `fd` is read by value. Returns zero, or a negative error number. A failure does not mean the descriptor is still open: on Linux it is released whatever this reports, so retrying a failed close can close a descriptor another thread has since opened under the same number. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/File.rux#L62){rel=""nofollow""} **Parameters** | Name | Type | Description | | ---- | ---------------- | ------------------ | | `fd` | `FileDescriptor` | an open descriptor | **Returns**: zero, or a negative error number ## `AtFdCwd` ```rux pub const AtFdCwd: int32 = -100; ``` `AT_FDCWD`: resolve a relative path against the current directory rather than a descriptor. The value every `*at` call takes when the caller means an ordinary path. It is `-100` rather than `-1` so that a stray `-1` from a failed open cannot be mistaken for it. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/File.rux#L70){rel=""nofollow""} ## `OpenReadOnly` ```rux pub const OpenReadOnly: int32 = 0; ``` `O_RDONLY`: open for reading only. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/File.rux#L74){rel=""nofollow""} ## `OpenWriteOnly` ```rux pub const OpenWriteOnly: int32 = 1; ``` `O_WRONLY`: open for writing only. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/File.rux#L78){rel=""nofollow""} ## `OpenReadWrite` ```rux pub const OpenReadWrite: int32 = 2; ``` `O_RDWR`: open for both reading and writing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/File.rux#L82){rel=""nofollow""} ## `OpenCreate` ```rux pub const OpenCreate: int32 = 64; ``` `O_CREAT`: create the file when it does not exist, which is when the mode argument is read. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/File.rux#L86){rel=""nofollow""} ## `OpenExclusive` ```rux pub const OpenExclusive: int32 = 128; ``` `O_EXCL`: with [`OpenCreate`](https://rux-lang.dev/docs/api/linux/files#open-create), fail rather than open a file that already exists. The pair is what makes creating a file an atomic claim on the name. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/File.rux#L91){rel=""nofollow""} ## `OpenTruncate` ```rux pub const OpenTruncate: int32 = 512; ``` `O_TRUNC`: truncate the file to nothing when opening it for writing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/File.rux#L95){rel=""nofollow""} ## `OpenAppend` ```rux pub const OpenAppend: int32 = 1024; ``` `O_APPEND`: every write goes to the end, atomically with respect to other appenders. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/File.rux#L99){rel=""nofollow""} ## `OpenNonBlocking` ```rux pub const OpenNonBlocking: int32 = 2048; ``` [`O_NONBLOCK`](https://rux-lang.dev/docs/api/linux/poll#o-nonblock): reads and writes report [`EAGAIN`](https://rux-lang.dev/docs/api/linux/errors#eagain) rather than waiting. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/File.rux#L103){rel=""nofollow""} ## `OpenCloseOnExec` ```rux pub const OpenCloseOnExec: int32 = 524288; ``` `O_CLOEXEC`: close this descriptor automatically when the process executes a new program. Worth setting on nearly everything: without it a descriptor leaks into every child, which is both a resource and a confidentiality problem. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/File.rux#L109){rel=""nofollow""} ## `OpenDirectory` ```rux // x86-64 pub const OpenDirectory: int32 = 65536; // AArch64 pub const OpenDirectory: int32 = 16384; ``` `O_DIRECTORY`: fail unless the target is a directory. x86-64 kept the number it had before the generic table was drawn up. On AArch64 this same bit means `O_DIRECT` instead, so a directory opened with the wrong number fails with [`EINVAL`](https://rux-lang.dev/docs/api/linux/errors#einval) rather than opening. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/File.rux#L119){rel=""nofollow""} ## `SeekSet` ```rux pub const SeekSet: int32 = 0; ``` `SEEK_SET`: measure the new offset from the start of the file. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/File.rux#L133){rel=""nofollow""} ## `SeekCurrent` ```rux pub const SeekCurrent: int32 = 1; ``` `SEEK_CUR`: measure the new offset from the current one. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/File.rux#L137){rel=""nofollow""} ## `SeekEnd` ```rux pub const SeekEnd: int32 = 2; ``` `SEEK_END`: measure the new offset from the end of the file. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/File.rux#L141){rel=""nofollow""} ## `OpenAt` ```rux pub func OpenAt( directoryFd: FileDescriptor, path: *char8, flags: int32, mode: FileMode ) -> int64 ``` Opens `path` relative to `directoryFd` and returns a descriptor, or a negative error number. `directoryFd` is a descriptor for the directory a relative path is resolved against, or [`AtFdCwd`](https://rux-lang.dev/docs/api/linux/files#at-fd-cwd) for the current one; an absolute path ignores it. `path` is borrowed and must be null-terminated. `flags` is one of the three access modes combined with whatever else applies. `mode` is the permission bits a newly created file gets, and is read only when [`OpenCreate`](https://rux-lang.dev/docs/api/linux/files#open-create) is set. This is the only open the package offers, because it is the only one AArch64 has. `path` must be non-null and terminated. The mode is masked by the process umask, which this cannot see. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/File.rux#L156){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------------- | ---------------- | ----------------------------------------------------------------------------------------------------------------------------- | | `directoryFd` | `FileDescriptor` | the directory `path` is relative to, or [`AtFdCwd`](https://rux-lang.dev/docs/api/linux/files#at-fd-cwd) for an ordinary path | | `path` | `*char8` | the path to open, as a null-terminated byte string | | `flags` | `int32` | the access mode and the open flags, combined with `|` | | `mode` | `FileMode` | the permission bits for a file this creates, ignored otherwise | **Returns**: the new descriptor, or a negative error number ## `Lseek` ```rux pub func Lseek( fd: FileDescriptor, offset: FileOffset, whence: int32 ) -> int64 ``` Moves the file offset of `fd` and returns where it ended up, or a negative error number. `offset` is measured from whichever origin `whence` names. Returns the resulting absolute offset. Seeking past the end is allowed and creates a hole when something is later written there. A pipe or socket has no offset to move and reports [`ESPIPE`](https://rux-lang.dev/docs/api/linux/errors#espipe). [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/File.rux#L170){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | ---------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `fd` | `FileDescriptor` | an open descriptor | | `offset` | `FileOffset` | how far to move, interpreted according to `whence` | | `whence` | `int32` | [`SeekSet`](https://rux-lang.dev/docs/api/linux/files#seek-set), [`SeekCurrent`](https://rux-lang.dev/docs/api/linux/files#seek-current) or [`SeekEnd`](https://rux-lang.dev/docs/api/linux/files#seek-end) | **Returns**: the resulting offset from the start, or a negative error number ## `FstatAt` ```rux pub func FstatAt( directoryFd: FileDescriptor, path: *char8, statBuffer: *var opaque, flags: int32 ) -> int64 ``` Fills `statBuffer` with what the kernel knows about the file `path` names. The kernel's own name for this call is `newfstatat`, which `SysNewFstatAt` keeps; the wrapper is spelled the way macOS and FreeBSD spell theirs, so one name reaches the call on all three systems. `statBuffer` must be writable for the whole of the architecture's `struct stat`, whose layout this package does not model: 144 bytes on x86-64 and 128 on AArch64, with the fields at different offsets in each. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/File.rux#L235){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------------- | ---------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `directoryFd` | `FileDescriptor` | the directory `path` is relative to, or [`AtFdCwd`](https://rux-lang.dev/docs/api/linux/files#at-fd-cwd) for an ordinary path | | `path` | `*char8` | the path to describe, as a null-terminated byte string | | `statBuffer` | `*var opaque` | receives the architecture's `struct stat` | | `flags` | `int32` | zero to follow a symbolic link at the end of the path, or [`SymlinkNoFollow`](https://rux-lang.dev/docs/api/linux/directories#symlink-no-follow) to describe the link | **Returns**: zero, or a negative error number ## `FchmodAt` ```rux pub func FchmodAt( directoryFd: FileDescriptor, path: *char8, mode: FileMode, flags: int32 ) -> int64 ``` Sets the permission bits of the file `path` names. `directoryFd` is [`AtFdCwd`](https://rux-lang.dev/docs/api/linux/files#at-fd-cwd) for an ordinary path. Returns zero, or a negative error number. Linux does not support [`SymlinkNoFollow`](https://rux-lang.dev/docs/api/linux/directories#symlink-no-follow) here and reports `EOPNOTSUPP` for it: a symbolic link's own bits mean nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/File.rux#L249){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------------- | ---------------- | ----------------------------------------------------------------------------------------------------------------------------- | | `directoryFd` | `FileDescriptor` | the directory `path` is relative to, or [`AtFdCwd`](https://rux-lang.dev/docs/api/linux/files#at-fd-cwd) for an ordinary path | | `path` | `*char8` | the path whose bits are set | | `mode` | `FileMode` | the permission bits to set | | `flags` | `int32` | zero, or [`SymlinkNoFollow`](https://rux-lang.dev/docs/api/linux/directories#symlink-no-follow) where the system supports it | **Returns**: zero, or a negative error number ## `UtimensAt` ```rux pub func UtimensAt( directoryFd: FileDescriptor, path: *char8, times: *opaque, flags: int32 ) -> int64 ``` Sets the access and modification times of the file `path` names. `times` is borrowed and holds two `timespec` values — access first, then modification — each a whole-second count and a nanosecond fraction, both 8 bytes. A null `times` sets both to now. `flags` may carry [`SymlinkNoFollow`](https://rux-lang.dev/docs/api/linux/directories#symlink-no-follow). Returns zero, or a negative error number. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/File.rux#L264){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------------- | ---------------- | ------------------------------------------------------------------------------------------------------------------------------- | | `directoryFd` | `FileDescriptor` | the directory `path` is relative to, or [`AtFdCwd`](https://rux-lang.dev/docs/api/linux/files#at-fd-cwd) for an ordinary path | | `path` | `*char8` | the path whose times are set | | `times` | `*opaque` | two `timespec` values, or null for now | | `flags` | `int32` | zero to follow a final symbolic link, or [`SymlinkNoFollow`](https://rux-lang.dev/docs/api/linux/directories#symlink-no-follow) | **Returns**: zero, or a negative error number ## `Fsync` ```rux pub func Fsync(fd: FileDescriptor) -> int64 ``` Flushes everything written to `fd` through to the storage device. Returns zero, or a negative error number. Returning only once the device has acknowledged the write is the whole point: without it, data a successful [`Write`](https://rux-lang.dev/docs/api/linux/files#write) reported may still be lost to a power failure. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/File.rux#L311){rel=""nofollow""} **Parameters** | Name | Type | Description | | ---- | ---------------- | ------------------ | | `fd` | `FileDescriptor` | an open descriptor | **Returns**: zero, or a negative error number ## `Ftruncate` ```rux pub func Ftruncate( fd: FileDescriptor, length: FileOffset ) -> int64 ``` Sets the length of the file behind `fd` to `length`. Returns zero, or a negative error number. Growing a file this way creates a hole rather than allocating, so a later write into it can still fail with [`ENOSPC`](https://rux-lang.dev/docs/api/linux/errors#enospc). Shrinking discards what was past the new end. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/File.rux#L322){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | ---------------- | ---------------------------------------- | | `fd` | `FileDescriptor` | an open descriptor | | `length` | `FileOffset` | the size the file should have afterwards | **Returns**: zero, or a negative error number ## `Fstat` ```rux pub func Fstat( fd: FileDescriptor, statBuffer: *var opaque ) -> int64 ``` Fills `statBuffer` with what the kernel knows about the file behind `fd`. `statBuffer` is borrowed and written with the kernel's `struct stat`, whose layout this package does not model: it differs by architecture, and reading it needs a declaration that says which. Returns zero, or a negative error number. `statBuffer` must be writable for the whole of the architecture's `struct stat`, which is 144 bytes on x86-64 and 128 on AArch64. Nothing here checks that. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/File.rux#L384){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------------ | ---------------- | ----------------------------------------- | | `fd` | `FileDescriptor` | an open descriptor | | `statBuffer` | `*var opaque` | receives the architecture's `struct stat` | **Returns**: zero, or a negative error number ## `Dup3` ```rux pub func Dup3( oldFd: FileDescriptor, newFd: FileDescriptor, flags: int32 ) -> int64 ``` Makes `newFd` a copy of `oldFd`, closing whatever `newFd` was. `flags` may carry [`OpenCloseOnExec`](https://rux-lang.dev/docs/api/linux/files#open-close-on-exec), which is the reason this exists rather than `dup2`: setting it afterwards leaves a window in which another thread can execute a new program and leak the descriptor. Returns `newFd`, or a negative error number. Duplicating a descriptor onto itself reports [`EINVAL`](https://rux-lang.dev/docs/api/linux/errors#einval) here, where `dup2` returned it unchanged. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/File.rux#L398){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------- | ---------------- | ----------------------------------------------------------------------------------------------------------------- | | `oldFd` | `FileDescriptor` | the descriptor to duplicate | | `newFd` | `FileDescriptor` | the number the duplicate should have | | `flags` | `int32` | zero, or [`OpenCloseOnExec`](https://rux-lang.dev/docs/api/linux/files#open-close-on-exec) for the new descriptor | **Returns**: `newFd`, or a negative error number ## `Pipe2` ```rux pub func Pipe2( descriptors: *var int32, flags: int32 ) -> int64 ``` Creates a pipe and writes its two descriptors into `descriptors`. `descriptors` is borrowed and receives the reading end at index zero and the writing end at index one. `flags` may carry [`OpenCloseOnExec`](https://rux-lang.dev/docs/api/linux/files#open-close-on-exec) and [`OpenNonBlocking`](https://rux-lang.dev/docs/api/linux/files#open-non-blocking). Returns zero, or a negative error number. `descriptors` must be writable for two `int32` values. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/File.rux#L410){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------------- | ------------ | -------------------------------------------------------------------------------------------------------- | | `descriptors` | `*var int32` | receives the read end at index zero and the write end at index one | | `flags` | `int32` | zero, or [`OpenCloseOnExec`](https://rux-lang.dev/docs/api/linux/files#open-close-on-exec) for both ends | **Returns**: zero, or a negative error number # Futexes Waiting on a word and waking its waiters through `futex`. ## `FutexWaitPrivate` ```rux pub const FutexWaitPrivate: int32 = 128; ``` `FUTEX_WAIT_PRIVATE`: sleep while the word holds the expected value. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Futex.rux#L21){rel=""nofollow""} ## `FutexWakePrivate` ```rux pub const FutexWakePrivate: int32 = 129; ``` `FUTEX_WAKE_PRIVATE`: wake threads sleeping on the word. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Futex.rux#L25){rel=""nofollow""} ## `FutexWait` ```rux pub func FutexWait( address: *uint32, expected: uint32, timeout: *Timespec ) -> int64 ``` Sleeps while `*address` equals `expected`, until a wake, a signal or the timeout. Returns at once with `-EAGAIN` when the word already differs, which is how a caller learns it changed. **See also**: <https://man7.org/linux/man-pages/man2/futex.2.html>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Futex.rux#L35){rel=""nofollow""} **Parameters** | Name | Type | Description | | ---------- | ----------- | -------------------------------------------------------------------------- | | `address` | `*uint32` | the word to wait on, four-byte aligned | | `expected` | `uint32` | the value the caller last saw there | | `timeout` | `*Timespec` | how long to wait at most, relative to now, or null to wait without a limit | **Returns**: zero after a wake, or a negative error number: [`EAGAIN`](https://rux-lang.dev/docs/api/linux/errors#eagain), [`EINTR`](https://rux-lang.dev/docs/api/linux/errors#eintr) or [`ETIMEDOUT`](https://rux-lang.dev/docs/api/linux/errors#etimedout) ## `FutexWake` ```rux pub func FutexWake(address: *uint32, count: int32) -> int64 ``` Wakes up to `count` threads sleeping on `address`. **See also**: <https://man7.org/linux/man-pages/man2/futex.2.html>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Futex.rux#L46){rel=""nofollow""} **Parameters** | Name | Type | Description | | --------- | --------- | ------------------------ | | `address` | `*uint32` | the word they wait on | | `count` | `int32` | how many to wake at most | **Returns**: how many were woken, or a negative error number # Memory Mapping, protecting and advising on pages of memory. ## `ProtectionNone` ```rux pub const ProtectionNone: int32 = 0; ``` `PROT_NONE`: the pages may not be touched at all. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Memory.rux#L11){rel=""nofollow""} ## `ProtectionRead` ```rux pub const ProtectionRead: int32 = 1; ``` `PROT_READ`: the pages may be read. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Memory.rux#L15){rel=""nofollow""} ## `ProtectionWrite` ```rux pub const ProtectionWrite: int32 = 2; ``` `PROT_WRITE`: the pages may be written. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Memory.rux#L19){rel=""nofollow""} ## `ProtectionExecute` ```rux pub const ProtectionExecute: int32 = 4; ``` `PROT_EXEC`: the pages may be executed. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Memory.rux#L23){rel=""nofollow""} ## `MapShared` ```rux pub const MapShared: int32 = 1; ``` `MAP_SHARED`: writes are visible to other mappings of the same object and reach it. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Memory.rux#L27){rel=""nofollow""} ## `MapPrivate` ```rux pub const MapPrivate: int32 = 2; ``` `MAP_PRIVATE`: writes are private to this mapping and never reach the object. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Memory.rux#L31){rel=""nofollow""} ## `MapFixed` ```rux pub const MapFixed: int32 = 16; ``` `MAP_FIXED`: place the mapping exactly at the requested address, replacing whatever was there. Dangerous by design: it silently unmaps anything already at the address, which may be someone else's mapping. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Memory.rux#L36){rel=""nofollow""} ## `MapAnonymous` ```rux pub const MapAnonymous: int32 = 32; ``` `MAP_ANONYMOUS`: the mapping is backed by zeroed pages rather than by a file. The descriptor argument is then unused and is conventionally `-1`. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Memory.rux#L41){rel=""nofollow""} ## `Mmap` ```rux pub func Mmap( address: *opaque, length: uint, protection: int32, flags: int32, fd: int32, offset: uint64 ) -> int64 ``` Creates a mapping and returns its address, or a negative error number. `address` is a hint unless [`MapFixed`](https://rux-lang.dev/docs/api/linux/memory#map-fixed) is set, and null asks the kernel to choose. `length` is rounded up to a whole number of pages. `fd` is the object to map, or `-1` with [`MapAnonymous`](https://rux-lang.dev/docs/api/linux/memory#map-anonymous). `offset` must be page-aligned. Returns the mapping's address as an integer. Testing it needs `Errors::IsError` rather than a sign test: a valid address may have its top bit set, and only the kernel's reserved `-4095` through `-1` range is a failure. The mapping outlives nothing on its own — it stays until [`Munmap`](https://rux-lang.dev/docs/api/linux/memory#munmap) releases it or the process ends. [`MapFixed`](https://rux-lang.dev/docs/api/linux/memory#map-fixed) replaces whatever occupies the address, including a mapping this program depends on. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Memory.rux#L58){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------------ | --------- | ------------------------------------------------------------------------------------------------------ | | `address` | `*opaque` | a hint for where to map, or null to let the kernel choose | | `length` | `uint` | how many bytes, rounded up to whole pages | | `protection` | `int32` | what may be done with the pages, as `Protection*` flags | | `flags` | `int32` | the mapping flags, as `Map*` values | | `fd` | `int32` | the file to map, or -1 with [`MapAnonymous`](https://rux-lang.dev/docs/api/linux/memory#map-anonymous) | | `offset` | `uint64` | where in the file the mapping starts | **Returns**: the mapping's address, or a negative error number ## `Munmap` ```rux pub func Munmap(address: *opaque, length: uint) -> int64 ``` Releases the mapping that begins at `address` and spans `length` bytes. `address` must be page-aligned; `length` is rounded up to whole pages. Returns zero, or a negative error number. Releasing a range that was never mapped succeeds and does nothing, so this cannot be used to discover whether a range was mapped. Every pointer into the range becomes invalid, and the address space may be handed to a later mapping at once. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Memory.rux#L79){rel=""nofollow""} **Parameters** | Name | Type | Description | | --------- | --------- | -------------------------------------- | | `address` | `*opaque` | a page-aligned address to release from | | `length` | `uint` | how many bytes to release | **Returns**: zero, or a negative error number ## `Brk` ```rux pub func Brk(address: *opaque) -> int64 ``` Sets the program break and returns where it ended up. `address` is the requested new break, or null to ask where it is. Returns the resulting break, which is the old one when the request could not be met — this call reports failure by not moving rather than by an error number. The break is a single process-wide value. Anything else in the process that uses it, including a C runtime that was linked in, is using the same one. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Memory.rux#L91){rel=""nofollow""} **Parameters** | Name | Type | Description | | --------- | --------- | --------------------------------------------------- | | `address` | `*opaque` | where to move the program break, or null to read it | **Returns**: the resulting break, or a negative error number ## `AdviseDontNeed` ```rux pub const AdviseDontNeed: int32 = 4; ``` `MADV_DONTNEED`: the pages are not needed, and the kernel may discard them. An anonymous page discarded this way reads back as zero next time, which is how a range is released without giving up the address space. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Memory.rux#L99){rel=""nofollow""} ## `AdviseWillNeed` ```rux pub const AdviseWillNeed: int32 = 3; ``` `MADV_WILLNEED`: the pages will be read soon, so reading them ahead is worthwhile. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Memory.rux#L103){rel=""nofollow""} ## `AdviseRandom` ```rux pub const AdviseRandom: int32 = 1; ``` `MADV_RANDOM`: the pages will be touched in no useful order, so reading ahead is not. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Memory.rux#L107){rel=""nofollow""} ## `AdviseSequential` ```rux pub const AdviseSequential: int32 = 2; ``` `MADV_SEQUENTIAL`: the pages will be touched in order. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Memory.rux#L111){rel=""nofollow""} ## `Mprotect` ```rux pub func Mprotect( address: *opaque, length: uint, protection: int32 ) -> int64 ``` Changes what may be done with the pages covering `address` through `address + length`. `address` must be page-aligned; `length` is rounded up to whole pages. `protection` is the same set [`Mmap`](https://rux-lang.dev/docs/api/linux/memory#mmap) takes. Returns zero, or a negative error number. Removing a permission takes effect at once, so a thread touching the range concurrently faults rather than finishing what it started. Nothing here checks that the range was ever mapped, and marking executable memory writable at the same time is what a hardened system refuses. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Memory.rux#L125){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------------ | --------- | ----------------------------------------- | | `address` | `*opaque` | a page-aligned address | | `length` | `uint` | how many bytes, rounded up to whole pages | | `protection` | `int32` | what may be done with them afterwards | **Returns**: zero, or a negative error number ## `Madvise` ```rux pub func Madvise( address: *opaque, length: uint, advice: int32 ) -> int64 ``` Tells the kernel how the pages covering a range are about to be used. `address` must be page-aligned. Returns zero, or a negative error number. Advice is advice: the kernel is free to ignore all of it, with the exception of [`AdviseDontNeed`](https://rux-lang.dev/docs/api/linux/memory#advise-dont-need), which actually discards. [`AdviseDontNeed`](https://rux-lang.dev/docs/api/linux/memory#advise-dont-need) loses whatever the range held. On anonymous memory that is a zeroing; on a private file mapping it discards the modifications rather than writing them back. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Memory.rux#L139){rel=""nofollow""} **Parameters** | Name | Type | Description | | --------- | --------- | -------------------------------- | | `address` | `*opaque` | a page-aligned address | | `length` | `uint` | how many bytes the advice covers | | `advice` | `int32` | one of the `Advise*` values | **Returns**: zero, or a negative error number ## `AuxPageSize` ```rux pub const AuxPageSize: uint64 = 6; ``` `AT_PAGESZ`: the auxiliary-vector entry holding the page size, in bytes. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Memory.rux#L144){rel=""nofollow""} ## `AuxNull` ```rux pub const AuxNull: uint64 = 0; ``` `AT_NULL`: the entry that ends the auxiliary vector. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Memory.rux#L148){rel=""nofollow""} ## `QueryPageSize` ```rux pub func QueryPageSize() -> int64 ``` The size of a page, read out of this process's auxiliary vector. Linux publishes the page size in the auxiliary vector the kernel hands to a new process, not behind a system call. libc captures that vector at startup and answers from it, which is what `getauxval` reads; this package calls no libc and captures nothing at startup, so it asks the kernel for the same vector through the interface that exposes it as a file, `/proc/self/auxv`. The file is a sequence of `(type, value)` pairs of unsigned 64-bit words, ending at a type of [`AuxNull`](https://rux-lang.dev/docs/api/linux/memory#aux-null). The cost is an open, a read and a close, so a caller needing the size more than once should keep it rather than ask again. Reports the open's or the read's own error number when `/proc` is not mounted or not readable, which is ordinary in a container built without it. Reports `-ENOENT` when the vector was readable but held no [`AuxPageSize`](https://rux-lang.dev/docs/api/linux/memory#aux-page-size) entry, and `-EINVAL` when it held one that is not a size the address space could have. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Memory.rux#L163){rel=""nofollow""} **Returns**: the page size in bytes, or a negative error number # Polling Descriptor flags and the epoll calls a poller waits with. ## `EpollEventBytes` ```rux // x86-64 pub const EpollEventBytes: uint = 12; // AArch64 pub const EpollEventBytes: uint = 16; ``` The size of one `epoll_event` in bytes: its four-byte event mask, padding, and eight-byte word. | Overload | Summary | | --------------------------------------- | ----------------------------------------------------------------------------------------------- | | `pub const EpollEventBytes: uint = 12;` | The size of one `epoll_event` in bytes: its four-byte event mask and eight-byte word, packed. | | `pub const EpollEventBytes: uint = 16;` | The size of one `epoll_event` in bytes: its four-byte event mask, padding, and eight-byte word. | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Poll.rux#L20){rel=""nofollow""} ## `EpollEventWordOffset` ```rux // x86-64 pub const EpollEventWordOffset: uint = 4; // AArch64 pub const EpollEventWordOffset: uint = 8; ``` Where the caller's word starts in an `epoll_event`. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Poll.rux#L24){rel=""nofollow""} ## `F_GETFL` ```rux pub const F_GETFL: int32 = 3; ``` `F_GETFL`: the [`fcntl`](https://rux-lang.dev/docs/api/linux/spawn#fcntl) command that reads a descriptor's status flags. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Poll.rux#L46){rel=""nofollow""} ## `F_SETFL` ```rux pub const F_SETFL: int32 = 4; ``` `F_SETFL`: the [`fcntl`](https://rux-lang.dev/docs/api/linux/spawn#fcntl) command that sets a descriptor's status flags. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Poll.rux#L51){rel=""nofollow""} ## `O_NONBLOCK` ```rux pub const O_NONBLOCK: int32 = 0x800; ``` `O_NONBLOCK`: the status flag that makes a call fail with [`EAGAIN`](https://rux-lang.dev/docs/api/linux/errors#eagain) rather than wait. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Poll.rux#L56){rel=""nofollow""} ## `EPOLL_CLOEXEC` ```rux pub const EPOLL_CLOEXEC: int32 = 0x80000; ``` `EPOLL_CLOEXEC`: close the epoll descriptor when the process starts another program. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Poll.rux#L61){rel=""nofollow""} ## `EPOLL_CTL_ADD` ```rux pub const EPOLL_CTL_ADD: int32 = 1; ``` `EPOLL_CTL_ADD`: register a descriptor. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Poll.rux#L66){rel=""nofollow""} ## `EPOLL_CTL_DEL` ```rux pub const EPOLL_CTL_DEL: int32 = 2; ``` `EPOLL_CTL_DEL`: remove a descriptor's registration. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Poll.rux#L71){rel=""nofollow""} ## `EPOLL_CTL_MOD` ```rux pub const EPOLL_CTL_MOD: int32 = 3; ``` `EPOLL_CTL_MOD`: change a registered descriptor's events and word. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Poll.rux#L76){rel=""nofollow""} ## `EPOLLIN` ```rux pub const EPOLLIN: uint32 = 0x1; ``` `EPOLLIN`: there is something to read, or a connection to accept. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Poll.rux#L81){rel=""nofollow""} ## `EPOLLOUT` ```rux pub const EPOLLOUT: uint32 = 0x4; ``` `EPOLLOUT`: a write would not wait. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Poll.rux#L86){rel=""nofollow""} ## `EPOLLERR` ```rux pub const EPOLLERR: uint32 = 0x8; ``` `EPOLLERR`: the descriptor has an error pending; always reported. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Poll.rux#L91){rel=""nofollow""} ## `EPOLLHUP` ```rux pub const EPOLLHUP: uint32 = 0x10; ``` `EPOLLHUP`: the peer has closed the connection; always reported. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Poll.rux#L96){rel=""nofollow""} ## `EPOLLRDHUP` ```rux pub const EPOLLRDHUP: uint32 = 0x2000; ``` `EPOLLRDHUP`: the peer has shut down its writing side. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Poll.rux#L101){rel=""nofollow""} ## `FcntlInt` ```rux pub func FcntlInt( fd: FileDescriptor, command: int32, argument: int64 ) -> int64 ``` Performs `command` on a descriptor with an integer argument. **See also**: <https://man7.org/linux/man-pages/man2/fcntl.2.html>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Poll.rux#L110){rel=""nofollow""} **Parameters** | Name | Type | Description | | ---------- | ---------------- | -------------------------------------------------------------------------------------------------------------------------------------- | | `fd` | `FileDescriptor` | the descriptor | | `command` | `int32` | such as [`F_GETFL`](https://rux-lang.dev/docs/api/linux/poll#f-getfl) or [`F_SETFL`](https://rux-lang.dev/docs/api/linux/poll#f-setfl) | | `argument` | `int64` | the command's argument, or zero | **Returns**: the command's result, or a negative error number ## `EpollCreate1` ```rux pub func EpollCreate1(flags: int32) -> int64 ``` Opens an epoll instance. **See also**: <https://man7.org/linux/man-pages/man2/epoll_create1.2.html>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Poll.rux#L119){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------- | ------- | --------------------------------------------------------------------------------- | | `flags` | `int32` | zero or [`EPOLL_CLOEXEC`](https://rux-lang.dev/docs/api/linux/poll#epoll-cloexec) | **Returns**: the instance's descriptor, or a negative error number ## `EpollControl` ```rux pub func EpollControl( epoll: FileDescriptor, operation: int32, fd: FileDescriptor, event: *opaque ) -> int64 ``` Adds, changes or removes the registration of `fd` with an epoll instance. **See also**: <https://man7.org/linux/man-pages/man2/epoll_ctl.2.html>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Poll.rux#L132){rel=""nofollow""} **Parameters** | Name | Type | Description | | ----------- | ---------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `epoll` | `FileDescriptor` | the instance | | `operation` | `int32` | [`EPOLL_CTL_ADD`](https://rux-lang.dev/docs/api/linux/poll#epoll-ctl-add), [`EPOLL_CTL_MOD`](https://rux-lang.dev/docs/api/linux/poll#epoll-ctl-mod) or [`EPOLL_CTL_DEL`](https://rux-lang.dev/docs/api/linux/poll#epoll-ctl-del) | | `fd` | `FileDescriptor` | the descriptor registered | | `event` | `*opaque` | [`EpollEventBytes`](https://rux-lang.dev/docs/api/linux/poll#epoll-event-bytes) bytes: the event mask and, at [`EpollEventWordOffset`](https://rux-lang.dev/docs/api/linux/poll#epoll-event-word-offset), the word to report; ignored when removing | **Returns**: zero, or a negative error number ## `EpollWait` ```rux pub func EpollWait( epoll: FileDescriptor, events: *var opaque, capacity: int32, timeout: int32 ) -> int64 ``` Waits until a registered descriptor is ready or `timeout` milliseconds pass, filling `events` with what is ready. **See also**: <https://man7.org/linux/man-pages/man2/epoll_wait.2.html>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Poll.rux#L145){rel=""nofollow""} **Parameters** | Name | Type | Description | | ---------- | ---------------- | ------------------------------------------------------------------------------------------------------------------------ | | `epoll` | `FileDescriptor` | the instance | | `events` | `*var opaque` | room for `capacity` events of [`EpollEventBytes`](https://rux-lang.dev/docs/api/linux/poll#epoll-event-bytes) bytes each | | `capacity` | `int32` | how many events fit | | `timeout` | `int32` | milliseconds to wait, zero to only look, or -1 to wait without end | **Returns**: how many events were filled, zero after the timeout, or a negative error number # Sockets Address families, socket types and options, and the calls that open, bind and connect sockets. ## `AF_INET` ```rux pub const AF_INET: int32 = 2; ``` `AF_INET`: the IPv4 address family. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Socket.rux#L41){rel=""nofollow""} ## `AF_INET6` ```rux pub const AF_INET6: int32 = 10; ``` `AF_INET6`: the IPv6 address family. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Socket.rux#L46){rel=""nofollow""} ## `SOCK_STREAM` ```rux pub const SOCK_STREAM: int32 = 1; ``` `SOCK_STREAM`: a connected byte stream. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Socket.rux#L51){rel=""nofollow""} ## `SOCK_DGRAM` ```rux pub const SOCK_DGRAM: int32 = 2; ``` `SOCK_DGRAM`: individual datagrams. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Socket.rux#L56){rel=""nofollow""} ## `SOCK_CLOEXEC` ```rux pub const SOCK_CLOEXEC: int32 = 0x80000; ``` `SOCK_CLOEXEC`: close the socket when the process starts another program. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Socket.rux#L61){rel=""nofollow""} ## `SOL_SOCKET` ```rux pub const SOL_SOCKET: int32 = 1; ``` `SOL_SOCKET`: the level of the options every socket has. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Socket.rux#L66){rel=""nofollow""} ## `SO_REUSEADDR` ```rux pub const SO_REUSEADDR: int32 = 2; ``` `SO_REUSEADDR`: let a listening address be bound again while old connections to it wind down. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Socket.rux#L71){rel=""nofollow""} ## `SO_RCVTIMEO` ```rux pub const SO_RCVTIMEO: int32 = 20; ``` `SO_RCVTIMEO`: how long a receive waits. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Socket.rux#L76){rel=""nofollow""} ## `SO_SNDTIMEO` ```rux pub const SO_SNDTIMEO: int32 = 21; ``` `SO_SNDTIMEO`: how long a send waits. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Socket.rux#L81){rel=""nofollow""} ## `IPPROTO_TCP` ```rux pub const IPPROTO_TCP: int32 = 6; ``` `IPPROTO_TCP`: the level of TCP's options. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Socket.rux#L86){rel=""nofollow""} ## `TCP_NODELAY` ```rux pub const TCP_NODELAY: int32 = 1; ``` `TCP_NODELAY`: send small writes at once rather than gathering them. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Socket.rux#L91){rel=""nofollow""} ## `IPPROTO_IPV6` ```rux pub const IPPROTO_IPV6: int32 = 41; ``` `IPPROTO_IPV6`: the level of IPv6's options. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Socket.rux#L96){rel=""nofollow""} ## `IPV6_V6ONLY` ```rux pub const IPV6_V6ONLY: int32 = 26; ``` `IPV6_V6ONLY`: accept only IPv6 on an IPv6 socket. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Socket.rux#L101){rel=""nofollow""} ## `MSG_NOSIGNAL` ```rux pub const MSG_NOSIGNAL: int32 = 0x4000; ``` `MSG_NOSIGNAL`: report a closed peer as an error rather than with `SIGPIPE`. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Socket.rux#L106){rel=""nofollow""} ## `Socket` ```rux pub func Socket( domain: int32, kind: int32, protocol: int32 ) -> int64 ``` Opens a socket. **See also**: <https://man7.org/linux/man-pages/man2/socket.2.html>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Socket.rux#L115){rel=""nofollow""} **Parameters** | Name | Type | Description | | ---------- | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `domain` | `int32` | the address family, such as [`AF_INET`](https://rux-lang.dev/docs/api/linux/socket#af-inet) | | `kind` | `int32` | the socket type, such as [`SOCK_STREAM`](https://rux-lang.dev/docs/api/linux/socket#sock-stream), combined with [`SOCK_CLOEXEC`](https://rux-lang.dev/docs/api/linux/socket#sock-cloexec) | | `protocol` | `int32` | the protocol, or zero for the family's default | **Returns**: the new descriptor, or a negative error number ## `Connect` ```rux pub func Connect( fd: FileDescriptor, address: *opaque, length: uint32 ) -> int64 ``` Connects a socket to `address`, waiting for a stream connection to be made. **See also**: <https://man7.org/linux/man-pages/man2/connect.2.html>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Socket.rux#L126){rel=""nofollow""} **Parameters** | Name | Type | Description | | --------- | ---------------- | --------------------------- | | `fd` | `FileDescriptor` | the socket | | `address` | `*opaque` | the address, a `sockaddr` | | `length` | `uint32` | the address's size in bytes | **Returns**: zero, or a negative error number ## `Bind` ```rux pub func Bind( fd: FileDescriptor, address: *opaque, length: uint32 ) -> int64 ``` Gives a socket its local address. **See also**: <https://man7.org/linux/man-pages/man2/bind.2.html>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Socket.rux#L137){rel=""nofollow""} **Parameters** | Name | Type | Description | | --------- | ---------------- | --------------------------- | | `fd` | `FileDescriptor` | the socket | | `address` | `*opaque` | the address, a `sockaddr` | | `length` | `uint32` | the address's size in bytes | **Returns**: zero, or a negative error number ## `Listen` ```rux pub func Listen(fd: FileDescriptor, backlog: int32) -> int64 ``` Makes a bound stream socket accept connections. **See also**: <https://man7.org/linux/man-pages/man2/listen.2.html>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Socket.rux#L147){rel=""nofollow""} **Parameters** | Name | Type | Description | | --------- | ---------------- | -------------------------------------------- | | `fd` | `FileDescriptor` | the socket | | `backlog` | `int32` | how many connections may wait to be accepted | **Returns**: zero, or a negative error number ## `Accept4` ```rux pub func Accept4( fd: FileDescriptor, address: *var opaque, length: *var uint32, flags: int32 ) -> int64 ``` Accepts a waiting connection as a new socket. **See also**: <https://man7.org/linux/man-pages/man2/accept4.2.html>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Socket.rux#L159){rel=""nofollow""} **Parameters** | Name | Type | Description | | --------- | ---------------- | ----------------------------------------------------------------------------------------------------------- | | `fd` | `FileDescriptor` | the listening socket | | `address` | `*var opaque` | receives the peer's address, or null | | `length` | `*var uint32` | the address buffer's size, then the address's, or null | | `flags` | `int32` | flags for the new socket, such as [`SOCK_CLOEXEC`](https://rux-lang.dev/docs/api/linux/socket#sock-cloexec) | **Returns**: the new descriptor, or a negative error number ## `SendTo` ```rux pub func SendTo( fd: FileDescriptor, buffer: *opaque, count: uint, flags: int32, address: *opaque, length: uint32 ) -> int64 ``` Sends bytes on a socket, to `address` when it is not connected. **See also**: <https://man7.org/linux/man-pages/man2/sendto.2.html>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Socket.rux#L173){rel=""nofollow""} **Parameters** | Name | Type | Description | | --------- | ---------------- | --------------------------------------------------------------------------------------- | | `fd` | `FileDescriptor` | the socket | | `buffer` | `*opaque` | the bytes | | `count` | `uint` | how many | | `flags` | `int32` | flags such as [`MSG_NOSIGNAL`](https://rux-lang.dev/docs/api/linux/socket#msg-nosignal) | | `address` | `*opaque` | the destination, or null for a connected socket | | `length` | `uint32` | the destination's size | **Returns**: the bytes sent, or a negative error number ## `ReceiveFrom` ```rux pub func ReceiveFrom( fd: FileDescriptor, buffer: *var opaque, count: uint, flags: int32, address: *var opaque, length: *var uint32 ) -> int64 ``` Receives bytes from a socket, and where they came from. **See also**: <https://man7.org/linux/man-pages/man2/recvfrom.2.html>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Socket.rux#L187){rel=""nofollow""} **Parameters** | Name | Type | Description | | --------- | ---------------- | ------------------------------------------------------ | | `fd` | `FileDescriptor` | the socket | | `buffer` | `*var opaque` | receives the bytes | | `count` | `uint` | how many fit | | `flags` | `int32` | flags, or zero | | `address` | `*var opaque` | receives the sender's address, or null | | `length` | `*var uint32` | the address buffer's size, then the address's, or null | **Returns**: the bytes received, zero once a stream's peer closed it, or a negative error number ## `Shutdown` ```rux pub func Shutdown(fd: FileDescriptor, how: int32) -> int64 ``` Ends one or both directions of a connection. **See also**: <https://man7.org/linux/man-pages/man2/shutdown.2.html>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Socket.rux#L197){rel=""nofollow""} **Parameters** | Name | Type | Description | | ----- | ---------------- | ----------------------------------- | | `fd` | `FileDescriptor` | the socket | | `how` | `int32` | `SHUT_RD`, `SHUT_WR` or `SHUT_RDWR` | **Returns**: zero, or a negative error number ## `SetSocketOption` ```rux pub func SetSocketOption( fd: FileDescriptor, level: int32, name: int32, value: *opaque, length: uint32 ) -> int64 ``` Sets a socket option. **See also**: <https://man7.org/linux/man-pages/man2/setsockopt.2.html>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Socket.rux#L210){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | ---------------- | ------------------------------------------------------------------------------------------------- | | `fd` | `FileDescriptor` | the socket | | `level` | `int32` | the option's level, such as [`SOL_SOCKET`](https://rux-lang.dev/docs/api/linux/socket#sol-socket) | | `name` | `int32` | the option | | `value` | `*opaque` | the option's value | | `length` | `uint32` | the value's size in bytes | **Returns**: zero, or a negative error number ## `GetSocketName` ```rux pub func GetSocketName( fd: FileDescriptor, address: *var opaque, length: *var uint32 ) -> int64 ``` Reads a socket's local address. **See also**: <https://man7.org/linux/man-pages/man2/getsockname.2.html>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Socket.rux#L221){rel=""nofollow""} **Parameters** | Name | Type | Description | | --------- | ---------------- | ------------------------------------- | | `fd` | `FileDescriptor` | the socket | | `address` | `*var opaque` | receives the address | | `length` | `*var uint32` | the buffer's size, then the address's | **Returns**: zero, or a negative error number ## `GetPeerName` ```rux pub func GetPeerName( fd: FileDescriptor, address: *var opaque, length: *var uint32 ) -> int64 ``` Reads the address of a connected socket's peer. **See also**: <https://man7.org/linux/man-pages/man2/getpeername.2.html>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Linux/Src/Socket.rux#L232){rel=""nofollow""} **Parameters** | Name | Type | Description | | --------- | ---------------- | ------------------------------------- | | `fd` | `FileDescriptor` | the socket | | `address` | `*var opaque` | receives the address | | `length` | `*var uint32` | the buffer's size, then the address's | **Returns**: zero, or a negative error number # FreeBSD FreeBSD platform bindings. ## Installation Add `FreeBSD` to the `[Dependencies]` table of your package's `Rux.toml`: ```toml [Dependencies] FreeBSD = { Namespace = "Rux", Version = "0.1.0" } ``` Standard packages are declared by hand: the registry does not serve them, so `rux add Rux/FreeBSD` cannot add them. ## Dependencies - [`Core`](https://rux-lang.dev/docs/api/core) 0.1.0 ## Guide FreeBSD platform bindings: the raw syscall interface, with no libc in between. ### What it provides | Module | Covers | | --------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `Types` | the kernel ABI's own types: [`ProcessId`](https://rux-lang.dev/docs/api/freebsd/types#process-id), [`FileDescriptor`](https://rux-lang.dev/docs/api/freebsd/types#file-descriptor), [`FileOffset`](https://rux-lang.dev/docs/api/freebsd/types#file-offset), [`FileMode`](https://rux-lang.dev/docs/api/freebsd/types#file-mode), [`UserId`](https://rux-lang.dev/docs/api/freebsd/types#user-id), [`Timespec`](https://rux-lang.dev/docs/api/freebsd/timespec) | | `Errors` | the errno numbers, and [`IsError`](https://rux-lang.dev/docs/api/freebsd/errors#is-error) / [`Errno`](https://rux-lang.dev/docs/api/freebsd/errors#errno) for reading a raw result | | `Syscall` | [`Syscall0`](https://rux-lang.dev/docs/api/freebsd/syscalls#syscall-0) through [`Syscall6`](https://rux-lang.dev/docs/api/freebsd/syscalls#syscall-6) as inline assembly, the call numbers, and [`SignExtendFd`](https://rux-lang.dev/docs/api/freebsd/syscalls#sign-extend-fd) | | `File` | [`Read`](https://rux-lang.dev/docs/api/freebsd/files#read), [`Write`](https://rux-lang.dev/docs/api/freebsd/files#write), [`Close`](https://rux-lang.dev/docs/api/freebsd/files#close), [`OpenAt`](https://rux-lang.dev/docs/api/freebsd/files#open-at), [`Lseek`](https://rux-lang.dev/docs/api/freebsd/files#lseek), [`Fsync`](https://rux-lang.dev/docs/api/freebsd/files#fsync), [`Ftruncate`](https://rux-lang.dev/docs/api/freebsd/files#ftruncate), [`UnlinkAt`](https://rux-lang.dev/docs/api/freebsd/directories#unlink-at), [`MkdirAt`](https://rux-lang.dev/docs/api/freebsd/directories#mkdir-at), [`RenameAt`](https://rux-lang.dev/docs/api/freebsd/directories#rename-at), [`Fstat`](https://rux-lang.dev/docs/api/freebsd/files#fstat), [`FstatAt`](https://rux-lang.dev/docs/api/freebsd/files#fstat-at), [`Dup2`](https://rux-lang.dev/docs/api/freebsd/files#dup2), [`Pipe2`](https://rux-lang.dev/docs/api/freebsd/files#pipe2), the open flags, and the three standard descriptors | | `Memory` | [`Mmap`](https://rux-lang.dev/docs/api/freebsd/memory#mmap), [`Munmap`](https://rux-lang.dev/docs/api/freebsd/memory#munmap), [`Brk`](https://rux-lang.dev/docs/api/freebsd/memory#brk), [`Mprotect`](https://rux-lang.dev/docs/api/freebsd/memory#mprotect), [`Madvise`](https://rux-lang.dev/docs/api/freebsd/memory#madvise), [`QueryPageSize`](https://rux-lang.dev/docs/api/freebsd/memory#query-page-size), and the protection, mapping and advice flags | | `Clock` | [`ClockGetTime`](https://rux-lang.dev/docs/api/freebsd/clock#clock-get-time), [`ClockGetResolution`](https://rux-lang.dev/docs/api/freebsd/clock#clock-get-resolution), [`Nanosleep`](https://rux-lang.dev/docs/api/freebsd/clock#nanosleep), and the clock identifiers | | `Entropy` | [`GetRandom`](https://rux-lang.dev/docs/api/freebsd/get-random), the only source here fit for a key or a token | | `Process` | [`Exit`](https://rux-lang.dev/docs/api/freebsd/process#exit) and [`GetPid`](https://rux-lang.dev/docs/api/freebsd/process#get-pid) | | `Dynamic` | [`dlopen`](https://rux-lang.dev/docs/api/freebsd/dynamic#dlopen), [`dlsym`](https://rux-lang.dev/docs/api/freebsd/dynamic#dlsym), [`dlclose`](https://rux-lang.dev/docs/api/freebsd/dynamic#dlclose), [`dlerror`](https://rux-lang.dev/docs/api/freebsd/dynamic#dlerror), and the `RTLD_*` flags | | `Thread` | [`pthread_create`](https://rux-lang.dev/docs/api/freebsd/thread#pthread-create), [`pthread_join`](https://rux-lang.dev/docs/api/freebsd/thread#pthread-join), [`pthread_detach`](https://rux-lang.dev/docs/api/freebsd/thread#pthread-detach), the `pthread_attr_*` stack-size calls, [`sched_yield`](https://rux-lang.dev/docs/api/freebsd/thread#sched-yield), [`sysconf`](https://rux-lang.dev/docs/api/freebsd/thread#sysconf) and [`SC_NPROCESSORS_ONLN`](https://rux-lang.dev/docs/api/freebsd/thread#sc-nprocessors-onln), and [`pthread_getthreadid_np`](https://rux-lang.dev/docs/api/freebsd/thread#pthread-getthreadid-np), linked from libthr and libc | | `Umtx` | [`UmtxWait`](https://rux-lang.dev/docs/api/freebsd/umtx#umtx-wait) and [`UmtxWake`](https://rux-lang.dev/docs/api/freebsd/umtx#umtx-wake), the private `_umtx_op(2)` word operations every lock in `Rux/Sync` sleeps on | | `Spawn` | [`posix_spawnp`](https://rux-lang.dev/docs/api/freebsd/spawn#posix-spawnp), the `posix_spawn_file_actions_*` calls, [`waitpid`](https://rux-lang.dev/docs/api/freebsd/spawn#waitpid), [`kill`](https://rux-lang.dev/docs/api/freebsd/spawn#kill), [`fcntl`](https://rux-lang.dev/docs/api/freebsd/spawn#fcntl) and [`__error`](https://rux-lang.dev/docs/api/freebsd/spawn#errno), linked from libc | | [`Socket`](https://rux-lang.dev/docs/api/freebsd/socket#socket) | [`Socket`](https://rux-lang.dev/docs/api/freebsd/socket#socket), [`Connect`](https://rux-lang.dev/docs/api/freebsd/socket#connect), [`Bind`](https://rux-lang.dev/docs/api/freebsd/socket#bind), [`Listen`](https://rux-lang.dev/docs/api/freebsd/socket#listen), [`Accept4`](https://rux-lang.dev/docs/api/freebsd/socket#accept4), [`SendTo`](https://rux-lang.dev/docs/api/freebsd/socket#sendto), [`ReceiveFrom`](https://rux-lang.dev/docs/api/freebsd/socket#receivefrom), [`Shutdown`](https://rux-lang.dev/docs/api/freebsd/socket#shutdown), [`SetSocketOption`](https://rux-lang.dev/docs/api/freebsd/socket#setsocketoption), [`GetSocketName`](https://rux-lang.dev/docs/api/freebsd/socket#getsocketname) and [`GetPeerName`](https://rux-lang.dev/docs/api/freebsd/socket#getpeername) as system calls, with the address families, socket options and [`MSG_NOSIGNAL`](https://rux-lang.dev/docs/api/freebsd/socket#msg-nosignal) | | `Resolve` | [`getaddrinfo`](https://rux-lang.dev/docs/api/freebsd/resolve#getaddrinfo), [`freeaddrinfo`](https://rux-lang.dev/docs/api/freebsd/resolve#freeaddrinfo) and [`AddressInfo`](https://rux-lang.dev/docs/api/freebsd/resolve#address-info), linked from libc | | `Poll` | [`Kqueue`](https://rux-lang.dev/docs/api/freebsd/poll#kqueue) and [`KeventCall`](https://rux-lang.dev/docs/api/freebsd/poll#kevent-call) as system calls, [`Kevent`](https://rux-lang.dev/docs/api/freebsd/poll#kevent), the `EVFILT_*` and `EV_*` flags, and [`FcntlInt`](https://rux-lang.dev/docs/api/freebsd/poll#fcntl-int) with [`F_GETFL`](https://rux-lang.dev/docs/api/freebsd/poll#f-getfl), [`F_SETFL`](https://rux-lang.dev/docs/api/freebsd/poll#f-setfl) and [`O_NONBLOCK`](https://rux-lang.dev/docs/api/freebsd/poll#o-nonblock) | The module names describe where each declaration comes from; they are not part of an import path. FreeBSD reports an error by setting the carry flag and leaving a *positive* errno in the result register, so a raw instruction result cannot be tested for sign. The assembly wrappers normalize that to a small negative number, which is Linux's convention, so everything above them reads the same on both systems and [`IsError`](https://rux-lang.dev/docs/api/freebsd/errors#is-error) and [`Errno`](https://rux-lang.dev/docs/api/freebsd/errors#errno) are the same two functions. Nothing here is interchangeable with `Rux/Linux`, and the resemblance is the hazard. The clock identifiers differ — monotonic is 4 here and 1 there — the open flags are the BSD ones, `MADV_DONTNEED` does not discard where Linux's does, and only the errno numbers below thirty-five agree. A value taken from one package and passed to the other compiles and means something else. [`QueryPageSize`](https://rux-lang.dev/docs/api/freebsd/memory#query-page-size) reads the `hw.pagesize` sysctl, which is how FreeBSD publishes the value; there is no dedicated call and no auxiliary vector to read without libc. ### The shared POSIX contract Nothing here is interchangeable with the other POSIX packages, but the three are *spelled* the same, which is a different claim and a deliberate one. An equivalent call has the same wrapper name, the same parameter names and the same parameter shapes on all three systems, so a consumer such as [`Rux/FileSystem`](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/../FileSystem){rel=""nofollow""} or [`Rux/Time`](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/../Time){rel=""nofollow""} writes one call site instead of a `when #target.os` ladder around three names for one idea. `Tests/Unit/PlatformBindingContractTests.cpp` compares the three packages' parsed sources and fails when they drift apart. The values are the opposite: every constant is this system's own, and the same file asserts that the ones a reader might carry across really do differ. ### What is tested `Tests/Packages/FreeBSD/Descriptors` covers descriptor numbering, short reads and writes, end of file, size boundaries and the native error for each way of misusing a descriptor or a name. `Tests/Packages/FreeBSD/Mapping` covers anonymous mappings, protection changes, advice, the requests the kernel refuses, and both edges of the reserved error-result window. `Tests/Packages/FreeBSD/Syscall` covers the wrapper surface and the shared POSIX contract. All of it compiles for both architectures, and none of it has ever run on a host that is not FreeBSD. Until it does, the syscall numbers, flag values and errno constants here rest on published documentation rather than on a passing test. ### Values and pointers Kernel records such as [`Timespec`](https://rux-lang.dev/docs/api/freebsd/timespec) are structural values and copy by value. Syscall wrappers deliberately retain raw pointers because the kernel consumes untyped integer addresses, buffers carry separate lengths, and optional outputs may be null. Pass addresses explicitly, for example `ClockGetTime(ClockMonotonic, @time)`, and uphold each function's safety contract. The package does not own raw addresses or descriptors; release them explicitly or use the higher-level `Rux/Memory` and `Rux/Io` packages. ### Platform FreeBSD only. Guard use behind a compile-time check, so a build for another target never resolves these declarations: ```rux import Core::{ #target }; when #target.os { .FreeBSD => import FreeBSD::{ StdOut, Write } } ``` Higher-level packages such as [`Rux/Io`](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/../Io){rel=""nofollow""} and [`Rux/Memory`](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/../Memory){rel=""nofollow""} already do this, and are the interface to prefer unless you need the syscall itself. ### AArch64 ABI The AArch64 wrappers follow the FreeBSD syscall convention: the call number is placed in `x8`, up to six wrapper arguments are shifted into `x0` through `x5`, and `svc #0` enters the kernel. A carry-set return is converted from a positive `errno` to the negative result used by the package API. Descriptor and clock identifiers are sign-extended before entering the generic `uint64` syscall interface. [`Mmap`](https://rux-lang.dev/docs/api/freebsd/memory#mmap) likewise preserves a signed descriptor while passing the FreeBSD 15.1 mapping constants and all six arguments directly. The same source keeps a separate set of x86-64 wrappers, which reach the kernel through `syscall` and normalize the carry flag the same way. ## Index ### Types | Name | Summary | | --------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- | | [`Kevent`](https://rux-lang.dev/docs/api/freebsd/poll#kevent) | One `struct kevent` as FreeBSD 12 and later lay it out: a change to register or an event to report. | | [`AddressInfo`](https://rux-lang.dev/docs/api/freebsd/resolve#address-info) | The C library's `addrinfo`: one result of [`getaddrinfo`](https://rux-lang.dev/docs/api/freebsd/resolve#getaddrinfo), linked to the next. | | [`SpawnFileActions`](https://rux-lang.dev/docs/api/freebsd/spawn#spawn-file-actions) | Room for a `posix_spawn_file_actions_t`, which each C library sizes its own way and none larger than this. | | [`PThread`](https://rux-lang.dev/docs/api/freebsd/thread#p-thread) | A thread as the C library names it, `pthread_t`. | | [`PThreadAttributes`](https://rux-lang.dev/docs/api/freebsd/thread#p-thread-attributes) | Room for a `pthread_attr_t`, which each C library sizes its own way and none larger than this. | | [`ProcessId`](https://rux-lang.dev/docs/api/freebsd/types#process-id) | A process identifier, as `getpid` and its relatives report one. | | [`FileDescriptor`](https://rux-lang.dev/docs/api/freebsd/types#file-descriptor) | A file descriptor, as the kernel numbers one. | | [`FileOffset`](https://rux-lang.dev/docs/api/freebsd/types#file-offset) | A byte offset within a file, 64 bits on every supported target. | | [`FileMode`](https://rux-lang.dev/docs/api/freebsd/types#file-mode) | A file's type and permission bits. | | [`UserId`](https://rux-lang.dev/docs/api/freebsd/types#user-id) | A user identifier. | | [`GroupId`](https://rux-lang.dev/docs/api/freebsd/types#group-id) | A group identifier. | | [`Timespec`](https://rux-lang.dev/docs/api/freebsd/timespec) | A duration or an instant, as seconds and nanoseconds. | ### Functions | Name | Summary | | -------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- | | [`ClockGetTime`](https://rux-lang.dev/docs/api/freebsd/clock#clock-get-time) | Reads `clockId` into `time`. | | [`Nanosleep`](https://rux-lang.dev/docs/api/freebsd/clock#nanosleep) | Suspends the caller for the requested duration. | | [`ClockGetResolution`](https://rux-lang.dev/docs/api/freebsd/clock#clock-get-resolution) | Reads the resolution of `clockId` into `resolution`. | | [`dlopen`](https://rux-lang.dev/docs/api/freebsd/dynamic#dlopen) | Loads a shared object and returns a handle to it, or null on failure. | | [`dlsym`](https://rux-lang.dev/docs/api/freebsd/dynamic#dlsym) | Finds a symbol in a loaded object and returns its address, or null. | | [`dlclose`](https://rux-lang.dev/docs/api/freebsd/dynamic#dlclose) | Drops one reference to a loaded object, unloading it when the last one goes. | | [`dlerror`](https://rux-lang.dev/docs/api/freebsd/dynamic#dlerror) | Reports the most recent loader error and clears it, or returns null when there is none. | | [`GetRandom`](https://rux-lang.dev/docs/api/freebsd/get-random) | Fills up to `length` bytes of `buffer` with unpredictable bytes. | | [`IsError`](https://rux-lang.dev/docs/api/freebsd/errors#is-error) | Whether a raw system-call result is one of the normalized error values. | | [`Errno`](https://rux-lang.dev/docs/api/freebsd/errors#errno) | The error number a raw system-call result carries, or zero when it carries none. | | [`Read`](https://rux-lang.dev/docs/api/freebsd/files#read) | Reads up to `count` bytes from `fd` into `buffer`. | | [`Write`](https://rux-lang.dev/docs/api/freebsd/files#write) | Writes up to `count` bytes from `buffer` to `fd`. | | [`Close`](https://rux-lang.dev/docs/api/freebsd/files#close) | Closes `fd` and releases what the kernel held for it. | | [`OpenAt`](https://rux-lang.dev/docs/api/freebsd/files#open-at) | Opens `path` relative to `directoryFd` and returns a descriptor, or a negative error number. | | [`Lseek`](https://rux-lang.dev/docs/api/freebsd/files#lseek) | Moves the file offset of `fd` and returns where it ended up, or a negative error number. | | [`Getcwd`](https://rux-lang.dev/docs/api/freebsd/directories#getcwd) | Writes the current working directory's absolute path into `buffer`, NUL-terminated. | | [`Chdir`](https://rux-lang.dev/docs/api/freebsd/directories#chdir) | Makes `path` the process's working directory. | | [`ReadlinkAt`](https://rux-lang.dev/docs/api/freebsd/directories#readlink-at) | Reads the text a symbolic link holds into `buffer`. | | [`FstatAt`](https://rux-lang.dev/docs/api/freebsd/files#fstat-at) | Fills `statBuffer` with what the kernel knows about the file `path` names. | | [`FchmodAt`](https://rux-lang.dev/docs/api/freebsd/files#fchmod-at) | Sets the permission bits of the file `path` names. | | [`UtimensAt`](https://rux-lang.dev/docs/api/freebsd/files#utimens-at) | Sets the access and modification times of the file `path` names. | | [`LinkAt`](https://rux-lang.dev/docs/api/freebsd/directories#link-at) | Creates a hard link: `newPath` becomes a second name for the file `oldPath` names. | | [`SymlinkAt`](https://rux-lang.dev/docs/api/freebsd/directories#symlink-at) | Creates a symbolic link at `linkPath` holding `target` as its text. | | [`Getdirentries`](https://rux-lang.dev/docs/api/freebsd/directories#getdirentries) | Reads directory entries from `fd` into `buffer`. | | [`Fsync`](https://rux-lang.dev/docs/api/freebsd/files#fsync) | Flushes everything written to `fd` through to the storage device. | | [`Ftruncate`](https://rux-lang.dev/docs/api/freebsd/files#ftruncate) | Sets the length of the file behind `fd` to `length`. | | [`UnlinkAt`](https://rux-lang.dev/docs/api/freebsd/directories#unlink-at) | Removes the name `path` from its directory. | | [`MkdirAt`](https://rux-lang.dev/docs/api/freebsd/directories#mkdir-at) | Creates a directory named `path` with permission bits `mode`. | | [`RenameAt`](https://rux-lang.dev/docs/api/freebsd/directories#rename-at) | Renames `oldPath` to `newPath`, each resolved against its own directory descriptor. | | [`Fstat`](https://rux-lang.dev/docs/api/freebsd/files#fstat) | Fills `statBuffer` with what the kernel knows about the file behind `fd`. | | [`Dup2`](https://rux-lang.dev/docs/api/freebsd/files#dup2) | Makes `newFd` a copy of `oldFd`, closing whatever `newFd` was. | | [`Pipe2`](https://rux-lang.dev/docs/api/freebsd/files#pipe2) | Creates a pipe and writes its two descriptors into `descriptors`. | | [`Mmap`](https://rux-lang.dev/docs/api/freebsd/memory#mmap) | Creates a mapping and returns its address, or a negative error number. | | [`Munmap`](https://rux-lang.dev/docs/api/freebsd/memory#munmap) | Releases the mapping that begins at `address` and spans `length` bytes. | | [`Brk`](https://rux-lang.dev/docs/api/freebsd/memory#brk) | Sets the program break and returns where it ended up. | | [`Mprotect`](https://rux-lang.dev/docs/api/freebsd/memory#mprotect) | Changes what may be done with the pages covering a range. | | [`Madvise`](https://rux-lang.dev/docs/api/freebsd/memory#madvise) | Tells the kernel how the pages covering a range are about to be used. | | [`QueryPageSize`](https://rux-lang.dev/docs/api/freebsd/memory#query-page-size) | The size of a page, asked of the kernel. | | [`FcntlInt`](https://rux-lang.dev/docs/api/freebsd/poll#fcntl-int) | Performs `command` on a descriptor with an integer argument. | | [`Kqueue`](https://rux-lang.dev/docs/api/freebsd/poll#kqueue) | Opens a kqueue. | | [`KeventCall`](https://rux-lang.dev/docs/api/freebsd/poll#kevent-call) | Applies `changeCount` changes, then waits until an event is ready or `timeout` passes, filling `events`. | | [`Exit`](https://rux-lang.dev/docs/api/freebsd/process#exit) | Ends the calling process with `code`. | | [`GetPid`](https://rux-lang.dev/docs/api/freebsd/process#get-pid) | The calling process's own identifier. | | [`QueryExecutablePath`](https://rux-lang.dev/docs/api/freebsd/process#query-executable-path) | Writes the absolute path of the calling process's executable into `buffer`, NUL-terminated. | | [`getaddrinfo`](https://rux-lang.dev/docs/api/freebsd/resolve#getaddrinfo) | Looks up the addresses of a host and service. | | [`freeaddrinfo`](https://rux-lang.dev/docs/api/freebsd/resolve#freeaddrinfo) | Frees the results of [`getaddrinfo`](https://rux-lang.dev/docs/api/freebsd/resolve#getaddrinfo). | | [`Socket`](https://rux-lang.dev/docs/api/freebsd/socket#socket) | Opens a socket. | | [`Connect`](https://rux-lang.dev/docs/api/freebsd/socket#connect) | Connects a socket to `address`, waiting for a stream connection to be made. | | [`Bind`](https://rux-lang.dev/docs/api/freebsd/socket#bind) | Gives a socket its local address. | | [`Listen`](https://rux-lang.dev/docs/api/freebsd/socket#listen) | Makes a bound stream socket accept connections. | | [`Accept4`](https://rux-lang.dev/docs/api/freebsd/socket#accept4) | Accepts a waiting connection as a new socket. | | [`SendTo`](https://rux-lang.dev/docs/api/freebsd/socket#sendto) | Sends bytes on a socket, to `address` when it is not connected. | | [`ReceiveFrom`](https://rux-lang.dev/docs/api/freebsd/socket#receivefrom) | Receives bytes from a socket, and where they came from. | | [`Shutdown`](https://rux-lang.dev/docs/api/freebsd/socket#shutdown) | Ends one or both directions of a connection. | | [`SetSocketOption`](https://rux-lang.dev/docs/api/freebsd/socket#setsocketoption) | Sets a socket option. | | [`GetSocketName`](https://rux-lang.dev/docs/api/freebsd/socket#getsocketname) | Reads a socket's local address. | | [`GetPeerName`](https://rux-lang.dev/docs/api/freebsd/socket#getpeername) | Reads the address of a connected socket's peer. | | [`posix_spawnp`](https://rux-lang.dev/docs/api/freebsd/spawn#posix-spawnp) | Starts `file`, found through `PATH` when it has no slash, as a child process. | | [`posix_spawn_file_actions_init`](https://rux-lang.dev/docs/api/freebsd/spawn#posix-spawn-file-actions-init) | Initializes an empty list of file actions. | | [`posix_spawn_file_actions_destroy`](https://rux-lang.dev/docs/api/freebsd/spawn#posix-spawn-file-actions-destroy) | Releases what [`posix_spawn_file_actions_init`](https://rux-lang.dev/docs/api/freebsd/spawn#posix-spawn-file-actions-init) and the actions added since set up. | | [`posix_spawn_file_actions_adddup2`](https://rux-lang.dev/docs/api/freebsd/spawn#posix-spawn-file-actions-adddup2) | Adds an action duplicating `fd` onto `newFd` in the child. | | [`posix_spawn_file_actions_addopen`](https://rux-lang.dev/docs/api/freebsd/spawn#posix-spawn-file-actions-addopen) | Adds an action opening `path` as `fd` in the child. | | [`posix_spawn_file_actions_addchdir_np`](https://rux-lang.dev/docs/api/freebsd/spawn#posix-spawn-file-actions-addchdir-np) | Adds an action changing the child's working directory to `path`. | | [`waitpid`](https://rux-lang.dev/docs/api/freebsd/spawn#waitpid) | Waits for a child to change state, and reports how it finished. | | [`kill`](https://rux-lang.dev/docs/api/freebsd/spawn#kill) | Sends a signal to a process. | | [`fcntl`](https://rux-lang.dev/docs/api/freebsd/spawn#fcntl) | Performs a control operation on a descriptor, such as setting its flags with [`F_SETFD`](https://rux-lang.dev/docs/api/freebsd/spawn#f-setfd). | | [`__error`](https://rux-lang.dev/docs/api/freebsd/spawn#errno) | Returns the address of the calling thread's errno, where the C library calls above leave their reason. | | [`Syscall0`](https://rux-lang.dev/docs/api/freebsd/syscalls#syscall-0) | Executes a raw FreeBSD system call without arguments. | | [`Syscall6`](https://rux-lang.dev/docs/api/freebsd/syscalls#syscall-6) | Executes a raw FreeBSD system call with six arguments. | | [`SignExtendFd`](https://rux-lang.dev/docs/api/freebsd/syscalls#sign-extend-fd) | Widens a file descriptor to the register width a system call takes it in. | | [`pthread_create`](https://rux-lang.dev/docs/api/freebsd/thread#pthread-create) | Starts a thread running `start(argument)`. | | [`pthread_join`](https://rux-lang.dev/docs/api/freebsd/thread#pthread-join) | Waits for a thread to finish and releases it. | | [`pthread_detach`](https://rux-lang.dev/docs/api/freebsd/thread#pthread-detach) | Lets a thread release itself when it finishes, so nothing has to join it. | | [`pthread_attr_init`](https://rux-lang.dev/docs/api/freebsd/thread#pthread-attr-init) | Initializes thread attributes to the defaults. | | [`pthread_attr_setstacksize`](https://rux-lang.dev/docs/api/freebsd/thread#pthread-attr-setstacksize) | Sets the stack size a thread started with these attributes gets. | | [`pthread_attr_destroy`](https://rux-lang.dev/docs/api/freebsd/thread#pthread-attr-destroy) | Releases what [`pthread_attr_init`](https://rux-lang.dev/docs/api/freebsd/thread#pthread-attr-init) set up. | | [`pthread_getthreadid_np`](https://rux-lang.dev/docs/api/freebsd/thread#pthread-getthreadid-np) | Returns the kernel's identifier for the calling thread. | | [`sched_yield`](https://rux-lang.dev/docs/api/freebsd/thread#sched-yield) | Gives up the processor so another ready thread can run. | | [`sysconf`](https://rux-lang.dev/docs/api/freebsd/thread#sysconf) | Reads a system configuration value. | | [`UmtxWait`](https://rux-lang.dev/docs/api/freebsd/umtx#umtx-wait) | Sleeps while `*address` equals `expected`, until a wake, a signal or the timeout. | | [`UmtxWake`](https://rux-lang.dev/docs/api/freebsd/umtx#umtx-wake) | Wakes up to `count` threads sleeping on `address`. | ### Constants | Name | Summary | | --------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | [`ClockRealtime`](https://rux-lang.dev/docs/api/freebsd/clock#clock-realtime) | `CLOCK_REALTIME`: wall-clock time, which can jump when the system clock is set. | | [`ClockMonotonic`](https://rux-lang.dev/docs/api/freebsd/clock#clock-monotonic) | `CLOCK_MONOTONIC`: time since an unspecified point, which never goes backwards. | | [`ClockMonotonicFast`](https://rux-lang.dev/docs/api/freebsd/clock#clock-monotonic-fast) | `CLOCK_MONOTONIC_FAST`: like [`ClockMonotonic`](https://rux-lang.dev/docs/api/freebsd/clock#clock-monotonic), read from a cached value rather than the hardware. | | [`ClockRealtimeFast`](https://rux-lang.dev/docs/api/freebsd/clock#clock-realtime-fast) | `CLOCK_REALTIME_FAST`: like [`ClockRealtime`](https://rux-lang.dev/docs/api/freebsd/clock#clock-realtime), read from a cached value. | | [`ClockProcessCpuTime`](https://rux-lang.dev/docs/api/freebsd/clock#clock-process-cpu-time) | `CLOCK_PROCESS_CPUTIME_ID`: processor time this process has used. | | [`RTLD_LAZY`](https://rux-lang.dev/docs/api/freebsd/dynamic#rtld-lazy) | `RTLD_LAZY`: resolve a function symbol the first time it is called rather than at load. | | [`RTLD_NOW`](https://rux-lang.dev/docs/api/freebsd/dynamic#rtld-now) | `RTLD_NOW`: resolve every symbol before [`dlopen`](https://rux-lang.dev/docs/api/freebsd/dynamic#dlopen) returns. | | [`RTLD_GLOBAL`](https://rux-lang.dev/docs/api/freebsd/dynamic#rtld-global) | `RTLD_GLOBAL`: make this object's symbols available to objects loaded afterwards. | | [`RTLD_LOCAL`](https://rux-lang.dev/docs/api/freebsd/dynamic#rtld-local) | `RTLD_LOCAL`: keep this object's symbols to itself, which is the default. | | [`RandomNonBlocking`](https://rux-lang.dev/docs/api/freebsd/get-random#random-non-blocking) | `GRND_NONBLOCK`: report rather than wait. | | [`RandomBlockingPool`](https://rux-lang.dev/docs/api/freebsd/get-random#random-blocking-pool) | `GRND_RANDOM`: accepted and ignored, which is what FreeBSD does with it. | | [`EPERM`](https://rux-lang.dev/docs/api/freebsd/errors#eperm) | `EPERM`: the operation is not permitted to this caller. | | [`ENOENT`](https://rux-lang.dev/docs/api/freebsd/errors#enoent) | `ENOENT`: no such file or directory. | | [`ESRCH`](https://rux-lang.dev/docs/api/freebsd/errors#esrch) | `ESRCH`: no such process. | | [`EINTR`](https://rux-lang.dev/docs/api/freebsd/errors#eintr) | `EINTR`: the call was interrupted by a signal before it did anything. | | [`EIO`](https://rux-lang.dev/docs/api/freebsd/errors#eio) | `EIO`: a low-level input or output error. | | [`ENXIO`](https://rux-lang.dev/docs/api/freebsd/errors#enxio) | `ENXIO`: no such device or address. | | [`EBADF`](https://rux-lang.dev/docs/api/freebsd/errors#ebadf) | `EBADF`: the file descriptor is not open, or is not open for what was asked. | | [`EAGAIN`](https://rux-lang.dev/docs/api/freebsd/errors#eagain) | `EAGAIN`: the operation would block, and the descriptor was set not to. | | [`ENOMEM`](https://rux-lang.dev/docs/api/freebsd/errors#enomem) | `ENOMEM`: not enough memory to satisfy the request. | | [`EACCES`](https://rux-lang.dev/docs/api/freebsd/errors#eacces) | `EACCES`: permission denied. | | [`EFAULT`](https://rux-lang.dev/docs/api/freebsd/errors#efault) | `EFAULT`: an address the call was given is outside the caller's address space. | | [`EBUSY`](https://rux-lang.dev/docs/api/freebsd/errors#ebusy) | `EBUSY`: the resource is in use. | | [`EEXIST`](https://rux-lang.dev/docs/api/freebsd/errors#eexist) | `EEXIST`: the file already exists. | | [`EXDEV`](https://rux-lang.dev/docs/api/freebsd/errors#exdev) | `EXDEV`: the two paths are on different file systems. | | [`ENOTDIR`](https://rux-lang.dev/docs/api/freebsd/errors#enotdir) | `ENOTDIR`: a path component that had to be a directory is not one. | | [`EISDIR`](https://rux-lang.dev/docs/api/freebsd/errors#eisdir) | `EISDIR`: the target is a directory and the operation is not one a directory accepts. | | [`EINVAL`](https://rux-lang.dev/docs/api/freebsd/errors#einval) | `EINVAL`: an argument is not valid. | | [`EMFILE`](https://rux-lang.dev/docs/api/freebsd/errors#emfile) | `EMFILE`: this process has too many descriptors open. | | [`ENOSPC`](https://rux-lang.dev/docs/api/freebsd/errors#enospc) | `ENOSPC`: the device has no room left. | | [`ESPIPE`](https://rux-lang.dev/docs/api/freebsd/errors#espipe) | `ESPIPE`: the descriptor is a pipe or socket and cannot be seeked. | | [`EROFS`](https://rux-lang.dev/docs/api/freebsd/errors#erofs) | `EROFS`: the file system is mounted read-only. | | [`EPIPE`](https://rux-lang.dev/docs/api/freebsd/errors#epipe) | `EPIPE`: the reading end of the pipe is closed. | | [`ENAMETOOLONG`](https://rux-lang.dev/docs/api/freebsd/errors#enametoolong) | `ENAMETOOLONG`: the path or a component of it is too long. | | [`ELOOP`](https://rux-lang.dev/docs/api/freebsd/errors#eloop) | `ELOOP`: too many symbolic links were followed resolving the path. | | [`ENOSYS`](https://rux-lang.dev/docs/api/freebsd/errors#enosys) | `ENOSYS`: the kernel does not implement this call. | | [`EOVERFLOW`](https://rux-lang.dev/docs/api/freebsd/errors#eoverflow) | `EOVERFLOW`: a value is too large for the type the call reports it in. | | [`ETIMEDOUT`](https://rux-lang.dev/docs/api/freebsd/errors#etimedout) | `ETIMEDOUT`: the operation timed out. | | [`MaximumErrno`](https://rux-lang.dev/docs/api/freebsd/errors#maximum-errno) | The largest error number the normalized error range holds. | | [`StdIn`](https://rux-lang.dev/docs/api/freebsd/files#std-in) | The descriptor a process reads its input from, unless something reassigned it. | | [`StdOut`](https://rux-lang.dev/docs/api/freebsd/files#std-out) | The descriptor a process writes its output to. | | [`StdErr`](https://rux-lang.dev/docs/api/freebsd/files#std-err) | The descriptor a process writes its diagnostics to. | | [`AtFdCwd`](https://rux-lang.dev/docs/api/freebsd/files#at-fd-cwd) | `AT_FDCWD`: resolve a relative path against the current directory rather than a descriptor. | | [`OpenReadOnly`](https://rux-lang.dev/docs/api/freebsd/files#open-read-only) | `O_RDONLY`: open for reading only. | | [`OpenWriteOnly`](https://rux-lang.dev/docs/api/freebsd/files#open-write-only) | `O_WRONLY`: open for writing only. | | [`OpenReadWrite`](https://rux-lang.dev/docs/api/freebsd/files#open-read-write) | `O_RDWR`: open for both reading and writing. | | [`OpenCreate`](https://rux-lang.dev/docs/api/freebsd/files#open-create) | `O_CREAT`: create the file when it does not exist, which is when the mode argument is read. | | [`OpenExclusive`](https://rux-lang.dev/docs/api/freebsd/files#open-exclusive) | `O_EXCL`: with [`OpenCreate`](https://rux-lang.dev/docs/api/freebsd/files#open-create), fail rather than open a file that already exists. | | [`OpenTruncate`](https://rux-lang.dev/docs/api/freebsd/files#open-truncate) | `O_TRUNC`: truncate the file to nothing when opening it for writing. | | [`OpenAppend`](https://rux-lang.dev/docs/api/freebsd/files#open-append) | `O_APPEND`: every write goes to the end. | | [`OpenNonBlocking`](https://rux-lang.dev/docs/api/freebsd/files#open-non-blocking) | [`O_NONBLOCK`](https://rux-lang.dev/docs/api/freebsd/poll#o-nonblock): reads and writes report [`EAGAIN`](https://rux-lang.dev/docs/api/freebsd/errors#eagain) rather than waiting. | | [`OpenCloseOnExec`](https://rux-lang.dev/docs/api/freebsd/files#open-close-on-exec) | `O_CLOEXEC`: close this descriptor automatically when the process executes a new program. | | [`OpenDirectory`](https://rux-lang.dev/docs/api/freebsd/files#open-directory) | `O_DIRECTORY`: fail unless the target is a directory. | | [`SeekSet`](https://rux-lang.dev/docs/api/freebsd/files#seek-set) | `SEEK_SET`: measure the new offset from the start of the file. | | [`SeekCurrent`](https://rux-lang.dev/docs/api/freebsd/files#seek-current) | `SEEK_CUR`: measure the new offset from the current one. | | [`SeekEnd`](https://rux-lang.dev/docs/api/freebsd/files#seek-end) | `SEEK_END`: measure the new offset from the end of the file. | | [`RemoveDirectory`](https://rux-lang.dev/docs/api/freebsd/directories#remove-directory) | `AT_REMOVEDIR`: make [`UnlinkAt`](https://rux-lang.dev/docs/api/freebsd/directories#unlink-at) remove a directory rather than a file. | | [`SymlinkNoFollow`](https://rux-lang.dev/docs/api/freebsd/directories#symlink-no-follow) | `AT_SYMLINK_NOFOLLOW`: act on a symbolic link itself rather than on what it points at. | | [`FollowSymlinks`](https://rux-lang.dev/docs/api/freebsd/directories#follow-symlinks) | `AT_SYMLINK_FOLLOW`: make [`LinkAt`](https://rux-lang.dev/docs/api/freebsd/directories#link-at) link a symbolic link's target rather than the link. | | [`ProtectionNone`](https://rux-lang.dev/docs/api/freebsd/memory#protection-none) | `PROT_NONE`: the pages may not be touched at all. | | [`ProtectionRead`](https://rux-lang.dev/docs/api/freebsd/memory#protection-read) | `PROT_READ`: the pages may be read. | | [`ProtectionWrite`](https://rux-lang.dev/docs/api/freebsd/memory#protection-write) | `PROT_WRITE`: the pages may be written. | | [`ProtectionExecute`](https://rux-lang.dev/docs/api/freebsd/memory#protection-execute) | `PROT_EXEC`: the pages may be executed. | | [`MapShared`](https://rux-lang.dev/docs/api/freebsd/memory#map-shared) | `MAP_SHARED`: writes are visible to other mappings of the same object and reach it. | | [`MapPrivate`](https://rux-lang.dev/docs/api/freebsd/memory#map-private) | `MAP_PRIVATE`: writes are private to this mapping and never reach the object. | | [`MapFixed`](https://rux-lang.dev/docs/api/freebsd/memory#map-fixed) | `MAP_FIXED`: place the mapping exactly at the requested address, replacing whatever was there. | | [`MapExclusive`](https://rux-lang.dev/docs/api/freebsd/memory#map-exclusive) | `MAP_EXCL`: with [`MapFixed`](https://rux-lang.dev/docs/api/freebsd/memory#map-fixed), refuse the address rather than replace what occupies it. | | [`MapAnonymous`](https://rux-lang.dev/docs/api/freebsd/memory#map-anonymous) | `MAP_ANON`: the mapping is backed by zeroed pages rather than by a file. | | [`AdviseNormal`](https://rux-lang.dev/docs/api/freebsd/memory#advise-normal) | `MADV_NORMAL`: no advice; the default. | | [`AdviseRandom`](https://rux-lang.dev/docs/api/freebsd/memory#advise-random) | `MADV_RANDOM`: the pages will be touched in no useful order. | | [`AdviseSequential`](https://rux-lang.dev/docs/api/freebsd/memory#advise-sequential) | `MADV_SEQUENTIAL`: the pages will be touched in order. | | [`AdviseWillNeed`](https://rux-lang.dev/docs/api/freebsd/memory#advise-will-need) | `MADV_WILLNEED`: the pages will be read soon. | | [`AdviseDontNeed`](https://rux-lang.dev/docs/api/freebsd/memory#advise-dont-need) | `MADV_DONTNEED`: the pages are not needed soon. | | [`AdviseFree`](https://rux-lang.dev/docs/api/freebsd/memory#advise-free) | `MADV_FREE`: the pages may be reclaimed, and read back as zero if they are. | | [`CtlHardware`](https://rux-lang.dev/docs/api/freebsd/memory#ctl-hw) | `CTL_HW`: the sysctl branch describing the machine. | | [`HardwarePageSize`](https://rux-lang.dev/docs/api/freebsd/memory#hw-pagesize) | `HW_PAGESIZE`: the leaf under [`CtlHardware`](https://rux-lang.dev/docs/api/freebsd/memory#ctl-hw) holding the page size, in bytes. | | [`F_GETFL`](https://rux-lang.dev/docs/api/freebsd/poll#f-getfl) | [`F_SETFD`](https://rux-lang.dev/docs/api/freebsd/spawn#f-setfd)'s companion `F_GETFL`: the [`fcntl`](https://rux-lang.dev/docs/api/freebsd/spawn#fcntl) command that reads a descriptor's status flags. | | [`F_SETFL`](https://rux-lang.dev/docs/api/freebsd/poll#f-setfl) | `F_SETFL`: the [`fcntl`](https://rux-lang.dev/docs/api/freebsd/spawn#fcntl) command that sets a descriptor's status flags. | | [`O_NONBLOCK`](https://rux-lang.dev/docs/api/freebsd/poll#o-nonblock) | `O_NONBLOCK`: the status flag that makes a call fail with [`EAGAIN`](https://rux-lang.dev/docs/api/freebsd/errors#eagain) rather than wait. | | [`EVFILT_READ`](https://rux-lang.dev/docs/api/freebsd/poll#evfilt-read) | `EVFILT_READ`: the filter that reports a descriptor with something to read, or a connection to accept. | | [`EVFILT_WRITE`](https://rux-lang.dev/docs/api/freebsd/poll#evfilt-write) | `EVFILT_WRITE`: the filter that reports a descriptor a write would not wait on. | | [`EV_ADD`](https://rux-lang.dev/docs/api/freebsd/poll#ev-add) | `EV_ADD`: add the change's filter, or update it. | | [`EV_DELETE`](https://rux-lang.dev/docs/api/freebsd/poll#ev-delete) | `EV_DELETE`: remove the change's filter. | | [`EV_RECEIPT`](https://rux-lang.dev/docs/api/freebsd/poll#ev-receipt) | `EV_RECEIPT`: report each change as an event, with its outcome in `data`, rather than waiting. | | [`EV_ERROR`](https://rux-lang.dev/docs/api/freebsd/poll#ev-error) | `EV_ERROR`: set on an event that reports a failed change, with the error number in `data`. | | [`EV_EOF`](https://rux-lang.dev/docs/api/freebsd/poll#ev-eof) | `EV_EOF`: the peer has closed its side. | | [`CtlKernel`](https://rux-lang.dev/docs/api/freebsd/process#ctl-kern) | `CTL_KERN`: the sysctl branch describing the kernel and its processes. | | [`KernelProcess`](https://rux-lang.dev/docs/api/freebsd/process#kern-proc) | `KERN_PROC`: the leaf under [`CtlKernel`](https://rux-lang.dev/docs/api/freebsd/process#ctl-kern) describing processes. | | [`KernelProcessPathname`](https://rux-lang.dev/docs/api/freebsd/process#kern-proc-pathname) | `KERN_PROC_PATHNAME`: the leaf under [`KernelProcess`](https://rux-lang.dev/docs/api/freebsd/process#kern-proc) holding a process's executable path. | | [`AF_INET`](https://rux-lang.dev/docs/api/freebsd/socket#af-inet) | `AF_INET`: the IPv4 address family. | | [`AF_INET6`](https://rux-lang.dev/docs/api/freebsd/socket#af-inet6) | `AF_INET6`: the IPv6 address family. | | [`SOCK_STREAM`](https://rux-lang.dev/docs/api/freebsd/socket#sock-stream) | `SOCK_STREAM`: a connected byte stream. | | [`SOCK_DGRAM`](https://rux-lang.dev/docs/api/freebsd/socket#sock-dgram) | `SOCK_DGRAM`: individual datagrams. | | [`SOCK_CLOEXEC`](https://rux-lang.dev/docs/api/freebsd/socket#sock-cloexec) | `SOCK_CLOEXEC`: close the socket when the process starts another program. | | [`SOL_SOCKET`](https://rux-lang.dev/docs/api/freebsd/socket#sol-socket) | `SOL_SOCKET`: the level of the options every socket has. | | [`SO_REUSEADDR`](https://rux-lang.dev/docs/api/freebsd/socket#so-reuseaddr) | `SO_REUSEADDR`: let a listening address be bound again while old connections to it wind down. | | [`SO_RCVTIMEO`](https://rux-lang.dev/docs/api/freebsd/socket#so-rcvtimeo) | `SO_RCVTIMEO`: how long a receive waits. | | [`SO_SNDTIMEO`](https://rux-lang.dev/docs/api/freebsd/socket#so-sndtimeo) | `SO_SNDTIMEO`: how long a send waits. | | [`IPPROTO_TCP`](https://rux-lang.dev/docs/api/freebsd/socket#ipproto-tcp) | `IPPROTO_TCP`: the level of TCP's options. | | [`TCP_NODELAY`](https://rux-lang.dev/docs/api/freebsd/socket#tcp-nodelay) | `TCP_NODELAY`: send small writes at once rather than gathering them. | | [`IPPROTO_IPV6`](https://rux-lang.dev/docs/api/freebsd/socket#ipproto-ipv6) | `IPPROTO_IPV6`: the level of IPv6's options. | | [`IPV6_V6ONLY`](https://rux-lang.dev/docs/api/freebsd/socket#ipv6-v6only) | `IPV6_V6ONLY`: accept only IPv6 on an IPv6 socket. | | [`MSG_NOSIGNAL`](https://rux-lang.dev/docs/api/freebsd/socket#msg-nosignal) | `MSG_NOSIGNAL`: report a closed peer as an error rather than with `SIGPIPE`. | | [`F_SETFD`](https://rux-lang.dev/docs/api/freebsd/spawn#f-setfd) | `F_SETFD`: the [`fcntl`](https://rux-lang.dev/docs/api/freebsd/spawn#fcntl) command that sets a descriptor's flags. | | [`FD_CLOEXEC`](https://rux-lang.dev/docs/api/freebsd/spawn#fd-cloexec) | `FD_CLOEXEC`: close the descriptor when the process starts another program. | | [`WNOHANG`](https://rux-lang.dev/docs/api/freebsd/spawn#wnohang) | `WNOHANG`: have [`waitpid`](https://rux-lang.dev/docs/api/freebsd/spawn#waitpid) return at once when the child has not finished. | | [`SIGKILL`](https://rux-lang.dev/docs/api/freebsd/spawn#sigkill) | `SIGKILL`: the signal that ends a process at once and cannot be caught. | | [`SysGetPid`](https://rux-lang.dev/docs/api/freebsd/syscalls#sys-get-pid) | `getpid(2)`'s system-call number. | | [`SysMmap`](https://rux-lang.dev/docs/api/freebsd/syscalls#sys-mmap) | `mmap(2)`'s system-call number. | | [`SC_NPROCESSORS_ONLN`](https://rux-lang.dev/docs/api/freebsd/thread#sc-nprocessors-onln) | `_SC_NPROCESSORS_ONLN`: the [`sysconf`](https://rux-lang.dev/docs/api/freebsd/thread#sysconf) name for the number of processors currently online. | | [`UMTX_OP_WAIT_UINT_PRIVATE`](https://rux-lang.dev/docs/api/freebsd/umtx#umtx-op-wait-uint-private) | `UMTX_OP_WAIT_UINT_PRIVATE`: sleep while a 32-bit word holds the expected value. | | [`UMTX_OP_WAKE_PRIVATE`](https://rux-lang.dev/docs/api/freebsd/umtx#umtx-op-wake-private) | `UMTX_OP_WAKE_PRIVATE`: wake threads sleeping on the word. | # Timespec A duration or an instant, as seconds and nanoseconds. ```rux pub struct Timespec { pub seconds: int64; pub nanoseconds: int64; } ``` `nanoseconds` is in `[0, 999999999]` for a value the kernel produced; a value the caller builds must normalize it, since a call given more than a second's worth reports [`EINVAL`](https://rux-lang.dev/docs/api/freebsd/errors#einval) rather than carrying. ## Fields | Name | Type | Description | | ------------- | ------- | --------------------------------------------------- | | `seconds` | `int64` | Whole seconds. | | `nanoseconds` | `int64` | Nanoseconds within the second, in `[0, 999999999]`. | # Types FreeBSD's scalar types for process, file and user identifiers. ## `FileDescriptor` ```rux pub type FileDescriptor = int32 ``` A file descriptor, as the kernel numbers one. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Types.rux#L11){rel=""nofollow""} ## `FileMode` ```rux pub type FileMode = uint16 ``` A file's type and permission bits. Sixteen bits here, where Linux's `mode_t` is thirty-two. The bit meanings agree; the width does not. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Types.rux#L20){rel=""nofollow""} ## `FileOffset` ```rux pub type FileOffset = int64 ``` A byte offset within a file, 64 bits on every supported target. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Types.rux#L15){rel=""nofollow""} ## `GroupId` ```rux pub type GroupId = uint32 ``` A group identifier. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Types.rux#L28){rel=""nofollow""} ## `ProcessId` ```rux pub type ProcessId = int32 ``` A process identifier, as `getpid` and its relatives report one. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Types.rux#L7){rel=""nofollow""} ## `UserId` ```rux pub type UserId = uint32 ``` A user identifier. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Types.rux#L24){rel=""nofollow""} # Directories and links The working directory, directory entries, removal, renaming and links. ## `RemoveDirectory` ```rux pub const RemoveDirectory: int32 = 0x0800; ``` `AT_REMOVEDIR`: make [`UnlinkAt`](https://rux-lang.dev/docs/api/freebsd/directories#unlink-at) remove a directory rather than a file. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/File.rux#L121){rel=""nofollow""} ## `Getcwd` ```rux pub func Getcwd(buffer: *var char8, size: uint) -> int64 ``` Writes the current working directory's absolute path into `buffer`, NUL-terminated. Returns zero, or a negative error number — unlike Linux's, which returns the length. `ERANGE` where the buffer is too small for the answer. `buffer` must be writable for `size` bytes. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/File.rux#L156){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | ------------ | -------------------------------------------------------- | | `buffer` | `*var char8` | receives the working directory as a null-terminated path | | `size` | `uint` | how many bytes `buffer` holds | **Returns**: the bytes written including the terminator, or a negative error number ## `Chdir` ```rux pub func Chdir(path: *char8) -> int64 ``` Makes `path` the process's working directory. Returns zero, or a negative error number. The change is process-wide and immediately visible to every thread. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/File.rux#L165){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------ | -------- | ------------------------ | | `path` | `*char8` | the directory to move to | **Returns**: zero, or a negative error number ## `ReadlinkAt` ```rux pub func ReadlinkAt( directoryFd: FileDescriptor, path: *char8, buffer: *var char8, size: uint ) -> int64 ``` Reads the text a symbolic link holds into `buffer`. `directoryFd` is [`AtFdCwd`](https://rux-lang.dev/docs/api/freebsd/files#at-fd-cwd) for an ordinary path. Returns the number of bytes written, or a negative error number. The text is **not** NUL-terminated, and is silently truncated where it does not fit. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/File.rux#L178){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------------- | ---------------- | ------------------------------------------------------------------------------------------------------------------------------- | | `directoryFd` | `FileDescriptor` | the directory `path` is relative to, or [`AtFdCwd`](https://rux-lang.dev/docs/api/freebsd/files#at-fd-cwd) for an ordinary path | | `path` | `*char8` | the symbolic link to read | | `buffer` | `*var char8` | receives the link's text, without a terminator | | `size` | `uint` | how many bytes `buffer` holds | **Returns**: the bytes written, which equals `size` when the text was truncated, or a negative error number ## `SymlinkNoFollow` ```rux pub const SymlinkNoFollow: int32 = 0x0200; ``` `AT_SYMLINK_NOFOLLOW`: act on a symbolic link itself rather than on what it points at. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/File.rux#L184){rel=""nofollow""} ## `LinkAt` ```rux pub func LinkAt( oldDirectoryFd: FileDescriptor, oldPath: *char8, newDirectoryFd: FileDescriptor, newPath: *char8, flags: int32 ) -> int64 ``` Creates a hard link: `newPath` becomes a second name for the file `oldPath` names. Returns zero, or a negative error number. `flags` is zero to leave a symbolic link at `oldPath` unfollowed, or [`FollowSymlinks`](https://rux-lang.dev/docs/api/freebsd/directories#follow-symlinks) to link what it points at. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/File.rux#L241){rel=""nofollow""} **Parameters** | Name | Type | Description | | ---------------- | ---------------- | ---------------------------------------------------------------------------------------------------------------------------------- | | `oldDirectoryFd` | `FileDescriptor` | the directory `oldPath` is relative to | | `oldPath` | `*char8` | the existing name | | `newDirectoryFd` | `FileDescriptor` | the directory `newPath` is relative to | | `newPath` | `*char8` | the new name for the same file | | `flags` | `int32` | zero, or [`FollowSymlinks`](https://rux-lang.dev/docs/api/freebsd/directories#follow-symlinks) to link what a final link points at | **Returns**: zero, or a negative error number ## `FollowSymlinks` ```rux pub const FollowSymlinks: int32 = 0x0400; ``` `AT_SYMLINK_FOLLOW`: make [`LinkAt`](https://rux-lang.dev/docs/api/freebsd/directories#link-at) link a symbolic link's target rather than the link. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/File.rux#L249){rel=""nofollow""} ## `SymlinkAt` ```rux pub func SymlinkAt( target: *char8, newDirectoryFd: FileDescriptor, linkPath: *char8 ) -> int64 ``` Creates a symbolic link at `linkPath` holding `target` as its text. Returns zero, or a negative error number. The target is stored, not checked: a dangling link is created as readily as a good one, which is a property callers rely on. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/File.rux#L259){rel=""nofollow""} **Parameters** | Name | Type | Description | | ---------------- | ---------------- | ------------------------------------------------- | | `target` | `*char8` | the text the link will hold, which need not exist | | `newDirectoryFd` | `FileDescriptor` | the directory `linkPath` is relative to | | `linkPath` | `*char8` | the link to create | **Returns**: zero, or a negative error number ## `Getdirentries` ```rux pub func Getdirentries( fd: FileDescriptor, buffer: *var opaque, count: uint, position: *var int64 ) -> int64 ``` Reads directory entries from `fd` into `buffer`. The buffer holds packed `dirent` records: the file number at offset 0 (8 bytes), a seek cookie at 8 (8 bytes), the record's length at 16 (2 bytes), the entry type at 18 (1 byte), padding at 19, the name's length at 20 (2 bytes), padding at 22, and the name from 24. The kernel writes as many whole records as fit. The fourth parameter is named as macOS names `Getdirentries64`'s, which is the same output. `buffer` must be writable for `count` bytes, and `position` must be null or writable for an `int64`. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/File.rux#L275){rel=""nofollow""} **Parameters** | Name | Type | Description | | ---------- | ---------------- | -------------------------------------------------------- | | `fd` | `FileDescriptor` | an open directory descriptor | | `buffer` | `*var opaque` | receives the packed records | | `count` | `uint` | how many bytes `buffer` holds | | `position` | `*var int64` | receives the position of the block read, and may be null | **Returns**: the bytes filled, zero at the end of the directory, or a negative error number ## `UnlinkAt` ```rux pub func UnlinkAt( directoryFd: FileDescriptor, path: *char8, flags: int32 ) -> int64 ``` Removes the name `path` from its directory. `flags` is zero for a file or [`RemoveDirectory`](https://rux-lang.dev/docs/api/freebsd/directories#remove-directory) for an empty directory. Removing a name does not free the file: anything still holding it open keeps using it. `path` must be non-null and terminated. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/File.rux#L307){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------------- | ---------------- | ------------------------------------------------------------------------------------------------------------------------------- | | `directoryFd` | `FileDescriptor` | the directory `path` is relative to, or [`AtFdCwd`](https://rux-lang.dev/docs/api/freebsd/files#at-fd-cwd) for an ordinary path | | `path` | `*char8` | the name to remove | | `flags` | `int32` | zero for a file, or [`RemoveDirectory`](https://rux-lang.dev/docs/api/freebsd/directories#remove-directory) for a directory | **Returns**: zero, or a negative error number ## `MkdirAt` ```rux pub func MkdirAt( directoryFd: FileDescriptor, path: *char8, mode: FileMode ) -> int64 ``` Creates a directory named `path` with permission bits `mode`. Reports [`EEXIST`](https://rux-lang.dev/docs/api/freebsd/errors#eexist) when the name is taken, which is how this is used as a lock. `path` must be non-null and terminated. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/File.rux#L319){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------------- | ---------------- | ------------------------------------------------------------------------------------------------------------------------------- | | `directoryFd` | `FileDescriptor` | the directory `path` is relative to, or [`AtFdCwd`](https://rux-lang.dev/docs/api/freebsd/files#at-fd-cwd) for an ordinary path | | `path` | `*char8` | the directory to create | | `mode` | `FileMode` | the permission bits for it | **Returns**: zero, or a negative error number ## `RenameAt` ```rux pub func RenameAt( oldDirectoryFd: FileDescriptor, oldPath: *char8, newDirectoryFd: FileDescriptor, newPath: *char8 ) -> int64 ``` Renames `oldPath` to `newPath`, each resolved against its own directory descriptor. Within one file system this replaces any existing `newPath` atomically. Across file systems it reports [`EXDEV`](https://rux-lang.dev/docs/api/freebsd/errors#exdev) rather than copying. Both paths must be non-null and terminated. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/File.rux#L333){rel=""nofollow""} **Parameters** | Name | Type | Description | | ---------------- | ---------------- | -------------------------------------- | | `oldDirectoryFd` | `FileDescriptor` | the directory `oldPath` is relative to | | `oldPath` | `*char8` | the name to move | | `newDirectoryFd` | `FileDescriptor` | the directory `newPath` is relative to | | `newPath` | `*char8` | the name to move it to | **Returns**: zero, or a negative error number # GetRandom Fills up to `length` bytes of `buffer` with unpredictable bytes. ```rux pub func GetRandom( buffer: *var opaque, length: uint, flags: uint32 ) -> int64 ``` Returns the number of bytes actually written, or a negative error number. A request over 256 bytes may be cut short, and a caller needing the whole buffer must call again for the rest. Runs in time proportional to `length` and allocates nothing. `buffer` must be writable for `length` bytes. Treat a short count as bytes obtained, not as failure, or the unwritten tail stays whatever it held — which for a key is the worst possible outcome. ## Parameters | Name | Type | Description | | -------- | ------------- | ------------------------------------ | | `buffer` | `*var opaque` | receives the bytes | | `length` | `uint` | how many bytes to ask for | | `flags` | `uint32` | zero, or one of the `Random*` values | **Returns**: the bytes written, which may be fewer than asked for, or a negative error number ## Related ### `RandomNonBlocking` ```rux pub const RandomNonBlocking: uint32 = 1; ``` `GRND_NONBLOCK`: report rather than wait. Present for parity; FreeBSD's generator does not block. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Entropy.rux#L10){rel=""nofollow""} ### `RandomBlockingPool` ```rux pub const RandomBlockingPool: uint32 = 2; ``` `GRND_RANDOM`: accepted and ignored, which is what FreeBSD does with it. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Entropy.rux#L14){rel=""nofollow""} # Process Ending the process and asking its identifier. ## `Exit` ```rux pub func Exit(code: int32) ``` Ends the calling process with `code`. Only the low eight bits reach a waiting parent. Does not return, and nothing is flushed or destroyed on the way out. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Process.rux#L12){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------ | ------- | ---------------------------------- | | `code` | `int32` | the status to report to the parent | ## `GetPid` ```rux pub func GetPid() -> ProcessId ``` The calling process's own identifier. Cannot fail. Runs in constant time and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Process.rux#L20){rel=""nofollow""} **Returns**: the calling process's identifier ## `CtlKernel` ```rux pub const CtlKernel: int32 = 1; ``` `CTL_KERN`: the sysctl branch describing the kernel and its processes. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Process.rux#L26){rel=""nofollow""} ## `KernelProcess` ```rux pub const KernelProcess: int32 = 14; ``` `KERN_PROC`: the leaf under [`CtlKernel`](https://rux-lang.dev/docs/api/freebsd/process#ctl-kern) describing processes. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Process.rux#L30){rel=""nofollow""} ## `KernelProcessPathname` ```rux pub const KernelProcessPathname: int32 = 12; ``` `KERN_PROC_PATHNAME`: the leaf under [`KernelProcess`](https://rux-lang.dev/docs/api/freebsd/process#kern-proc) holding a process's executable path. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Process.rux#L34){rel=""nofollow""} ## `QueryExecutablePath` ```rux pub func QueryExecutablePath( buffer: *var char8, length: *var uint ) -> int64 ``` Writes the absolute path of the calling process's executable into `buffer`, NUL-terminated. This is the `kern.proc.pathname` sysctl for process `-1`, the caller. `length` holds the buffer's size on entry and, on success, the path's length including its terminator. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Process.rux#L43){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | ------------ | -------------------------------------------------- | | `buffer` | `*var char8` | receives the path | | `length` | `*var uint` | the buffer's size in bytes, then the bytes written | **Returns**: zero, or a negative error number, [`ENOMEM`](https://rux-lang.dev/docs/api/freebsd/errors#enomem) when the buffer is too short # Name resolution [`getaddrinfo`](https://rux-lang.dev/docs/api/freebsd/resolve#getaddrinfo) and the list of addresses it returns. ## `AddressInfo` ```rux pub struct AddressInfo { pub flags: int32; pub family: int32; pub socketType: int32; pub protocol: int32; pub addressLength: uint32; pub canonicalName: *char8; pub address: *opaque; pub next: *var AddressInfo; } ``` The C library's `addrinfo`: one result of [`getaddrinfo`](https://rux-lang.dev/docs/api/freebsd/resolve#getaddrinfo), linked to the next. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Resolve.rux#L10){rel=""nofollow""} **Fields** | Name | Type | Description | | --------------- | ------------------ | ---------------------------------------- | | `flags` | `int32` | Flags such as `AI_PASSIVE`. | | `family` | `int32` | The address family, or zero for any. | | `socketType` | `int32` | The socket type, or zero for any. | | `protocol` | `int32` | The protocol, or zero for any. | | `addressLength` | `uint32` | The size of `address` in bytes. | | `canonicalName` | `*char8` | The host's canonical name, or null. | | `address` | `*opaque` | The address, a `sockaddr`. | | `next` | `*var AddressInfo` | The next result, or null after the last. | ## `getaddrinfo` ```rux pub extern func getaddrinfo( node: *char8, service: *char8, hints: *AddressInfo, result: *var *var AddressInfo ) -> int32 ``` Looks up the addresses of a host and service. **See also**: <https://man.freebsd.org/cgi/man.cgi?query=getaddrinfo&sektion=3>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Resolve.rux#L39){rel=""nofollow""} **Parameters** | Name | Type | Description | | --------- | ----------------------- | ------------------------------------------------------------------------------------------------------------------ | | `node` | `*char8` | the host name or numeric address, NUL-terminated, or null | | `service` | `*char8` | the service name or port number, NUL-terminated, or null | | `hints` | `*AddressInfo` | what kind of results are wanted, or null for every kind | | `result` | `*var *var AddressInfo` | receives the first result, freed with [`freeaddrinfo`](https://rux-lang.dev/docs/api/freebsd/resolve#freeaddrinfo) | **Returns**: zero, or an `EAI_*` code ## `freeaddrinfo` ```rux pub extern func freeaddrinfo(info: *var AddressInfo) ``` Frees the results of [`getaddrinfo`](https://rux-lang.dev/docs/api/freebsd/resolve#getaddrinfo). **See also**: <https://man.freebsd.org/cgi/man.cgi?query=freeaddrinfo&sektion=3>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Resolve.rux#L45){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------ | ------------------ | ---------------- | | `info` | `*var AddressInfo` | the first result | # Starting processes `posix_spawn` and its file actions, and waiting for and signalling a child. ## `SpawnFileActions` ```rux pub struct SpawnFileActions { // private fields } ``` Room for a `posix_spawn_file_actions_t`, which each C library sizes its own way and none larger than this. Only ever passed by address to the `posix_spawn_file_actions_*` calls, which initialize and read it. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Spawn.rux#L14){rel=""nofollow""} **Constructors** ### `SpawnFileActions` ```rux pub func SpawnFileActions() -> SpawnFileActions ``` Zeroed storage for [`posix_spawn_file_actions_init`](https://rux-lang.dev/docs/api/freebsd/spawn#posix-spawn-file-actions-init) to initialize. **Returns**: the storage [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Spawn.rux#L22){rel=""nofollow""} ## `F_SETFD` ```rux pub const F_SETFD: int32 = 2; ``` `F_SETFD`: the [`fcntl`](https://rux-lang.dev/docs/api/freebsd/spawn#fcntl) command that sets a descriptor's flags. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Spawn.rux#L30){rel=""nofollow""} ## `FD_CLOEXEC` ```rux pub const FD_CLOEXEC: int32 = 1; ``` `FD_CLOEXEC`: close the descriptor when the process starts another program. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Spawn.rux#L35){rel=""nofollow""} ## `WNOHANG` ```rux pub const WNOHANG: int32 = 1; ``` `WNOHANG`: have [`waitpid`](https://rux-lang.dev/docs/api/freebsd/spawn#waitpid) return at once when the child has not finished. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Spawn.rux#L40){rel=""nofollow""} ## `SIGKILL` ```rux pub const SIGKILL: int32 = 9; ``` `SIGKILL`: the signal that ends a process at once and cannot be caught. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Spawn.rux#L45){rel=""nofollow""} ## `posix_spawnp` ```rux pub extern func posix_spawnp( pid: *var int32, file: *char8, fileActions: *SpawnFileActions, attributes: *opaque, arguments: **char8, environment: **char8 ) -> int32 ``` Starts `file`, found through `PATH` when it has no slash, as a child process. **See also**: <https://man.freebsd.org/cgi/man.cgi?query=posix_spawn&sektion=3>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Spawn.rux#L59){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------------- | ------------------- | ---------------------------------------------------------------------- | | `pid` | `*var int32` | receives the child's process identifier | | `file` | `*char8` | the program, NUL-terminated | | `fileActions` | `*SpawnFileActions` | the descriptor and directory setup to run in the child first, or null | | `attributes` | `*opaque` | spawn attributes, or null for the defaults | | `arguments` | `**char8` | the argument vector, its first entry the program's name, ended by null | | `environment` | `**char8` | the environment, `NAME=VALUE` entries ended by null | **Returns**: zero, or an error number ## `posix_spawn_file_actions_init` ```rux pub extern func posix_spawn_file_actions_init(actions: *var SpawnFileActions) -> int32 ``` Initializes an empty list of file actions. **See also**: <https://man.freebsd.org/cgi/man.cgi?query=posix_spawn_file_actions_init&sektion=3>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Spawn.rux#L67){rel=""nofollow""} **Parameters** | Name | Type | Description | | --------- | ----------------------- | ------------------------- | | `actions` | `*var SpawnFileActions` | the storage to initialize | **Returns**: zero, or an error number ## `posix_spawn_file_actions_destroy` ```rux pub extern func posix_spawn_file_actions_destroy(actions: *var SpawnFileActions) -> int32 ``` Releases what [`posix_spawn_file_actions_init`](https://rux-lang.dev/docs/api/freebsd/spawn#posix-spawn-file-actions-init) and the actions added since set up. **See also**: <https://man.freebsd.org/cgi/man.cgi?query=posix_spawn_file_actions_destroy&sektion=3>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Spawn.rux#L74){rel=""nofollow""} **Parameters** | Name | Type | Description | | --------- | ----------------------- | ------------------------ | | `actions` | `*var SpawnFileActions` | initialized file actions | **Returns**: zero, or an error number ## `posix_spawn_file_actions_adddup2` ```rux pub extern func posix_spawn_file_actions_adddup2( actions: *var SpawnFileActions, fd: int32, newFd: int32 ) -> int32 ``` Adds an action duplicating `fd` onto `newFd` in the child. **See also**: <https://man.freebsd.org/cgi/man.cgi?query=posix_spawn_file_actions_adddup2&sektion=3>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Spawn.rux#L83){rel=""nofollow""} **Parameters** | Name | Type | Description | | --------- | ----------------------- | --------------------------- | | `actions` | `*var SpawnFileActions` | initialized file actions | | `fd` | `int32` | the descriptor to duplicate | | `newFd` | `int32` | the descriptor it becomes | **Returns**: zero, or an error number ## `posix_spawn_file_actions_addopen` ```rux pub extern func posix_spawn_file_actions_addopen( actions: *var SpawnFileActions, fd: int32, path: *char8, flags: int32, mode: FileMode ) -> int32 ``` Adds an action opening `path` as `fd` in the child. **See also**: <https://man.freebsd.org/cgi/man.cgi?query=posix_spawn_file_actions_addopen&sektion=3>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Spawn.rux#L94){rel=""nofollow""} **Parameters** | Name | Type | Description | | --------- | ----------------------- | ------------------------------------------ | | `actions` | `*var SpawnFileActions` | initialized file actions | | `fd` | `int32` | the descriptor the file becomes | | `path` | `*char8` | the file, NUL-terminated | | `flags` | `int32` | the open flags | | `mode` | `FileMode` | the permissions of a file the open creates | **Returns**: zero, or an error number ## `posix_spawn_file_actions_addchdir_np` ```rux pub extern func posix_spawn_file_actions_addchdir_np( actions: *var SpawnFileActions, path: *char8 ) -> int32 ``` Adds an action changing the child's working directory to `path`. **See also**: <https://man.freebsd.org/cgi/man.cgi?query=posix_spawn_file_actions_addchdir_np&sektion=3>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Spawn.rux#L103){rel=""nofollow""} **Parameters** | Name | Type | Description | | --------- | ----------------------- | ----------------------------- | | `actions` | `*var SpawnFileActions` | initialized file actions | | `path` | `*char8` | the directory, NUL-terminated | **Returns**: zero, or an error number ## `waitpid` ```rux pub extern func waitpid( pid: int32, status: *var int32, options: int32 ) -> int32 ``` Waits for a child to change state, and reports how it finished. **See also**: <https://man.freebsd.org/cgi/man.cgi?query=waitpid&sektion=2>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Spawn.rux#L112){rel=""nofollow""} **Parameters** | Name | Type | Description | | --------- | ------------ | ----------------------------------------------------------------------------------------------------------------------------------- | | `pid` | `int32` | the child's process identifier | | `status` | `*var int32` | receives the encoded status | | `options` | `int32` | zero to wait, or [`WNOHANG`](https://rux-lang.dev/docs/api/freebsd/spawn#wnohang) to return at once when the child is still running | **Returns**: the child's identifier, zero with [`WNOHANG`](https://rux-lang.dev/docs/api/freebsd/spawn#wnohang) when it is still running, or -1 with the reason in errno ## `kill` ```rux pub extern func kill(pid: int32, signal: int32) -> int32 ``` Sends a signal to a process. **See also**: <https://man.freebsd.org/cgi/man.cgi?query=kill&sektion=2>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Spawn.rux#L120){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | ------- | ------------------------------------------------------------------------------------------- | | `pid` | `int32` | the process | | `signal` | `int32` | the signal number, such as [`SIGKILL`](https://rux-lang.dev/docs/api/freebsd/spawn#sigkill) | **Returns**: zero, or -1 with the reason in errno ## `fcntl` ```rux pub extern func fcntl( fd: int32, command: int32, ... ) -> int32 ``` Performs a control operation on a descriptor, such as setting its flags with [`F_SETFD`](https://rux-lang.dev/docs/api/freebsd/spawn#f-setfd). **See also**: <https://man.freebsd.org/cgi/man.cgi?query=fcntl&sektion=2>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Spawn.rux#L128){rel=""nofollow""} **Parameters** | Name | Type | Description | | --------- | ------- | -------------- | | `fd` | `int32` | the descriptor | | `command` | `int32` | the operation | | `...` | | | **Returns**: the operation's result, or -1 with the reason in errno ## `__error` ```rux pub extern func __error() -> *var int32 ``` Returns the address of the calling thread's errno, where the C library calls above leave their reason. **See also**: <https://man.freebsd.org/cgi/man.cgi?query=errno&sektion=2>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Spawn.rux#L134){rel=""nofollow""} **Returns**: the errno's address # System calls The raw system-call entry points and the call numbers they take. ## `SysGetPid` ```rux pub const SysGetPid: uint64 = 20; ``` `getpid(2)`'s system-call number. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Syscall.rux#L20){rel=""nofollow""} ## `SysMmap` ```rux pub const SysMmap: uint64 = 477; ``` `mmap(2)`'s system-call number. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Syscall.rux#L26){rel=""nofollow""} ## `Syscall0` ```rux pub func Syscall0(number: uint64) -> int64 ``` Executes a raw FreeBSD system call without arguments. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Syscall.rux#L76){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | -------- | ----------------------- | | `number` | `uint64` | the system call to make | **Returns**: the kernel's raw result ## `Syscall6` ```rux pub func Syscall6( number: uint64, arg0: uint64, arg1: uint64, arg2: uint64, arg3: uint64, arg4: uint64, arg5: uint64 ) -> int64 ``` Executes a raw FreeBSD system call with six arguments. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Syscall.rux#L166){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | -------- | -------------------------- | | `number` | `uint64` | the system call to make | | `arg0` | `uint64` | the call's first argument | | `arg1` | `uint64` | the call's second argument | | `arg2` | `uint64` | the call's third argument | | `arg3` | `uint64` | the call's fourth argument | | `arg4` | `uint64` | the call's fifth argument | | `arg5` | `uint64` | the call's sixth argument | **Returns**: the kernel's raw result ## `SignExtendFd` ```rux pub func SignExtendFd(fd: int32) -> uint64 ``` Widens a file descriptor to the register width a system call takes it in. `fd` is read by value; the widened value is returned by copy. Sign extension is what matters: `-1` has to arrive as all ones rather than as a small positive number. Cannot fail. Runs in constant time and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Syscall.rux#L281){rel=""nofollow""} **Parameters** | Name | Type | Description | | ---- | ------- | ----------------------- | | `fd` | `int32` | the descriptor to widen | **Returns**: it sign-extended, so a negative one stays negative # Threads POSIX threads: starting, joining and detaching them, their stack size, and the processor count. ## `PThread` ```rux pub type PThread = uint64 ``` A thread as the C library names it, `pthread_t`. Every system this package family binds keeps it in one word. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Thread.rux#L15){rel=""nofollow""} ## `PThreadAttributes` ```rux pub struct PThreadAttributes { // private fields } ``` Room for a `pthread_attr_t`, which each C library sizes its own way and none larger than this. Only ever passed by address to the `pthread_attr_*` calls, which initialize and read it. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Thread.rux#L20){rel=""nofollow""} **Constructors** ### `PThreadAttributes` ```rux pub func PThreadAttributes() -> PThreadAttributes ``` Zeroed storage for [`pthread_attr_init`](https://rux-lang.dev/docs/api/freebsd/thread#pthread-attr-init) to initialize. **Returns**: the storage [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Thread.rux#L28){rel=""nofollow""} ## `SC_NPROCESSORS_ONLN` ```rux pub const SC_NPROCESSORS_ONLN: int32 = 58; ``` `_SC_NPROCESSORS_ONLN`: the [`sysconf`](https://rux-lang.dev/docs/api/freebsd/thread#sysconf) name for the number of processors currently online. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Thread.rux#L36){rel=""nofollow""} ## `pthread_create` ```rux pub extern func pthread_create( thread: *var PThread, attributes: *PThreadAttributes, start: *opaque, argument: *var opaque ) -> int32 ``` Starts a thread running `start(argument)`. **See also**: <https://man.freebsd.org/cgi/man.cgi?query=pthread_create&sektion=3>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Thread.rux#L48){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------------ | -------------------- | --------------------------------------------------------------------- | | `thread` | `*var PThread` | receives the new thread | | `attributes` | `*PThreadAttributes` | initialized attributes, or null for the defaults | | `start` | `*opaque` | the thread's entry point, a function taking and returning one pointer | | `argument` | `*var opaque` | the value handed to the entry point | **Returns**: zero, or an error number ## `pthread_join` ```rux pub extern func pthread_join( thread: PThread, result: *var *var opaque ) -> int32 ``` Waits for a thread to finish and releases it. **See also**: <https://man.freebsd.org/cgi/man.cgi?query=pthread_join&sektion=3>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Thread.rux#L57){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | ------------------ | ----------------------------------------------------------------- | | `thread` | `PThread` | a thread nothing has joined or detached | | `result` | `*var *var opaque` | receives the value its entry point returned, or null to ignore it | **Returns**: zero, or an error number ## `pthread_detach` ```rux pub extern func pthread_detach(thread: PThread) -> int32 ``` Lets a thread release itself when it finishes, so nothing has to join it. **See also**: <https://man.freebsd.org/cgi/man.cgi?query=pthread_detach&sektion=3>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Thread.rux#L64){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | --------- | --------------------------------------- | | `thread` | `PThread` | a thread nothing has joined or detached | **Returns**: zero, or an error number ## `pthread_attr_init` ```rux pub extern func pthread_attr_init(attributes: *var PThreadAttributes) -> int32 ``` Initializes thread attributes to the defaults. **See also**: <https://man.freebsd.org/cgi/man.cgi?query=pthread_attr_init&sektion=3>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Thread.rux#L71){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------------ | ------------------------ | ------------------------- | | `attributes` | `*var PThreadAttributes` | the storage to initialize | **Returns**: zero, or an error number ## `pthread_attr_setstacksize` ```rux pub extern func pthread_attr_setstacksize( attributes: *var PThreadAttributes, size: uint ) -> int32 ``` Sets the stack size a thread started with these attributes gets. **See also**: <https://man.freebsd.org/cgi/man.cgi?query=pthread_attr_setstacksize&sektion=3>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Thread.rux#L79){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------------ | ------------------------ | ------------------------------------------------------ | | `attributes` | `*var PThreadAttributes` | initialized attributes | | `size` | `uint` | the stack size in bytes, at least the system's minimum | **Returns**: zero, or an error number ## `pthread_attr_destroy` ```rux pub extern func pthread_attr_destroy(attributes: *var PThreadAttributes) -> int32 ``` Releases what [`pthread_attr_init`](https://rux-lang.dev/docs/api/freebsd/thread#pthread-attr-init) set up. **See also**: <https://man.freebsd.org/cgi/man.cgi?query=pthread_attr_destroy&sektion=3>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Thread.rux#L86){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------------ | ------------------------ | ---------------------- | | `attributes` | `*var PThreadAttributes` | initialized attributes | **Returns**: zero, or an error number ## `pthread_getthreadid_np` ```rux pub extern func pthread_getthreadid_np() -> int32 ``` Returns the kernel's identifier for the calling thread. **See also**: <https://man.freebsd.org/cgi/man.cgi?query=pthread_getthreadid_np&sektion=3>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Thread.rux#L92){rel=""nofollow""} **Returns**: the calling thread's identifier ## `sched_yield` ```rux pub extern func sched_yield() -> int32 ``` Gives up the processor so another ready thread can run. **See also**: <https://man.freebsd.org/cgi/man.cgi?query=sched_yield&sektion=2>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Thread.rux#L102){rel=""nofollow""} **Returns**: zero, or -1 with the reason in errno ## `sysconf` ```rux pub extern func sysconf(name: int32) -> int64 ``` Reads a system configuration value. **See also**: <https://man.freebsd.org/cgi/man.cgi?query=sysconf&sektion=3>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Thread.rux#L109){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------ | ------- | -------------------------------------------------------------------------------------------------------------------- | | `name` | `int32` | the value to read, such as [`SC_NPROCESSORS_ONLN`](https://rux-lang.dev/docs/api/freebsd/thread#sc-nprocessors-onln) | **Returns**: the value, or -1 when the system has no limit or does not know the name # Clocks Reading clocks and sleeping. ## `ClockRealtime` ```rux pub const ClockRealtime: int32 = 0; ``` `CLOCK_REALTIME`: wall-clock time, which can jump when the system clock is set. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Clock.rux#L11){rel=""nofollow""} ## `ClockMonotonic` ```rux pub const ClockMonotonic: int32 = 4; ``` `CLOCK_MONOTONIC`: time since an unspecified point, which never goes backwards. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Clock.rux#L15){rel=""nofollow""} ## `ClockGetTime` ```rux pub func ClockGetTime( clockId: int32, time: *var Timespec ) -> int64 ``` Reads `clockId` into `time`. Returns zero, or a negative error number. `time` must be non-null and writable. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Clock.rux#L24){rel=""nofollow""} **Parameters** | Name | Type | Description | | --------- | --------------- | -------------------- | | `clockId` | `int32` | which clock to read | | `time` | `*var Timespec` | receives the reading | **Returns**: zero, or a negative error number ## `Nanosleep` ```rux pub func Nanosleep( request: *Timespec, remaining: *var Timespec ) -> int64 ``` Suspends the caller for the requested duration. `remaining` is written when a signal cut the wait short, and may be null. Returns zero, or a negative error number; [`EINTR`](https://rux-lang.dev/docs/api/freebsd/errors#eintr) with the unslept time in `remaining` is how a signal is reported. `request` must be non-null, and its nanoseconds must be under one second. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Clock.rux#L36){rel=""nofollow""} **Parameters** | Name | Type | Description | | ----------- | --------------- | --------------------------------------------------------------------------- | | `request` | `*Timespec` | how long to wait | | `remaining` | `*var Timespec` | receives the unslept time when a signal cut the wait short, and may be null | **Returns**: zero, or a negative error number ## `ClockMonotonicFast` ```rux pub const ClockMonotonicFast: int32 = 12; ``` `CLOCK_MONOTONIC_FAST`: like [`ClockMonotonic`](https://rux-lang.dev/docs/api/freebsd/clock#clock-monotonic), read from a cached value rather than the hardware. Cheaper and coarser. FreeBSD offers this pairing where Linux offers a coarse clock under a different number. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Clock.rux#L43){rel=""nofollow""} ## `ClockRealtimeFast` ```rux pub const ClockRealtimeFast: int32 = 10; ``` `CLOCK_REALTIME_FAST`: like [`ClockRealtime`](https://rux-lang.dev/docs/api/freebsd/clock#clock-realtime), read from a cached value. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Clock.rux#L47){rel=""nofollow""} ## `ClockProcessCpuTime` ```rux pub const ClockProcessCpuTime: int32 = 15; ``` `CLOCK_PROCESS_CPUTIME_ID`: processor time this process has used. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Clock.rux#L51){rel=""nofollow""} ## `ClockGetResolution` ```rux pub func ClockGetResolution( clockId: int32, resolution: *var Timespec ) -> int64 ``` Reads the resolution of `clockId` into `resolution`. Returns zero, or a negative error number. The resolution is the granularity the clock advances by, not the cost of reading it and not a promise about accuracy. `resolution` must be non-null and writable. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Clock.rux#L61){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------------ | --------------- | ------------------------ | | `clockId` | `int32` | which clock to describe | | `resolution` | `*var Timespec` | receives the granularity | **Returns**: zero, or a negative error number # Dynamic loading The mode flags [`dlopen`](https://rux-lang.dev/docs/api/freebsd/dynamic#dlopen) takes. ## `RTLD_LAZY` ```rux pub const RTLD_LAZY: int32 = 1; ``` `RTLD_LAZY`: resolve a function symbol the first time it is called rather than at load. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Dynamic.rux#L12){rel=""nofollow""} ## `RTLD_NOW` ```rux pub const RTLD_NOW: int32 = 2; ``` `RTLD_NOW`: resolve every symbol before [`dlopen`](https://rux-lang.dev/docs/api/freebsd/dynamic#dlopen) returns. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Dynamic.rux#L17){rel=""nofollow""} ## `RTLD_GLOBAL` ```rux pub const RTLD_GLOBAL: int32 = 256; ``` `RTLD_GLOBAL`: make this object's symbols available to objects loaded afterwards. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Dynamic.rux#L22){rel=""nofollow""} ## `RTLD_LOCAL` ```rux pub const RTLD_LOCAL: int32 = 0; ``` `RTLD_LOCAL`: keep this object's symbols to itself, which is the default. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Dynamic.rux#L27){rel=""nofollow""} ## `dlopen` ```rux pub extern func dlopen( filename: *char8, flags: int32 ) -> *var opaque ``` Loads a shared object and returns a handle to it, or null on failure. A name without a slash is resolved by the loader's own search rules, and one with a slash as a path. A second call for an object already loaded returns the same handle and raises its reference count rather than loading it twice. Failure is reported through [`dlerror`](https://rux-lang.dev/docs/api/freebsd/dynamic#dlerror), not errno. **See also**: <https://man.freebsd.org/cgi/man.cgi?query=dlopen>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Dynamic.rux#L40){rel=""nofollow""} **Parameters** | Name | Type | Description | | ---------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `filename` | `*char8` | a NUL-terminated name or path, or null for the main program | | `flags` | `int32` | [`RTLD_LAZY`](https://rux-lang.dev/docs/api/freebsd/dynamic#rtld-lazy) or [`RTLD_NOW`](https://rux-lang.dev/docs/api/freebsd/dynamic#rtld-now), combined with the other `RTLD_*` flags | **Returns**: a handle for [`dlsym`](https://rux-lang.dev/docs/api/freebsd/dynamic#dlsym) and [`dlclose`](https://rux-lang.dev/docs/api/freebsd/dynamic#dlclose), or null with the reason in [`dlerror`](https://rux-lang.dev/docs/api/freebsd/dynamic#dlerror) ## `dlsym` ```rux pub extern func dlsym( handle: *var opaque, symbol: *char8 ) -> *var opaque ``` Finds a symbol in a loaded object and returns its address, or null. A null return is ambiguous, since a symbol whose address is legitimately zero exists. Clear [`dlerror`](https://rux-lang.dev/docs/api/freebsd/dynamic#dlerror) by calling it, then call this, then read [`dlerror`](https://rux-lang.dev/docs/api/freebsd/dynamic#dlerror) again to tell the two apart. **See also**: <https://man.freebsd.org/cgi/man.cgi?query=dlsym>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Dynamic.rux#L50){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | ------------- | ------------------------------------------------------------------------------ | | `handle` | `*var opaque` | a handle from [`dlopen`](https://rux-lang.dev/docs/api/freebsd/dynamic#dlopen) | | `symbol` | `*char8` | the NUL-terminated symbol name | **Returns**: the symbol's address, or null ## `dlclose` ```rux pub extern func dlclose(handle: *var opaque) -> int32 ``` Drops one reference to a loaded object, unloading it when the last one goes. Every address obtained from the object through [`dlsym`](https://rux-lang.dev/docs/api/freebsd/dynamic#dlsym) becomes invalid once it is actually unloaded, which this gives no way to observe. **See also**: <https://man.freebsd.org/cgi/man.cgi?query=dlclose>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Dynamic.rux#L59){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | ------------- | ------------------------------------------------------------------------------ | | `handle` | `*var opaque` | a handle from [`dlopen`](https://rux-lang.dev/docs/api/freebsd/dynamic#dlopen) | **Returns**: zero on success, and non-zero with the reason in [`dlerror`](https://rux-lang.dev/docs/api/freebsd/dynamic#dlerror) ## `dlerror` ```rux pub extern func dlerror() -> *char8 ``` Reports the most recent loader error and clears it, or returns null when there is none. The message points at storage the loader owns and a later call may reuse. Reading it clears the error, so two calls in a row report the second as no error at all. **See also**: <https://man.freebsd.org/cgi/man.cgi?query=dlerror>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Dynamic.rux#L67){rel=""nofollow""} **Returns**: a NUL-terminated message, or null # Errors The error numbers, and telling a raw result from an error. ## `EPERM` ```rux pub const EPERM: int64 = 1; ``` `EPERM`: the operation is not permitted to this caller. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Errors.rux#L12){rel=""nofollow""} ## `ENOENT` ```rux pub const ENOENT: int64 = 2; ``` `ENOENT`: no such file or directory. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Errors.rux#L17){rel=""nofollow""} ## `ESRCH` ```rux pub const ESRCH: int64 = 3; ``` `ESRCH`: no such process. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Errors.rux#L22){rel=""nofollow""} ## `EINTR` ```rux pub const EINTR: int64 = 4; ``` `EINTR`: the call was interrupted by a signal before it did anything. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Errors.rux#L27){rel=""nofollow""} ## `EIO` ```rux pub const EIO: int64 = 5; ``` `EIO`: a low-level input or output error. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Errors.rux#L32){rel=""nofollow""} ## `ENXIO` ```rux pub const ENXIO: int64 = 6; ``` `ENXIO`: no such device or address. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Errors.rux#L37){rel=""nofollow""} ## `EBADF` ```rux pub const EBADF: int64 = 9; ``` `EBADF`: the file descriptor is not open, or is not open for what was asked. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Errors.rux#L42){rel=""nofollow""} ## `EAGAIN` ```rux pub const EAGAIN: int64 = 35; ``` `EAGAIN`: the operation would block, and the descriptor was set not to. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Errors.rux#L47){rel=""nofollow""} ## `ENOMEM` ```rux pub const ENOMEM: int64 = 12; ``` `ENOMEM`: not enough memory to satisfy the request. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Errors.rux#L52){rel=""nofollow""} ## `EACCES` ```rux pub const EACCES: int64 = 13; ``` `EACCES`: permission denied. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Errors.rux#L57){rel=""nofollow""} ## `EFAULT` ```rux pub const EFAULT: int64 = 14; ``` `EFAULT`: an address the call was given is outside the caller's address space. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Errors.rux#L62){rel=""nofollow""} ## `EBUSY` ```rux pub const EBUSY: int64 = 16; ``` `EBUSY`: the resource is in use. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Errors.rux#L67){rel=""nofollow""} ## `EEXIST` ```rux pub const EEXIST: int64 = 17; ``` `EEXIST`: the file already exists. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Errors.rux#L72){rel=""nofollow""} ## `EXDEV` ```rux pub const EXDEV: int64 = 18; ``` `EXDEV`: the two paths are on different file systems. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Errors.rux#L77){rel=""nofollow""} ## `ENOTDIR` ```rux pub const ENOTDIR: int64 = 20; ``` `ENOTDIR`: a path component that had to be a directory is not one. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Errors.rux#L82){rel=""nofollow""} ## `EISDIR` ```rux pub const EISDIR: int64 = 21; ``` `EISDIR`: the target is a directory and the operation is not one a directory accepts. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Errors.rux#L87){rel=""nofollow""} ## `EINVAL` ```rux pub const EINVAL: int64 = 22; ``` `EINVAL`: an argument is not valid. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Errors.rux#L92){rel=""nofollow""} ## `EMFILE` ```rux pub const EMFILE: int64 = 24; ``` `EMFILE`: this process has too many descriptors open. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Errors.rux#L97){rel=""nofollow""} ## `ENOSPC` ```rux pub const ENOSPC: int64 = 28; ``` `ENOSPC`: the device has no room left. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Errors.rux#L102){rel=""nofollow""} ## `ESPIPE` ```rux pub const ESPIPE: int64 = 29; ``` `ESPIPE`: the descriptor is a pipe or socket and cannot be seeked. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Errors.rux#L107){rel=""nofollow""} ## `EROFS` ```rux pub const EROFS: int64 = 30; ``` `EROFS`: the file system is mounted read-only. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Errors.rux#L112){rel=""nofollow""} ## `EPIPE` ```rux pub const EPIPE: int64 = 32; ``` `EPIPE`: the reading end of the pipe is closed. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Errors.rux#L117){rel=""nofollow""} ## `ENAMETOOLONG` ```rux pub const ENAMETOOLONG: int64 = 63; ``` `ENAMETOOLONG`: the path or a component of it is too long. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Errors.rux#L122){rel=""nofollow""} ## `ELOOP` ```rux pub const ELOOP: int64 = 62; ``` `ELOOP`: too many symbolic links were followed resolving the path. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Errors.rux#L127){rel=""nofollow""} ## `ENOSYS` ```rux pub const ENOSYS: int64 = 78; ``` `ENOSYS`: the kernel does not implement this call. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Errors.rux#L132){rel=""nofollow""} ## `EOVERFLOW` ```rux pub const EOVERFLOW: int64 = 84; ``` `EOVERFLOW`: a value is too large for the type the call reports it in. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Errors.rux#L137){rel=""nofollow""} ## `ETIMEDOUT` ```rux pub const ETIMEDOUT: int64 = 60; ``` `ETIMEDOUT`: the operation timed out. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Errors.rux#L142){rel=""nofollow""} ## `MaximumErrno` ```rux pub const MaximumErrno: int64 = 4095; ``` The largest error number the normalized error range holds. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Errors.rux#L146){rel=""nofollow""} ## `IsError` ```rux pub func IsError(result: int64) -> bool ``` Whether a raw system-call result is one of the normalized error values. `result` is read by value. True for `-4095` through `-1`, and false for everything else, including every valid mapping address a memory call returns. Cannot fail. Runs in constant time and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Errors.rux#L155){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | ------- | ---------------------- | | `result` | `int64` | the raw result to test | **Returns**: whether it is one of the reserved error values ## `Errno` ```rux pub func Errno(result: int64) -> int64 ``` The error number a raw system-call result carries, or zero when it carries none. `result` is read by value; the number is returned by copy, positive, as a man page names it. Cannot fail. Runs in constant time and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Errors.rux#L165){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | ------- | ---------------------- | | `result` | `int64` | the raw result to read | **Returns**: the error number, positive, or zero when the result carries none # Files Opening, reading, writing and inspecting files through descriptors. ## `StdIn` ```rux pub const StdIn: int32 = 0; ``` The descriptor a process reads its input from, unless something reassigned it. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/File.rux#L14){rel=""nofollow""} ## `StdOut` ```rux pub const StdOut: int32 = 1; ``` The descriptor a process writes its output to. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/File.rux#L18){rel=""nofollow""} ## `StdErr` ```rux pub const StdErr: int32 = 2; ``` The descriptor a process writes its diagnostics to. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/File.rux#L22){rel=""nofollow""} ## `Read` ```rux pub func Read( fd: FileDescriptor, buffer: *var opaque, count: uint ) -> int64 ``` Reads up to `count` bytes from `fd` into `buffer`. `buffer` is borrowed and written. Returns the number of bytes read, zero at end of file, or a negative error number. A short count is ordinary. `buffer` must be writable for `count` bytes. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/File.rux#L33){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | ---------------- | ------------------------- | | `fd` | `FileDescriptor` | an open descriptor | | `buffer` | `*var opaque` | receives the bytes | | `count` | `uint` | how many bytes to ask for | **Returns**: the bytes read, zero at end of file, or a negative error number ## `Write` ```rux pub func Write( fd: FileDescriptor, buffer: *opaque, count: uint ) -> int64 ``` Writes up to `count` bytes from `buffer` to `fd`. `buffer` is borrowed and read. Returns the number of bytes written, or a negative error number. A short count is ordinary and the rest has to be written by calling again. `buffer` must be readable for `count` bytes. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/File.rux#L46){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | ---------------- | ----------------------- | | `fd` | `FileDescriptor` | an open descriptor | | `buffer` | `*opaque` | the bytes to write | | `count` | `uint` | how many bytes to offer | **Returns**: the bytes written, or a negative error number ## `Close` ```rux pub func Close(fd: FileDescriptor) -> int64 ``` Closes `fd` and releases what the kernel held for it. Returns zero, or a negative error number. A failure does not mean the descriptor is still open, so retrying a failed close can close one another thread has since opened under the same number. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/File.rux#L56){rel=""nofollow""} **Parameters** | Name | Type | Description | | ---- | ---------------- | ------------------ | | `fd` | `FileDescriptor` | an open descriptor | **Returns**: zero, or a negative error number ## `AtFdCwd` ```rux pub const AtFdCwd: int32 = -100; ``` `AT_FDCWD`: resolve a relative path against the current directory rather than a descriptor. FreeBSD spells this `-100`, the same value Linux uses, which is one of the few places the two agree exactly. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/File.rux#L63){rel=""nofollow""} ## `OpenReadOnly` ```rux pub const OpenReadOnly: int32 = 0x0000; ``` `O_RDONLY`: open for reading only. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/File.rux#L67){rel=""nofollow""} ## `OpenWriteOnly` ```rux pub const OpenWriteOnly: int32 = 0x0001; ``` `O_WRONLY`: open for writing only. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/File.rux#L71){rel=""nofollow""} ## `OpenReadWrite` ```rux pub const OpenReadWrite: int32 = 0x0002; ``` `O_RDWR`: open for both reading and writing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/File.rux#L75){rel=""nofollow""} ## `OpenCreate` ```rux pub const OpenCreate: int32 = 0x0200; ``` `O_CREAT`: create the file when it does not exist, which is when the mode argument is read. FreeBSD's flag bits are the BSD ones and are not Linux's: `O_CREAT` is `0x0200` here and `0x40` there. A flag value must never be carried between the two packages. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/File.rux#L81){rel=""nofollow""} ## `OpenExclusive` ```rux pub const OpenExclusive: int32 = 0x0800; ``` `O_EXCL`: with [`OpenCreate`](https://rux-lang.dev/docs/api/freebsd/files#open-create), fail rather than open a file that already exists. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/File.rux#L85){rel=""nofollow""} ## `OpenTruncate` ```rux pub const OpenTruncate: int32 = 0x0400; ``` `O_TRUNC`: truncate the file to nothing when opening it for writing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/File.rux#L89){rel=""nofollow""} ## `OpenAppend` ```rux pub const OpenAppend: int32 = 0x0008; ``` `O_APPEND`: every write goes to the end. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/File.rux#L93){rel=""nofollow""} ## `OpenNonBlocking` ```rux pub const OpenNonBlocking: int32 = 0x0004; ``` [`O_NONBLOCK`](https://rux-lang.dev/docs/api/freebsd/poll#o-nonblock): reads and writes report [`EAGAIN`](https://rux-lang.dev/docs/api/freebsd/errors#eagain) rather than waiting. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/File.rux#L97){rel=""nofollow""} ## `OpenCloseOnExec` ```rux pub const OpenCloseOnExec: int32 = 0x00100000; ``` `O_CLOEXEC`: close this descriptor automatically when the process executes a new program. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/File.rux#L101){rel=""nofollow""} ## `OpenDirectory` ```rux pub const OpenDirectory: int32 = 0x00020000; ``` `O_DIRECTORY`: fail unless the target is a directory. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/File.rux#L105){rel=""nofollow""} ## `SeekSet` ```rux pub const SeekSet: int32 = 0; ``` `SEEK_SET`: measure the new offset from the start of the file. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/File.rux#L109){rel=""nofollow""} ## `SeekCurrent` ```rux pub const SeekCurrent: int32 = 1; ``` `SEEK_CUR`: measure the new offset from the current one. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/File.rux#L113){rel=""nofollow""} ## `SeekEnd` ```rux pub const SeekEnd: int32 = 2; ``` `SEEK_END`: measure the new offset from the end of the file. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/File.rux#L117){rel=""nofollow""} ## `OpenAt` ```rux pub func OpenAt( directoryFd: FileDescriptor, path: *char8, flags: int32, mode: FileMode ) -> int64 ``` Opens `path` relative to `directoryFd` and returns a descriptor, or a negative error number. `directoryFd` is [`AtFdCwd`](https://rux-lang.dev/docs/api/freebsd/files#at-fd-cwd) for an ordinary path. `mode` is read only when [`OpenCreate`](https://rux-lang.dev/docs/api/freebsd/files#open-create) is set. `path` must be non-null and terminated. The mode is masked by the process umask. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/File.rux#L132){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------------- | ---------------- | ------------------------------------------------------------------------------------------------------------------------------- | | `directoryFd` | `FileDescriptor` | the directory `path` is relative to, or [`AtFdCwd`](https://rux-lang.dev/docs/api/freebsd/files#at-fd-cwd) for an ordinary path | | `path` | `*char8` | the path to open, as a null-terminated byte string | | `flags` | `int32` | the access mode and the open flags, combined with `|` | | `mode` | `FileMode` | the permission bits for a file this creates, ignored otherwise | **Returns**: the new descriptor, or a negative error number ## `Lseek` ```rux pub func Lseek( fd: FileDescriptor, offset: FileOffset, whence: int32 ) -> int64 ``` Moves the file offset of `fd` and returns where it ended up, or a negative error number. Seeking past the end creates a hole when something is later written there. A pipe reports [`ESPIPE`](https://rux-lang.dev/docs/api/freebsd/errors#espipe). [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/File.rux#L144){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | ---------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `fd` | `FileDescriptor` | an open descriptor | | `offset` | `FileOffset` | how far to move, interpreted according to `whence` | | `whence` | `int32` | [`SeekSet`](https://rux-lang.dev/docs/api/freebsd/files#seek-set), [`SeekCurrent`](https://rux-lang.dev/docs/api/freebsd/files#seek-current) or [`SeekEnd`](https://rux-lang.dev/docs/api/freebsd/files#seek-end) | **Returns**: the resulting offset from the start, or a negative error number ## `FstatAt` ```rux pub func FstatAt( directoryFd: FileDescriptor, path: *char8, statBuffer: *var opaque, flags: int32 ) -> int64 ``` Fills `statBuffer` with what the kernel knows about the file `path` names. `directoryFd` is [`AtFdCwd`](https://rux-lang.dev/docs/api/freebsd/files#at-fd-cwd) for an ordinary path. `flags` is zero to follow a symbolic link at the end of the path, or [`SymlinkNoFollow`](https://rux-lang.dev/docs/api/freebsd/directories#symlink-no-follow) to describe the link itself. Returns zero, or a negative error number. `statBuffer` must be writable for the whole of `struct stat`, which is 224 bytes and whose layout this package does not model. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/File.rux#L197){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------------- | ---------------- | --------------------------------------------------------------------------------------------------------------------------------- | | `directoryFd` | `FileDescriptor` | the directory `path` is relative to, or [`AtFdCwd`](https://rux-lang.dev/docs/api/freebsd/files#at-fd-cwd) for an ordinary path | | `path` | `*char8` | the path to describe | | `statBuffer` | `*var opaque` | receives the architecture's `struct stat` | | `flags` | `int32` | zero to follow a final symbolic link, or [`SymlinkNoFollow`](https://rux-lang.dev/docs/api/freebsd/directories#symlink-no-follow) | **Returns**: zero, or a negative error number ## `FchmodAt` ```rux pub func FchmodAt( directoryFd: FileDescriptor, path: *char8, mode: FileMode, flags: int32 ) -> int64 ``` Sets the permission bits of the file `path` names. `directoryFd` is [`AtFdCwd`](https://rux-lang.dev/docs/api/freebsd/files#at-fd-cwd) for an ordinary path. `flags` may carry [`SymlinkNoFollow`](https://rux-lang.dev/docs/api/freebsd/directories#symlink-no-follow). Returns zero, or a negative error number. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/File.rux#L211){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------------- | ---------------- | ------------------------------------------------------------------------------------------------------------------------------- | | `directoryFd` | `FileDescriptor` | the directory `path` is relative to, or [`AtFdCwd`](https://rux-lang.dev/docs/api/freebsd/files#at-fd-cwd) for an ordinary path | | `path` | `*char8` | the path whose bits are set | | `mode` | `FileMode` | the permission bits to set | | `flags` | `int32` | zero, or [`SymlinkNoFollow`](https://rux-lang.dev/docs/api/freebsd/directories#symlink-no-follow) where the system supports it | **Returns**: zero, or a negative error number ## `UtimensAt` ```rux pub func UtimensAt( directoryFd: FileDescriptor, path: *char8, times: *opaque, flags: int32 ) -> int64 ``` Sets the access and modification times of the file `path` names. `times` is borrowed and holds two `timespec` values — access first, then modification — each a whole-second count and a nanosecond fraction, both 8 bytes. A null `times` sets both to now. `flags` may carry [`SymlinkNoFollow`](https://rux-lang.dev/docs/api/freebsd/directories#symlink-no-follow). Returns zero, or a negative error number. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/File.rux#L226){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------------- | ---------------- | --------------------------------------------------------------------------------------------------------------------------------- | | `directoryFd` | `FileDescriptor` | the directory `path` is relative to, or [`AtFdCwd`](https://rux-lang.dev/docs/api/freebsd/files#at-fd-cwd) for an ordinary path | | `path` | `*char8` | the path whose times are set | | `times` | `*opaque` | two `timespec` values, or null for now | | `flags` | `int32` | zero to follow a final symbolic link, or [`SymlinkNoFollow`](https://rux-lang.dev/docs/api/freebsd/directories#symlink-no-follow) | **Returns**: zero, or a negative error number ## `Fsync` ```rux pub func Fsync(fd: FileDescriptor) -> int64 ``` Flushes everything written to `fd` through to the storage device. Returns zero, or a negative error number. Without it, data a successful [`Write`](https://rux-lang.dev/docs/api/freebsd/files#write) reported may still be lost. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/File.rux#L284){rel=""nofollow""} **Parameters** | Name | Type | Description | | ---- | ---------------- | ------------------ | | `fd` | `FileDescriptor` | an open descriptor | **Returns**: zero, or a negative error number ## `Ftruncate` ```rux pub func Ftruncate( fd: FileDescriptor, length: FileOffset ) -> int64 ``` Sets the length of the file behind `fd` to `length`. Growing creates a hole rather than allocating, so a later write into it can still fail with [`ENOSPC`](https://rux-lang.dev/docs/api/freebsd/errors#enospc). [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/File.rux#L294){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | ---------------- | ---------------------------------------- | | `fd` | `FileDescriptor` | an open descriptor | | `length` | `FileOffset` | the size the file should have afterwards | **Returns**: zero, or a negative error number ## `Fstat` ```rux pub func Fstat( fd: FileDescriptor, statBuffer: *var opaque ) -> int64 ``` Fills `statBuffer` with what the kernel knows about the file behind `fd`. The kernel's `struct stat` is not modelled here: its layout is FreeBSD's own and differs from Linux's in both size and field order. `statBuffer` must be writable for the whole of FreeBSD's `struct stat`, which this does not check. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/File.rux#L347){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------------ | ---------------- | ----------------------------------------- | | `fd` | `FileDescriptor` | an open descriptor | | `statBuffer` | `*var opaque` | receives the architecture's `struct stat` | **Returns**: zero, or a negative error number ## `Dup2` ```rux pub func Dup2( oldFd: FileDescriptor, newFd: FileDescriptor ) -> int64 ``` Makes `newFd` a copy of `oldFd`, closing whatever `newFd` was. Returns `newFd`, or a negative error number. Duplicating a descriptor onto itself returns it unchanged. FreeBSD has `dup2` on both architectures, so this is the plain form rather than Linux's `dup3`; setting close-on-exec is a separate [`fcntl`](https://rux-lang.dev/docs/api/freebsd/spawn#fcntl) this package does not wrap. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/File.rux#L359){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------- | ---------------- | ------------------------------------ | | `oldFd` | `FileDescriptor` | the descriptor to duplicate | | `newFd` | `FileDescriptor` | the number the duplicate should have | **Returns**: `newFd`, or a negative error number ## `Pipe2` ```rux pub func Pipe2( descriptors: *var int32, flags: int32 ) -> int64 ``` Creates a pipe and writes its two descriptors into `descriptors`. The reading end lands at index zero and the writing end at index one. `flags` may carry [`OpenCloseOnExec`](https://rux-lang.dev/docs/api/freebsd/files#open-close-on-exec) and [`OpenNonBlocking`](https://rux-lang.dev/docs/api/freebsd/files#open-non-blocking). `descriptors` must be writable for two `int32` values. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/File.rux#L371){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------------- | ------------ | ---------------------------------------------------------------------------------------------------------- | | `descriptors` | `*var int32` | receives the read end at index zero and the write end at index one | | `flags` | `int32` | zero, or [`OpenCloseOnExec`](https://rux-lang.dev/docs/api/freebsd/files#open-close-on-exec) for both ends | **Returns**: zero, or a negative error number # Memory Mapping, protecting and advising on pages of memory. ## `ProtectionNone` ```rux pub const ProtectionNone: int32 = 0x00; ``` `PROT_NONE`: the pages may not be touched at all. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Memory.rux#L10){rel=""nofollow""} ## `ProtectionRead` ```rux pub const ProtectionRead: int32 = 0x01; ``` `PROT_READ`: the pages may be read. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Memory.rux#L14){rel=""nofollow""} ## `ProtectionWrite` ```rux pub const ProtectionWrite: int32 = 0x02; ``` `PROT_WRITE`: the pages may be written. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Memory.rux#L18){rel=""nofollow""} ## `ProtectionExecute` ```rux pub const ProtectionExecute: int32 = 0x04; ``` `PROT_EXEC`: the pages may be executed. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Memory.rux#L22){rel=""nofollow""} ## `MapShared` ```rux pub const MapShared: int32 = 0x0001; ``` `MAP_SHARED`: writes are visible to other mappings of the same object and reach it. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Memory.rux#L26){rel=""nofollow""} ## `MapPrivate` ```rux pub const MapPrivate: int32 = 0x0002; ``` `MAP_PRIVATE`: writes are private to this mapping and never reach the object. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Memory.rux#L30){rel=""nofollow""} ## `MapFixed` ```rux pub const MapFixed: int32 = 0x0010; ``` `MAP_FIXED`: place the mapping exactly at the requested address, replacing whatever was there. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Memory.rux#L34){rel=""nofollow""} ## `MapExclusive` ```rux pub const MapExclusive: int32 = 0x4000; ``` `MAP_EXCL`: with [`MapFixed`](https://rux-lang.dev/docs/api/freebsd/memory#map-fixed), refuse the address rather than replace what occupies it. The one way to ask whether a range is free: a fixed, exclusive request over anything already mapped fails with [`ENOMEM`](https://rux-lang.dev/docs/api/freebsd/errors#enomem), and one over a hole takes it. [`Mprotect`](https://rux-lang.dev/docs/api/freebsd/memory#mprotect) cannot answer that question, since it skips the holes in a range rather than refusing them. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Memory.rux#L41){rel=""nofollow""} ## `MapAnonymous` ```rux pub const MapAnonymous: int32 = 0x1000; ``` `MAP_ANON`: the mapping is backed by zeroed pages rather than by a file. FreeBSD numbers this differently from Linux, which is one of the reasons the two packages are separate. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Memory.rux#L46){rel=""nofollow""} ## `Mmap` ```rux pub func Mmap( address: *opaque, length: uint, protection: int32, flags: int32, fd: int32, offset: uint64 ) -> int64 ``` Creates a mapping and returns its address, or a negative error number. `address` is a hint unless [`MapFixed`](https://rux-lang.dev/docs/api/freebsd/memory#map-fixed) is set. `fd` is the object to map, or `-1` with [`MapAnonymous`](https://rux-lang.dev/docs/api/freebsd/memory#map-anonymous). Testing the result needs `Errors::IsError` rather than a sign test, since a valid address may have its top bit set. [`MapFixed`](https://rux-lang.dev/docs/api/freebsd/memory#map-fixed) replaces whatever occupies the address, including a mapping this program depends on, unless [`MapExclusive`](https://rux-lang.dev/docs/api/freebsd/memory#map-exclusive) is set with it. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Memory.rux#L61){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------------ | --------- | -------------------------------------------------------------------------------------------------------- | | `address` | `*opaque` | a hint for where to map, or null to let the kernel choose | | `length` | `uint` | how many bytes, rounded up to whole pages | | `protection` | `int32` | what may be done with the pages, as `Protection*` flags | | `flags` | `int32` | the mapping flags, as `Map*` values | | `fd` | `int32` | the file to map, or -1 with [`MapAnonymous`](https://rux-lang.dev/docs/api/freebsd/memory#map-anonymous) | | `offset` | `uint64` | where in the file the mapping starts | **Returns**: the mapping's address, or a negative error number ## `Munmap` ```rux pub func Munmap(address: *opaque, length: uint) -> int64 ``` Releases the mapping that begins at `address` and spans `length` bytes. Returns zero, or a negative error number. Releasing a range that was never mapped succeeds and does nothing. Every pointer into the range becomes invalid. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Memory.rux#L80){rel=""nofollow""} **Parameters** | Name | Type | Description | | --------- | --------- | -------------------------------------- | | `address` | `*opaque` | a page-aligned address to release from | | `length` | `uint` | how many bytes to release | **Returns**: zero, or a negative error number ## `Brk` ```rux pub func Brk(address: *opaque) -> int64 ``` Sets the program break and returns where it ended up. Reports failure by not moving rather than by an error number. The break is a single process-wide value. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Memory.rux#L89){rel=""nofollow""} **Parameters** | Name | Type | Description | | --------- | --------- | --------------------------------------------------- | | `address` | `*opaque` | where to move the program break, or null to read it | **Returns**: the resulting break, or a negative error number ## `AdviseNormal` ```rux pub const AdviseNormal: int32 = 0; ``` `MADV_NORMAL`: no advice; the default. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Memory.rux#L95){rel=""nofollow""} ## `AdviseRandom` ```rux pub const AdviseRandom: int32 = 1; ``` `MADV_RANDOM`: the pages will be touched in no useful order. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Memory.rux#L99){rel=""nofollow""} ## `AdviseSequential` ```rux pub const AdviseSequential: int32 = 2; ``` `MADV_SEQUENTIAL`: the pages will be touched in order. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Memory.rux#L103){rel=""nofollow""} ## `AdviseWillNeed` ```rux pub const AdviseWillNeed: int32 = 3; ``` `MADV_WILLNEED`: the pages will be read soon. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Memory.rux#L107){rel=""nofollow""} ## `AdviseDontNeed` ```rux pub const AdviseDontNeed: int32 = 4; ``` `MADV_DONTNEED`: the pages are not needed soon. FreeBSD's meaning is weaker than Linux's: it does not discard the pages, so an anonymous page does not read back as zero afterwards. `MADV_FREE` is the one that lets the kernel take the storage, and that difference is exactly why an advice value must not be carried between the two packages. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Memory.rux#L114){rel=""nofollow""} ## `AdviseFree` ```rux pub const AdviseFree: int32 = 5; ``` `MADV_FREE`: the pages may be reclaimed, and read back as zero if they are. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Memory.rux#L118){rel=""nofollow""} ## `Mprotect` ```rux pub func Mprotect( address: *opaque, length: uint, protection: int32 ) -> int64 ``` Changes what may be done with the pages covering a range. `address` must be page-aligned. Returns zero, or a negative error number. Removing a permission takes effect at once, so a thread touching the range concurrently faults. Nothing checks that the range was ever mapped, and a hardened system refuses writable executable memory. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Memory.rux#L129){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------------ | --------- | ----------------------------------------- | | `address` | `*opaque` | a page-aligned address | | `length` | `uint` | how many bytes, rounded up to whole pages | | `protection` | `int32` | what may be done with them afterwards | **Returns**: zero, or a negative error number ## `Madvise` ```rux pub func Madvise( address: *opaque, length: uint, advice: int32 ) -> int64 ``` Tells the kernel how the pages covering a range are about to be used. Advice is advice: the kernel is free to ignore it. [`AdviseFree`](https://rux-lang.dev/docs/api/freebsd/memory#advise-free) is the one that actually releases storage. [`AdviseFree`](https://rux-lang.dev/docs/api/freebsd/memory#advise-free) loses whatever the range held. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Memory.rux#L141){rel=""nofollow""} **Parameters** | Name | Type | Description | | --------- | --------- | -------------------------------- | | `address` | `*opaque` | a page-aligned address | | `length` | `uint` | how many bytes the advice covers | | `advice` | `int32` | one of the `Advise*` values | **Returns**: zero, or a negative error number ## `CtlHardware` ```rux pub const CtlHardware: int32 = 6; ``` `CTL_HW`: the sysctl branch describing the machine. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Memory.rux#L146){rel=""nofollow""} ## `HardwarePageSize` ```rux pub const HardwarePageSize: int32 = 7; ``` `HW_PAGESIZE`: the leaf under [`CtlHardware`](https://rux-lang.dev/docs/api/freebsd/memory#ctl-hw) holding the page size, in bytes. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Memory.rux#L150){rel=""nofollow""} ## `QueryPageSize` ```rux pub func QueryPageSize() -> int64 ``` The size of a page, asked of the kernel. FreeBSD publishes this as the `hw.pagesize` sysctl rather than as a dedicated call, and that is the query this package uses: it needs no libc, no auxiliary vector and no state captured at process start. The value is a power of two and is the granularity [`Mmap`](https://rux-lang.dev/docs/api/freebsd/memory#mmap) rounds to. A caller that cannot use a failure has no business asking: the whole point of returning one is that a system which will not answer is not a system to guess about. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Memory.rux#L160){rel=""nofollow""} **Returns**: the page size in bytes, or a negative error number # Polling Descriptor flags and the kqueue filters a poller waits with. ## `F_GETFL` ```rux pub const F_GETFL: int32 = 3; ``` [`F_SETFD`](https://rux-lang.dev/docs/api/freebsd/spawn#f-setfd)'s companion `F_GETFL`: the [`fcntl`](https://rux-lang.dev/docs/api/freebsd/spawn#fcntl) command that reads a descriptor's status flags. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Poll.rux#L15){rel=""nofollow""} ## `F_SETFL` ```rux pub const F_SETFL: int32 = 4; ``` `F_SETFL`: the [`fcntl`](https://rux-lang.dev/docs/api/freebsd/spawn#fcntl) command that sets a descriptor's status flags. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Poll.rux#L20){rel=""nofollow""} ## `O_NONBLOCK` ```rux pub const O_NONBLOCK: int32 = 0x4; ``` `O_NONBLOCK`: the status flag that makes a call fail with [`EAGAIN`](https://rux-lang.dev/docs/api/freebsd/errors#eagain) rather than wait. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Poll.rux#L25){rel=""nofollow""} ## `EVFILT_READ` ```rux pub const EVFILT_READ: int16 = -1; ``` `EVFILT_READ`: the filter that reports a descriptor with something to read, or a connection to accept. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Poll.rux#L30){rel=""nofollow""} ## `EVFILT_WRITE` ```rux pub const EVFILT_WRITE: int16 = -2; ``` `EVFILT_WRITE`: the filter that reports a descriptor a write would not wait on. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Poll.rux#L35){rel=""nofollow""} ## `EV_ADD` ```rux pub const EV_ADD: uint16 = 0x1; ``` `EV_ADD`: add the change's filter, or update it. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Poll.rux#L40){rel=""nofollow""} ## `EV_DELETE` ```rux pub const EV_DELETE: uint16 = 0x2; ``` `EV_DELETE`: remove the change's filter. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Poll.rux#L45){rel=""nofollow""} ## `EV_RECEIPT` ```rux pub const EV_RECEIPT: uint16 = 0x40; ``` `EV_RECEIPT`: report each change as an event, with its outcome in `data`, rather than waiting. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Poll.rux#L50){rel=""nofollow""} ## `EV_ERROR` ```rux pub const EV_ERROR: uint16 = 0x4000; ``` `EV_ERROR`: set on an event that reports a failed change, with the error number in `data`. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Poll.rux#L55){rel=""nofollow""} ## `EV_EOF` ```rux pub const EV_EOF: uint16 = 0x8000; ``` `EV_EOF`: the peer has closed its side. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Poll.rux#L60){rel=""nofollow""} ## `Kevent` ```rux pub struct Kevent { pub ident: uint64; pub filter: int16; pub flags: uint16; pub filterFlags: uint32; pub data: int64; pub userData: uint64; pub extension: uint64[N]; } ``` One `struct kevent` as FreeBSD 12 and later lay it out: a change to register or an event to report. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Poll.rux#L64){rel=""nofollow""} **Fields** | Name | Type | Description | | ------------- | ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `ident` | `uint64` | The descriptor. | | `filter` | `int16` | [`EVFILT_READ`](https://rux-lang.dev/docs/api/freebsd/poll#evfilt-read) or [`EVFILT_WRITE`](https://rux-lang.dev/docs/api/freebsd/poll#evfilt-write). | | `flags` | `uint16` | [`EV_ADD`](https://rux-lang.dev/docs/api/freebsd/poll#ev-add), [`EV_DELETE`](https://rux-lang.dev/docs/api/freebsd/poll#ev-delete) and the flags reported back, such as [`EV_EOF`](https://rux-lang.dev/docs/api/freebsd/poll#ev-eof) and [`EV_ERROR`](https://rux-lang.dev/docs/api/freebsd/poll#ev-error). | | `filterFlags` | `uint32` | Filter-specific flags. | | `data` | `int64` | Filter-specific data: bytes ready, or an error number. | | `userData` | `uint64` | The word the caller chose, reported back with every event. | | `extension` | `uint64[N]` | Extensions the kernel uses and returns; zero in a change. | **Associated functions** ### `Of` ```rux pub func Of( ident: uint64, filter: int16, flags: uint16, userData: uint64 ) -> Kevent ``` A change or an empty event: `filter` on `ident` with `flags`, reporting `userData`. | Name | Type | Description | | ---------- | -------- | --------------------------------------------------------------------- | | `ident` | `uint64` | the descriptor | | `filter` | `int16` | the filter | | `flags` | `uint16` | such as [`EV_ADD`](https://rux-lang.dev/docs/api/freebsd/poll#ev-add) | | `userData` | `uint64` | the word to report | **Returns**: the kevent [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Poll.rux#L89){rel=""nofollow""} ## `FcntlInt` ```rux pub func FcntlInt( fd: FileDescriptor, command: int32, argument: int64 ) -> int64 ``` Performs `command` on a descriptor with an integer argument. **See also**: <https://man.freebsd.org/cgi/man.cgi?query=fcntl&sektion=2>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Poll.rux#L102){rel=""nofollow""} **Parameters** | Name | Type | Description | | ---------- | ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------ | | `fd` | `FileDescriptor` | the descriptor | | `command` | `int32` | such as [`F_GETFL`](https://rux-lang.dev/docs/api/freebsd/poll#f-getfl) or [`F_SETFL`](https://rux-lang.dev/docs/api/freebsd/poll#f-setfl) | | `argument` | `int64` | the command's argument, or zero | **Returns**: the command's result, or a negative error number ## `Kqueue` ```rux pub func Kqueue() -> int64 ``` Opens a kqueue. **See also**: <https://man.freebsd.org/cgi/man.cgi?query=kqueue&sektion=2>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Poll.rux#L110){rel=""nofollow""} **Returns**: the kqueue's descriptor, or a negative error number ## `KeventCall` ```rux pub func KeventCall( queue: FileDescriptor, changes: *Kevent, changeCount: int32, events: *var Kevent, eventCount: int32, timeout: *Timespec ) -> int64 ``` Applies `changeCount` changes, then waits until an event is ready or `timeout` passes, filling `events`. **See also**: <https://man.freebsd.org/cgi/man.cgi?query=kevent&sektion=2>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Poll.rux#L124){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------------- | ---------------- | --------------------------------------------- | | `queue` | `FileDescriptor` | the kqueue | | `changes` | `*Kevent` | the changes to apply, or null | | `changeCount` | `int32` | how many changes there are | | `events` | `*var Kevent` | room for `eventCount` events, or null | | `eventCount` | `int32` | how many events fit | | `timeout` | `*Timespec` | how long to wait, or null to wait without end | **Returns**: how many events were filled, or a negative error number # Sockets Address families, socket types and options, and the calls that open, bind and connect sockets. ## `AF_INET` ```rux pub const AF_INET: int32 = 2; ``` `AF_INET`: the IPv4 address family. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Socket.rux#L22){rel=""nofollow""} ## `AF_INET6` ```rux pub const AF_INET6: int32 = 28; ``` `AF_INET6`: the IPv6 address family. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Socket.rux#L27){rel=""nofollow""} ## `SOCK_STREAM` ```rux pub const SOCK_STREAM: int32 = 1; ``` `SOCK_STREAM`: a connected byte stream. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Socket.rux#L32){rel=""nofollow""} ## `SOCK_DGRAM` ```rux pub const SOCK_DGRAM: int32 = 2; ``` `SOCK_DGRAM`: individual datagrams. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Socket.rux#L37){rel=""nofollow""} ## `SOCK_CLOEXEC` ```rux pub const SOCK_CLOEXEC: int32 = 0x10000000; ``` `SOCK_CLOEXEC`: close the socket when the process starts another program. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Socket.rux#L42){rel=""nofollow""} ## `SOL_SOCKET` ```rux pub const SOL_SOCKET: int32 = 0xffff; ``` `SOL_SOCKET`: the level of the options every socket has. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Socket.rux#L47){rel=""nofollow""} ## `SO_REUSEADDR` ```rux pub const SO_REUSEADDR: int32 = 4; ``` `SO_REUSEADDR`: let a listening address be bound again while old connections to it wind down. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Socket.rux#L52){rel=""nofollow""} ## `SO_RCVTIMEO` ```rux pub const SO_RCVTIMEO: int32 = 0x1006; ``` `SO_RCVTIMEO`: how long a receive waits. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Socket.rux#L57){rel=""nofollow""} ## `SO_SNDTIMEO` ```rux pub const SO_SNDTIMEO: int32 = 0x1005; ``` `SO_SNDTIMEO`: how long a send waits. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Socket.rux#L62){rel=""nofollow""} ## `IPPROTO_TCP` ```rux pub const IPPROTO_TCP: int32 = 6; ``` `IPPROTO_TCP`: the level of TCP's options. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Socket.rux#L67){rel=""nofollow""} ## `TCP_NODELAY` ```rux pub const TCP_NODELAY: int32 = 1; ``` `TCP_NODELAY`: send small writes at once rather than gathering them. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Socket.rux#L72){rel=""nofollow""} ## `IPPROTO_IPV6` ```rux pub const IPPROTO_IPV6: int32 = 41; ``` `IPPROTO_IPV6`: the level of IPv6's options. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Socket.rux#L77){rel=""nofollow""} ## `IPV6_V6ONLY` ```rux pub const IPV6_V6ONLY: int32 = 27; ``` `IPV6_V6ONLY`: accept only IPv6 on an IPv6 socket. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Socket.rux#L82){rel=""nofollow""} ## `MSG_NOSIGNAL` ```rux pub const MSG_NOSIGNAL: int32 = 0x20000; ``` `MSG_NOSIGNAL`: report a closed peer as an error rather than with `SIGPIPE`. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Socket.rux#L87){rel=""nofollow""} ## `Socket` ```rux pub func Socket( domain: int32, kind: int32, protocol: int32 ) -> int64 ``` Opens a socket. **See also**: <https://man.freebsd.org/cgi/man.cgi?query=socket&sektion=2>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Socket.rux#L96){rel=""nofollow""} **Parameters** | Name | Type | Description | | ---------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `domain` | `int32` | the address family, such as [`AF_INET`](https://rux-lang.dev/docs/api/freebsd/socket#af-inet) | | `kind` | `int32` | the socket type, such as [`SOCK_STREAM`](https://rux-lang.dev/docs/api/freebsd/socket#sock-stream), combined with [`SOCK_CLOEXEC`](https://rux-lang.dev/docs/api/freebsd/socket#sock-cloexec) | | `protocol` | `int32` | the protocol, or zero for the family's default | **Returns**: the new descriptor, or a negative error number ## `Connect` ```rux pub func Connect( fd: FileDescriptor, address: *opaque, length: uint32 ) -> int64 ``` Connects a socket to `address`, waiting for a stream connection to be made. **See also**: <https://man.freebsd.org/cgi/man.cgi?query=connect&sektion=2>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Socket.rux#L107){rel=""nofollow""} **Parameters** | Name | Type | Description | | --------- | ---------------- | --------------------------- | | `fd` | `FileDescriptor` | the socket | | `address` | `*opaque` | the address, a `sockaddr` | | `length` | `uint32` | the address's size in bytes | **Returns**: zero, or a negative error number ## `Bind` ```rux pub func Bind( fd: FileDescriptor, address: *opaque, length: uint32 ) -> int64 ``` Gives a socket its local address. **See also**: <https://man.freebsd.org/cgi/man.cgi?query=bind&sektion=2>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Socket.rux#L118){rel=""nofollow""} **Parameters** | Name | Type | Description | | --------- | ---------------- | --------------------------- | | `fd` | `FileDescriptor` | the socket | | `address` | `*opaque` | the address, a `sockaddr` | | `length` | `uint32` | the address's size in bytes | **Returns**: zero, or a negative error number ## `Listen` ```rux pub func Listen(fd: FileDescriptor, backlog: int32) -> int64 ``` Makes a bound stream socket accept connections. **See also**: <https://man.freebsd.org/cgi/man.cgi?query=listen&sektion=2>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Socket.rux#L128){rel=""nofollow""} **Parameters** | Name | Type | Description | | --------- | ---------------- | -------------------------------------------- | | `fd` | `FileDescriptor` | the socket | | `backlog` | `int32` | how many connections may wait to be accepted | **Returns**: zero, or a negative error number ## `Accept4` ```rux pub func Accept4( fd: FileDescriptor, address: *var opaque, length: *var uint32, flags: int32 ) -> int64 ``` Accepts a waiting connection as a new socket. **See also**: <https://man.freebsd.org/cgi/man.cgi?query=accept4&sektion=2>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Socket.rux#L140){rel=""nofollow""} **Parameters** | Name | Type | Description | | --------- | ---------------- | ------------------------------------------------------------------------------------------------------------- | | `fd` | `FileDescriptor` | the listening socket | | `address` | `*var opaque` | receives the peer's address, or null | | `length` | `*var uint32` | the address buffer's size, then the address's, or null | | `flags` | `int32` | flags for the new socket, such as [`SOCK_CLOEXEC`](https://rux-lang.dev/docs/api/freebsd/socket#sock-cloexec) | **Returns**: the new descriptor, or a negative error number ## `SendTo` ```rux pub func SendTo( fd: FileDescriptor, buffer: *opaque, count: uint, flags: int32, address: *opaque, length: uint32 ) -> int64 ``` Sends bytes on a socket, to `address` when it is not connected. **See also**: <https://man.freebsd.org/cgi/man.cgi?query=sendto&sektion=2>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Socket.rux#L154){rel=""nofollow""} **Parameters** | Name | Type | Description | | --------- | ---------------- | ----------------------------------------------------------------------------------------- | | `fd` | `FileDescriptor` | the socket | | `buffer` | `*opaque` | the bytes | | `count` | `uint` | how many | | `flags` | `int32` | flags such as [`MSG_NOSIGNAL`](https://rux-lang.dev/docs/api/freebsd/socket#msg-nosignal) | | `address` | `*opaque` | the destination, or null for a connected socket | | `length` | `uint32` | the destination's size | **Returns**: the bytes sent, or a negative error number ## `ReceiveFrom` ```rux pub func ReceiveFrom( fd: FileDescriptor, buffer: *var opaque, count: uint, flags: int32, address: *var opaque, length: *var uint32 ) -> int64 ``` Receives bytes from a socket, and where they came from. **See also**: <https://man.freebsd.org/cgi/man.cgi?query=recvfrom&sektion=2>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Socket.rux#L168){rel=""nofollow""} **Parameters** | Name | Type | Description | | --------- | ---------------- | ------------------------------------------------------ | | `fd` | `FileDescriptor` | the socket | | `buffer` | `*var opaque` | receives the bytes | | `count` | `uint` | how many fit | | `flags` | `int32` | flags, or zero | | `address` | `*var opaque` | receives the sender's address, or null | | `length` | `*var uint32` | the address buffer's size, then the address's, or null | **Returns**: the bytes received, zero once a stream's peer closed it, or a negative error number ## `Shutdown` ```rux pub func Shutdown(fd: FileDescriptor, how: int32) -> int64 ``` Ends one or both directions of a connection. **See also**: <https://man.freebsd.org/cgi/man.cgi?query=shutdown&sektion=2>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Socket.rux#L178){rel=""nofollow""} **Parameters** | Name | Type | Description | | ----- | ---------------- | ----------------------------------- | | `fd` | `FileDescriptor` | the socket | | `how` | `int32` | `SHUT_RD`, `SHUT_WR` or `SHUT_RDWR` | **Returns**: zero, or a negative error number ## `SetSocketOption` ```rux pub func SetSocketOption( fd: FileDescriptor, level: int32, name: int32, value: *opaque, length: uint32 ) -> int64 ``` Sets a socket option. **See also**: <https://man.freebsd.org/cgi/man.cgi?query=setsockopt&sektion=2>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Socket.rux#L191){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | ---------------- | --------------------------------------------------------------------------------------------------- | | `fd` | `FileDescriptor` | the socket | | `level` | `int32` | the option's level, such as [`SOL_SOCKET`](https://rux-lang.dev/docs/api/freebsd/socket#sol-socket) | | `name` | `int32` | the option | | `value` | `*opaque` | the option's value | | `length` | `uint32` | the value's size in bytes | **Returns**: zero, or a negative error number ## `GetSocketName` ```rux pub func GetSocketName( fd: FileDescriptor, address: *var opaque, length: *var uint32 ) -> int64 ``` Reads a socket's local address. **See also**: <https://man.freebsd.org/cgi/man.cgi?query=getsockname&sektion=2>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Socket.rux#L202){rel=""nofollow""} **Parameters** | Name | Type | Description | | --------- | ---------------- | ------------------------------------- | | `fd` | `FileDescriptor` | the socket | | `address` | `*var opaque` | receives the address | | `length` | `*var uint32` | the buffer's size, then the address's | **Returns**: zero, or a negative error number ## `GetPeerName` ```rux pub func GetPeerName( fd: FileDescriptor, address: *var opaque, length: *var uint32 ) -> int64 ``` Reads the address of a connected socket's peer. **See also**: <https://man.freebsd.org/cgi/man.cgi?query=getpeername&sektion=2>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Socket.rux#L213){rel=""nofollow""} **Parameters** | Name | Type | Description | | --------- | ---------------- | ------------------------------------- | | `fd` | `FileDescriptor` | the socket | | `address` | `*var opaque` | receives the address | | `length` | `*var uint32` | the buffer's size, then the address's | **Returns**: zero, or a negative error number # Address waits Waiting on a word and waking its waiters through `_umtx_op`. ## `UMTX_OP_WAIT_UINT_PRIVATE` ```rux pub const UMTX_OP_WAIT_UINT_PRIVATE: int32 = 15; ``` `UMTX_OP_WAIT_UINT_PRIVATE`: sleep while a 32-bit word holds the expected value. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Umtx.rux#L13){rel=""nofollow""} ## `UMTX_OP_WAKE_PRIVATE` ```rux pub const UMTX_OP_WAKE_PRIVATE: int32 = 16; ``` `UMTX_OP_WAKE_PRIVATE`: wake threads sleeping on the word. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Umtx.rux#L18){rel=""nofollow""} ## `UmtxWait` ```rux pub func UmtxWait( address: *uint32, expected: uint32, timeout: *Timespec ) -> int64 ``` Sleeps while `*address` equals `expected`, until a wake, a signal or the timeout. **See also**: <https://man.freebsd.org/cgi/man.cgi?query=_umtx_op&sektion=2>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Umtx.rux#L27){rel=""nofollow""} **Parameters** | Name | Type | Description | | ---------- | ----------- | -------------------------------------------------------------------------- | | `address` | `*uint32` | the word to wait on, four-byte aligned | | `expected` | `uint32` | the value the caller last saw there | | `timeout` | `*Timespec` | how long to wait at most, relative to now, or null to wait without a limit | **Returns**: zero after a wake or when the word already differs, or a negative error number: [`EINTR`](https://rux-lang.dev/docs/api/freebsd/errors#eintr) or [`ETIMEDOUT`](https://rux-lang.dev/docs/api/freebsd/errors#etimedout) ## `UmtxWake` ```rux pub func UmtxWake(address: *uint32, count: int32) -> int64 ``` Wakes up to `count` threads sleeping on `address`. **See also**: <https://man.freebsd.org/cgi/man.cgi?query=_umtx_op&sektion=2>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/FreeBSD/Src/Umtx.rux#L39){rel=""nofollow""} **Parameters** | Name | Type | Description | | --------- | --------- | ------------------------ | | `address` | `*uint32` | the word they wait on | | `count` | `int32` | how many to wake at most | **Returns**: zero, or a negative error number # macOS macOS platform bindings. ## Installation Add `macOS` to the `[Dependencies]` table of your package's `Rux.toml`: ```toml [Dependencies] macOS = { Namespace = "Rux", Version = "0.1.0" } ``` Standard packages are declared by hand: the registry does not serve them, so `rux add Rux/macOS` cannot add them. ## Dependencies - [`Core`](https://rux-lang.dev/docs/api/core) 0.1.0 ## Guide macOS platform bindings: the Darwin ABI as libSystem publishes it, which on this system is the only interface Apple supports. ### What it provides | Module | Covers | | ------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `Types` | the Darwin ABI's own types: [`ProcessId`](https://rux-lang.dev/docs/api/macos/types#process-id), [`FileDescriptor`](https://rux-lang.dev/docs/api/macos/types#file-descriptor), [`FileMode`](https://rux-lang.dev/docs/api/macos/types#file-mode), [`UserId`](https://rux-lang.dev/docs/api/macos/types#user-id), [`Timespec`](https://rux-lang.dev/docs/api/macos/timespec), [`Timeval`](https://rux-lang.dev/docs/api/macos/timeval) | | `Errors` | the errno numbers, [`CurrentErrno`](https://rux-lang.dev/docs/api/macos/errors#current-errno), and the [`Normalize`](https://rux-lang.dev/docs/api/macos/errors#normalize) / [`IsError`](https://rux-lang.dev/docs/api/macos/errors#is-error) / [`Errno`](https://rux-lang.dev/docs/api/macos/errors#errno) fold | | `LibSystem` | every libSystem entry point this package binds, under the symbol it exports, including [`_NSGetArgc`](https://rux-lang.dev/docs/api/macos/process#ns-get-argc), [`_NSGetArgv`](https://rux-lang.dev/docs/api/macos/process#ns-get-argv) and [`_NSGetEnviron`](https://rux-lang.dev/docs/api/macos/process#ns-get-environ) | | `File` | [`Read`](https://rux-lang.dev/docs/api/macos/files#read), [`Write`](https://rux-lang.dev/docs/api/macos/files#write), [`Close`](https://rux-lang.dev/docs/api/macos/files#close), [`OpenAt`](https://rux-lang.dev/docs/api/macos/files#open-at), [`Lseek`](https://rux-lang.dev/docs/api/macos/files#lseek), [`Fsync`](https://rux-lang.dev/docs/api/macos/files#fsync), [`Ftruncate`](https://rux-lang.dev/docs/api/macos/files#ftruncate), [`UnlinkAt`](https://rux-lang.dev/docs/api/macos/directories#unlink-at), [`MkdirAt`](https://rux-lang.dev/docs/api/macos/directories#mkdir-at), [`RenameAt`](https://rux-lang.dev/docs/api/macos/directories#rename-at), [`Dup2`](https://rux-lang.dev/docs/api/macos/files#dup2), [`Pipe`](https://rux-lang.dev/docs/api/macos/files#pipe), the open flags, and the three standard descriptors | | `Memory` | [`Mmap`](https://rux-lang.dev/docs/api/macos/memory#mmap), [`Munmap`](https://rux-lang.dev/docs/api/macos/memory#munmap), [`Mprotect`](https://rux-lang.dev/docs/api/macos/memory#mprotect), [`Madvise`](https://rux-lang.dev/docs/api/macos/memory#madvise), [`QueryPageSize`](https://rux-lang.dev/docs/api/macos/memory#query-page-size), and the protection, mapping and advice flags | | `Clock` | [`ClockGetTime`](https://rux-lang.dev/docs/api/macos/clock#clock-get-time), [`ClockGetResolution`](https://rux-lang.dev/docs/api/macos/clock#clock-get-resolution), [`GetTimeOfDay`](https://rux-lang.dev/docs/api/macos/clock#get-time-of-day), [`Nanosleep`](https://rux-lang.dev/docs/api/macos/clock#nanosleep), and the clock identifiers | | `Entropy` | [`GetRandom`](https://rux-lang.dev/docs/api/macos/get-random), which cannot fail and has no short count | | `Process` | [`Exit`](https://rux-lang.dev/docs/api/macos/process#exit) and [`GetPid`](https://rux-lang.dev/docs/api/macos/process#get-pid) | | `Dynamic` | the `RTLD_*` flags; [`dlopen`](https://rux-lang.dev/docs/api/macos/dynamic#dlopen), [`dlsym`](https://rux-lang.dev/docs/api/macos/dynamic#dlsym), [`dlclose`](https://rux-lang.dev/docs/api/macos/dynamic#dlclose) and [`dlerror`](https://rux-lang.dev/docs/api/macos/dynamic#dlerror) are in `LibSystem` | | `Thread` | [`pthread_create`](https://rux-lang.dev/docs/api/macos/thread#pthread-create), [`pthread_join`](https://rux-lang.dev/docs/api/macos/thread#pthread-join), [`pthread_detach`](https://rux-lang.dev/docs/api/macos/thread#pthread-detach), the `pthread_attr_*` stack-size calls, [`sched_yield`](https://rux-lang.dev/docs/api/macos/thread#sched-yield), [`sysconf`](https://rux-lang.dev/docs/api/macos/thread#sysconf) and [`SC_NPROCESSORS_ONLN`](https://rux-lang.dev/docs/api/macos/thread#sc-nprocessors-onln), and [`pthread_threadid_np`](https://rux-lang.dev/docs/api/macos/thread#pthread-threadid-np), linked from libSystem | | `Ulock` | [`__ulock_wait`](https://rux-lang.dev/docs/api/macos/ulock#ulock-wait), [`__ulock_wake`](https://rux-lang.dev/docs/api/macos/ulock#ulock-wake) and their flags, the word operations every lock in `Rux/Sync` sleeps on | | `Spawn` | [`posix_spawnp`](https://rux-lang.dev/docs/api/macos/spawn#posix-spawnp), the `posix_spawn_file_actions_*` calls, [`waitpid`](https://rux-lang.dev/docs/api/macos/spawn#waitpid), [`kill`](https://rux-lang.dev/docs/api/macos/spawn#kill) and [`fcntl`](https://rux-lang.dev/docs/api/macos/spawn#fcntl) | | [`Socket`](https://rux-lang.dev/docs/api/macos/socket#socket) | the BSD socket calls behind the same wrappers as Linux and FreeBSD, [`SO_NOSIGPIPE`](https://rux-lang.dev/docs/api/macos/socket#so-nosigpipe), and [`getaddrinfo`](https://rux-lang.dev/docs/api/macos/resolve#getaddrinfo), [`freeaddrinfo`](https://rux-lang.dev/docs/api/macos/resolve#freeaddrinfo) and [`AddressInfo`](https://rux-lang.dev/docs/api/macos/resolve#address-info) | | `Poll` | [`Kqueue`](https://rux-lang.dev/docs/api/macos/poll#kqueue) and [`KeventCall`](https://rux-lang.dev/docs/api/macos/poll#kevent-call) over libSystem's `kqueue` and `kevent`, [`Kevent`](https://rux-lang.dev/docs/api/macos/poll#kevent), the `EVFILT_*` and `EV_*` flags, and [`FcntlInt`](https://rux-lang.dev/docs/api/macos/poll#fcntl-int) with [`F_GETFL`](https://rux-lang.dev/docs/api/macos/poll#f-getfl), [`F_SETFL`](https://rux-lang.dev/docs/api/macos/poll#f-setfl) and [`O_NONBLOCK`](https://rux-lang.dev/docs/api/macos/poll#o-nonblock) | The module names describe where each declaration comes from; they are not part of an import path. **Apple does not support calling the kernel directly.** The trap numbers are private, they have changed between releases, and on Apple Silicon the trap interface is not reachable from ordinary code at all. libSystem is the ABI, and this package binds it — which is what makes it different in kind from `Rux/Linux` and `Rux/FreeBSD`, whose kernels publish a stable numbering. libSystem reports failure the way C does, with `-1` and a positive `errno` reached through an accessor. [`Normalize`](https://rux-lang.dev/docs/api/macos/errors#normalize) folds those two into the one negative-error convention the other platform packages use, so [`IsError`](https://rux-lang.dev/docs/api/macos/errors#is-error) and [`Errno`](https://rux-lang.dev/docs/api/macos/errors#errno) read the same on all three. Nothing here is interchangeable with the other platform packages. `AT_FDCWD` is `-2` on Darwin and `-100` elsewhere; monotonic is clock 6 here, 1 on Linux, 4 on FreeBSD; [`RTLD_LOCAL`](https://rux-lang.dev/docs/api/macos/dynamic#rtld-local) is 4 and [`RTLD_GLOBAL`](https://rux-lang.dev/docs/api/macos/dynamic#rtld-global) is 8, where both other systems use 0 and 256. A value carried across compiles and means something else. There is no `Brk`: Darwin's `brk` and `sbrk` have been unavailable to 64-bit code from the start. There is no `Pipe2`: Darwin has only `pipe`, so close-on-exec must be set afterwards. And [`Fsync`](https://rux-lang.dev/docs/api/macos/files#fsync) is weaker here than elsewhere — it does not wait for the device to commit, which `F_FULLFSYNC` through [`fcntl`](https://rux-lang.dev/docs/api/macos/spawn#fcntl) is what does. ### What is tested `Tests/Packages/macOS/Descriptors` covers descriptor numbering, short reads and writes, end of file, size boundaries and the native error for each way of misusing a descriptor or a name. `Tests/Packages/macOS/Mapping` covers anonymous mappings, protection changes, advice, the requests the kernel refuses, and both edges of the reserved error-result window. `Tests/Packages/macOS/Syscall` covers the wrapper surface and the shared POSIX contract. All of it compiles for both architectures, and none of it has ever run on a host that is not macOS. Until it does, the syscall numbers, flag values and errno constants here rest on published documentation rather than on a passing test. ### The shared POSIX contract Nothing here is interchangeable with `Rux/Linux` or `Rux/FreeBSD`, but the three are *spelled* the same, which is a different claim and a deliberate one. An equivalent call has the same wrapper name, the same parameter names and the same parameter shapes on all three systems, so a consumer such as [`Rux/FileSystem`](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/../FileSystem){rel=""nofollow""} or [`Rux/Time`](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/../Time){rel=""nofollow""} writes one call site instead of a `when #target.os` ladder around three names for one idea. `Tests/Unit/PlatformBindingContractTests.cpp` compares the three packages' parsed sources and fails when they drift apart. The values are the opposite: every constant is this system's own, and the same file asserts that the ones a reader might carry across really do differ. ### Values and pointers Darwin records such as [`Timespec`](https://rux-lang.dev/docs/api/macos/timespec) and [`Timeval`](https://rux-lang.dev/docs/api/macos/timeval) are structural values and copy by value, and every call that reads or fills one takes its address: `GetTimeOfDay(@time)`, `ClockGetTime(ClockMonotonic, @time)`. That is the convention on all three POSIX packages. It is not the prettiest form available here — libSystem's C declarations would accept a reference, and this package used them until the divergence showed up as target branches in `Rux/Time` — but one shape across three systems is worth more than a borrow on one of them. libSystem declarations retain raw pointers for nullable parameters, byte buffers, loader handles, and OS-owned storage. These pointers do not express ownership; use the documented close or unmap operation, or prefer `Rux/Io` and `Rux/Memory` for managed interfaces. ### Platform macOS only. Guard use behind a compile-time check, so a build for another target never resolves these declarations: ```rux import Core::{ #target }; when #target.os == .macOS { import macOS::{ StdOut, Write }; } ``` ## Index ### Types | Name | Summary | | ------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------- | | [`Kevent`](https://rux-lang.dev/docs/api/macos/poll#kevent) | One `struct kevent` as 64-bit macOS lays it out: a change to register or an event to report. | | [`AddressInfo`](https://rux-lang.dev/docs/api/macos/resolve#address-info) | The C library's `addrinfo`: one result of [`getaddrinfo`](https://rux-lang.dev/docs/api/macos/resolve#getaddrinfo), linked to the next. | | [`SpawnFileActions`](https://rux-lang.dev/docs/api/macos/spawn#spawn-file-actions) | Room for a `posix_spawn_file_actions_t`, which each C library sizes its own way and none larger than this. | | [`PThread`](https://rux-lang.dev/docs/api/macos/thread#p-thread) | A thread as the C library names it, `pthread_t`. | | [`PThreadAttributes`](https://rux-lang.dev/docs/api/macos/thread#p-thread-attributes) | Room for a `pthread_attr_t`, which each C library sizes its own way and none larger than this. | | [`ProcessId`](https://rux-lang.dev/docs/api/macos/types#process-id) | A process identifier, as `getpid` reports one. | | [`FileDescriptor`](https://rux-lang.dev/docs/api/macos/types#file-descriptor) | A file descriptor, as the kernel numbers one. | | [`FileOffset`](https://rux-lang.dev/docs/api/macos/types#file-offset) | A byte offset within a file, 64 bits on every supported Apple target. | | [`FileMode`](https://rux-lang.dev/docs/api/macos/types#file-mode) | A file's type and permission bits. | | [`UserId`](https://rux-lang.dev/docs/api/macos/types#user-id) | A user identifier. | | [`GroupId`](https://rux-lang.dev/docs/api/macos/types#group-id) | A group identifier. | | [`Timespec`](https://rux-lang.dev/docs/api/macos/timespec) | A duration or an instant, as seconds and nanoseconds. | | [`Timeval`](https://rux-lang.dev/docs/api/macos/timeval) | A duration or an instant, as seconds and microseconds. | ### Functions | Name | Summary | | ------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------ | | [`ClockGetTime`](https://rux-lang.dev/docs/api/macos/clock#clock-get-time) | Reads `clockId` into `time`. | | [`ClockGetResolution`](https://rux-lang.dev/docs/api/macos/clock#clock-get-resolution) | Reads the resolution of `clockId` into `resolution`. | | [`GetTimeOfDay`](https://rux-lang.dev/docs/api/macos/clock#get-time-of-day) | Reads the wall clock into `time`, to microsecond resolution. | | [`Nanosleep`](https://rux-lang.dev/docs/api/macos/clock#nanosleep) | Suspends the caller for the requested duration. | | [`GetRandom`](https://rux-lang.dev/docs/api/macos/get-random) | Fills `length` bytes of `buffer` with unpredictable bytes. | | [`CurrentErrno`](https://rux-lang.dev/docs/api/macos/errors#current-errno) | The calling thread's current `errno` value. | | [`Normalize`](https://rux-lang.dev/docs/api/macos/errors#normalize) | Folds a libSystem result and the thread's `errno` into one value. | | [`IsError`](https://rux-lang.dev/docs/api/macos/errors#is-error) | Whether a normalized result is one of the reserved error values. | | [`Errno`](https://rux-lang.dev/docs/api/macos/errors#errno) | The error number a normalized result carries, or zero when it carries none. | | [`Read`](https://rux-lang.dev/docs/api/macos/files#read) | Reads up to `count` bytes from `fd` into `buffer`. | | [`Write`](https://rux-lang.dev/docs/api/macos/files#write) | Writes up to `count` bytes from `buffer` to `fd`. | | [`Close`](https://rux-lang.dev/docs/api/macos/files#close) | Closes `fd` and releases what the kernel held for it. | | [`OpenAt`](https://rux-lang.dev/docs/api/macos/files#open-at) | Opens `path` relative to `directoryFd` and returns a descriptor, or a negative error number. | | [`Lseek`](https://rux-lang.dev/docs/api/macos/files#lseek) | Moves the file offset of `fd` and returns where it ended up, or a negative error number. | | [`Getcwd`](https://rux-lang.dev/docs/api/macos/directories#getcwd) | Writes the current working directory's absolute path into `buffer`, NUL-terminated. | | [`Chdir`](https://rux-lang.dev/docs/api/macos/directories#chdir) | Makes `path` the process's working directory. | | [`ReadlinkAt`](https://rux-lang.dev/docs/api/macos/directories#readlink-at) | Reads the text a symbolic link holds into `buffer`. | | [`Fstat`](https://rux-lang.dev/docs/api/macos/files#fstat) | Fills `statBuffer` with what the kernel knows about the file behind `fd`. | | [`FstatAt`](https://rux-lang.dev/docs/api/macos/files#fstat-at) | Fills `statBuffer` with what the kernel knows about the file `path` names. | | [`FchmodAt`](https://rux-lang.dev/docs/api/macos/files#fchmod-at) | Sets the permission bits of the file `path` names. | | [`UtimensAt`](https://rux-lang.dev/docs/api/macos/files#utimens-at) | Sets the access and modification times of the file `path` names. | | [`LinkAt`](https://rux-lang.dev/docs/api/macos/directories#link-at) | Creates a hard link: `newPath` becomes a second name for the file `oldPath` names. | | [`SymlinkAt`](https://rux-lang.dev/docs/api/macos/directories#symlink-at) | Creates a symbolic link at `linkPath` holding `target` as its text. | | [`Getdirentries64`](https://rux-lang.dev/docs/api/macos/directories#getdirentries64) | Reads directory entries from `fd` into `buffer`, and returns the bytes filled, zero at the end, or a negative error number. | | [`Fsync`](https://rux-lang.dev/docs/api/macos/files#fsync) | Flushes everything written to `fd` toward the storage device. | | [`Ftruncate`](https://rux-lang.dev/docs/api/macos/files#ftruncate) | Sets the length of the file behind `fd` to `length`. | | [`UnlinkAt`](https://rux-lang.dev/docs/api/macos/directories#unlink-at) | Removes the name `path` from its directory. | | [`MkdirAt`](https://rux-lang.dev/docs/api/macos/directories#mkdir-at) | Creates a directory named `path` with permission bits `mode`. | | [`RenameAt`](https://rux-lang.dev/docs/api/macos/directories#rename-at) | Renames `oldPath` to `newPath`, each resolved against its own directory descriptor. | | [`Dup2`](https://rux-lang.dev/docs/api/macos/files#dup2) | Makes `newFd` a copy of `oldFd`, closing whatever `newFd` was. | | [`Pipe`](https://rux-lang.dev/docs/api/macos/files#pipe) | Creates a pipe and writes its two descriptors into `descriptors`. | | [`getpagesize`](https://rux-lang.dev/docs/api/macos/memory#getpagesize) | Reports the system page size, in bytes. | | [`_NSGetArgc`](https://rux-lang.dev/docs/api/macos/process#ns-get-argc) | The address of the process's argument count. | | [`_NSGetArgv`](https://rux-lang.dev/docs/api/macos/process#ns-get-argv) | The address of the process's argument vector. | | [`_NSGetExecutablePath`](https://rux-lang.dev/docs/api/macos/process#ns-get-executable-path) | Copies the path of the process's executable into `buffer`, NUL-terminated. | | [`_NSGetEnviron`](https://rux-lang.dev/docs/api/macos/process#ns-get-environ) | The address of the process's environment vector. | | [`dlopen`](https://rux-lang.dev/docs/api/macos/dynamic#dlopen) | Loads a shared object and returns a handle to it, or null on failure. | | [`dlsym`](https://rux-lang.dev/docs/api/macos/dynamic#dlsym) | Finds a symbol in a loaded object and returns its address, or null. | | [`dlclose`](https://rux-lang.dev/docs/api/macos/dynamic#dlclose) | Drops one reference to a loaded object, unloading it when the last one goes. | | [`dlerror`](https://rux-lang.dev/docs/api/macos/dynamic#dlerror) | Reports the most recent loader error and clears it, or returns null when there is none. | | [`Mmap`](https://rux-lang.dev/docs/api/macos/memory#mmap) | Creates a mapping and returns its address, or a negative error number. | | [`Munmap`](https://rux-lang.dev/docs/api/macos/memory#munmap) | Releases the mapping that begins at `address` and spans `length` bytes. | | [`Mprotect`](https://rux-lang.dev/docs/api/macos/memory#mprotect) | Changes what may be done with the pages covering a range. | | [`Madvise`](https://rux-lang.dev/docs/api/macos/memory#madvise) | Tells the kernel how the pages covering a range are about to be used. | | [`QueryPageSize`](https://rux-lang.dev/docs/api/macos/memory#query-page-size) | The size of a page, asked of libSystem. | | [`FcntlInt`](https://rux-lang.dev/docs/api/macos/poll#fcntl-int) | Performs `command` on a descriptor with an integer argument. | | [`Kqueue`](https://rux-lang.dev/docs/api/macos/poll#kqueue) | Opens a kqueue. | | [`KeventCall`](https://rux-lang.dev/docs/api/macos/poll#kevent-call) | Applies `changeCount` changes, then waits until an event is ready or `timeout` passes, filling `events`. | | [`Exit`](https://rux-lang.dev/docs/api/macos/process#exit) | Ends the calling process with `code`. | | [`GetPid`](https://rux-lang.dev/docs/api/macos/process#get-pid) | The calling process's own identifier. | | [`Socket`](https://rux-lang.dev/docs/api/macos/socket#socket) | Opens a socket. | | [`Connect`](https://rux-lang.dev/docs/api/macos/socket#connect) | Connects a socket to `address`, waiting for a stream connection to be made. | | [`Bind`](https://rux-lang.dev/docs/api/macos/socket#bind) | Gives a socket its local address. | | [`Listen`](https://rux-lang.dev/docs/api/macos/socket#listen) | Makes a bound stream socket accept connections. | | [`Accept4`](https://rux-lang.dev/docs/api/macos/socket#accept4) | Accepts a waiting connection as a new socket. | | [`SendTo`](https://rux-lang.dev/docs/api/macos/socket#sendto) | Sends bytes on a socket, to `address` when it is not connected. | | [`ReceiveFrom`](https://rux-lang.dev/docs/api/macos/socket#receivefrom) | Receives bytes from a socket, and where they came from. | | [`Shutdown`](https://rux-lang.dev/docs/api/macos/socket#shutdown) | Ends one or both directions of a connection. | | [`SetSocketOption`](https://rux-lang.dev/docs/api/macos/socket#setsocketoption) | Sets a socket option. | | [`GetSocketName`](https://rux-lang.dev/docs/api/macos/socket#getsocketname) | Reads a socket's local address. | | [`GetPeerName`](https://rux-lang.dev/docs/api/macos/socket#getpeername) | Reads the address of a connected socket's peer. | | [`getaddrinfo`](https://rux-lang.dev/docs/api/macos/resolve#getaddrinfo) | Looks up the addresses of a host and service. | | [`freeaddrinfo`](https://rux-lang.dev/docs/api/macos/resolve#freeaddrinfo) | Frees the results of [`getaddrinfo`](https://rux-lang.dev/docs/api/macos/resolve#getaddrinfo). | | [`posix_spawnp`](https://rux-lang.dev/docs/api/macos/spawn#posix-spawnp) | Starts `file`, found through `PATH` when it has no slash, as a child process. | | [`posix_spawn_file_actions_init`](https://rux-lang.dev/docs/api/macos/spawn#posix-spawn-file-actions-init) | Initializes an empty list of file actions. | | [`posix_spawn_file_actions_destroy`](https://rux-lang.dev/docs/api/macos/spawn#posix-spawn-file-actions-destroy) | Releases what [`posix_spawn_file_actions_init`](https://rux-lang.dev/docs/api/macos/spawn#posix-spawn-file-actions-init) and the actions added since set up. | | [`posix_spawn_file_actions_adddup2`](https://rux-lang.dev/docs/api/macos/spawn#posix-spawn-file-actions-adddup2) | Adds an action duplicating `fd` onto `newFd` in the child. | | [`posix_spawn_file_actions_addopen`](https://rux-lang.dev/docs/api/macos/spawn#posix-spawn-file-actions-addopen) | Adds an action opening `path` as `fd` in the child. | | [`posix_spawn_file_actions_addchdir_np`](https://rux-lang.dev/docs/api/macos/spawn#posix-spawn-file-actions-addchdir-np) | Adds an action changing the child's working directory to `path`. | | [`waitpid`](https://rux-lang.dev/docs/api/macos/spawn#waitpid) | Waits for a child to change state, and reports how it finished. | | [`kill`](https://rux-lang.dev/docs/api/macos/spawn#kill) | Sends a signal to a process. | | [`fcntl`](https://rux-lang.dev/docs/api/macos/spawn#fcntl) | Performs a control operation on a descriptor, such as setting its flags with [`F_SETFD`](https://rux-lang.dev/docs/api/macos/spawn#f-setfd). | | [`pthread_create`](https://rux-lang.dev/docs/api/macos/thread#pthread-create) | Starts a thread running `start(argument)`. | | [`pthread_join`](https://rux-lang.dev/docs/api/macos/thread#pthread-join) | Waits for a thread to finish and releases it. | | [`pthread_detach`](https://rux-lang.dev/docs/api/macos/thread#pthread-detach) | Lets a thread release itself when it finishes, so nothing has to join it. | | [`pthread_attr_init`](https://rux-lang.dev/docs/api/macos/thread#pthread-attr-init) | Initializes thread attributes to the defaults. | | [`pthread_attr_setstacksize`](https://rux-lang.dev/docs/api/macos/thread#pthread-attr-setstacksize) | Sets the stack size a thread started with these attributes gets. | | [`pthread_attr_destroy`](https://rux-lang.dev/docs/api/macos/thread#pthread-attr-destroy) | Releases what [`pthread_attr_init`](https://rux-lang.dev/docs/api/macos/thread#pthread-attr-init) set up. | | [`pthread_threadid_np`](https://rux-lang.dev/docs/api/macos/thread#pthread-threadid-np) | Reads the system-wide identifier of a thread, or of the calling thread when `thread` is zero. | | [`sched_yield`](https://rux-lang.dev/docs/api/macos/thread#sched-yield) | Gives up the processor so another ready thread can run. | | [`sysconf`](https://rux-lang.dev/docs/api/macos/thread#sysconf) | Reads a system configuration value. | | [`__ulock_wait`](https://rux-lang.dev/docs/api/macos/ulock#ulock-wait) | Sleeps while `*address` equals `value`, until a wake, a signal or the timeout. | | [`__ulock_wake`](https://rux-lang.dev/docs/api/macos/ulock#ulock-wake) | Wakes a thread, or all of them with [`ULF_WAKE_ALL`](https://rux-lang.dev/docs/api/macos/ulock#ulf-wake-all), sleeping on `address`. | ### Constants | Name | Summary | | --------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | [`ClockRealtime`](https://rux-lang.dev/docs/api/macos/clock#clock-realtime) | `CLOCK_REALTIME`: wall-clock time, which can jump when the system clock is set. | | [`ClockMonotonic`](https://rux-lang.dev/docs/api/macos/clock#clock-monotonic) | `CLOCK_MONOTONIC`: time since boot, which never goes backwards. | | [`ClockMonotonicRaw`](https://rux-lang.dev/docs/api/macos/clock#clock-monotonic-raw) | `CLOCK_MONOTONIC_RAW`: like [`ClockMonotonic`](https://rux-lang.dev/docs/api/macos/clock#clock-monotonic), but not adjusted by time synchronization. | | [`RTLD_LAZY`](https://rux-lang.dev/docs/api/macos/dynamic#rtld-lazy) | `RTLD_LAZY`: resolve a function symbol the first time it is called rather than at load. | | [`RTLD_NOW`](https://rux-lang.dev/docs/api/macos/dynamic#rtld-now) | `RTLD_NOW`: resolve every symbol before [`dlopen`](https://rux-lang.dev/docs/api/macos/dynamic#dlopen) returns. | | [`RTLD_LOCAL`](https://rux-lang.dev/docs/api/macos/dynamic#rtld-local) | `RTLD_LOCAL`: keep this object's symbols to itself, which is Darwin's default. | | [`RTLD_GLOBAL`](https://rux-lang.dev/docs/api/macos/dynamic#rtld-global) | `RTLD_GLOBAL`: make this object's symbols available to objects loaded afterwards. | | [`EPERM`](https://rux-lang.dev/docs/api/macos/errors#eperm) | `EPERM`: the operation is not permitted to this caller. | | [`ENOENT`](https://rux-lang.dev/docs/api/macos/errors#enoent) | `ENOENT`: no such file or directory. | | [`ESRCH`](https://rux-lang.dev/docs/api/macos/errors#esrch) | `ESRCH`: no process has that identifier. | | [`EINTR`](https://rux-lang.dev/docs/api/macos/errors#eintr) | `EINTR`: the call was interrupted by a signal before it did anything. | | [`EIO`](https://rux-lang.dev/docs/api/macos/errors#eio) | `EIO`: a low-level input or output error. | | [`ENXIO`](https://rux-lang.dev/docs/api/macos/errors#enxio) | `ENXIO`: no such device or address. | | [`EBADF`](https://rux-lang.dev/docs/api/macos/errors#ebadf) | `EBADF`: the file descriptor is not open, or is not open for what was asked. | | [`ENOMEM`](https://rux-lang.dev/docs/api/macos/errors#enomem) | `ENOMEM`: not enough memory to satisfy the request. | | [`EACCES`](https://rux-lang.dev/docs/api/macos/errors#eacces) | `EACCES`: permission denied. | | [`EFAULT`](https://rux-lang.dev/docs/api/macos/errors#efault) | `EFAULT`: an address the call was given is outside the caller's address space. | | [`EBUSY`](https://rux-lang.dev/docs/api/macos/errors#ebusy) | `EBUSY`: the resource is in use by something else. | | [`EEXIST`](https://rux-lang.dev/docs/api/macos/errors#eexist) | `EEXIST`: the file already exists. | | [`EXDEV`](https://rux-lang.dev/docs/api/macos/errors#exdev) | `EXDEV`: the two paths are on different file systems. | | [`ENOTDIR`](https://rux-lang.dev/docs/api/macos/errors#enotdir) | `ENOTDIR`: a path component that had to be a directory is not one. | | [`EISDIR`](https://rux-lang.dev/docs/api/macos/errors#eisdir) | `EISDIR`: the target is a directory and the operation is not one a directory accepts. | | [`EINVAL`](https://rux-lang.dev/docs/api/macos/errors#einval) | `EINVAL`: an argument is not valid. | | [`EMFILE`](https://rux-lang.dev/docs/api/macos/errors#emfile) | `EMFILE`: this process has too many descriptors open. | | [`ENOSPC`](https://rux-lang.dev/docs/api/macos/errors#enospc) | `ENOSPC`: the device has no room left. | | [`ESPIPE`](https://rux-lang.dev/docs/api/macos/errors#espipe) | `ESPIPE`: the descriptor is a pipe or socket and cannot be seeked. | | [`EROFS`](https://rux-lang.dev/docs/api/macos/errors#erofs) | `EROFS`: the file system is mounted read-only. | | [`EPIPE`](https://rux-lang.dev/docs/api/macos/errors#epipe) | `EPIPE`: the reading end of the pipe is closed. | | [`EAGAIN`](https://rux-lang.dev/docs/api/macos/errors#eagain) | `EAGAIN`: the operation would block, and the descriptor was set not to. | | [`ELOOP`](https://rux-lang.dev/docs/api/macos/errors#eloop) | `ELOOP`: too many symbolic links were followed resolving the path. | | [`ENAMETOOLONG`](https://rux-lang.dev/docs/api/macos/errors#enametoolong) | `ENAMETOOLONG`: the path or a component of it is too long. | | [`ENOSYS`](https://rux-lang.dev/docs/api/macos/errors#enosys) | `ENOSYS`: the system does not implement this call. | | [`EOVERFLOW`](https://rux-lang.dev/docs/api/macos/errors#eoverflow) | `EOVERFLOW`: a value is too large for the type the call reports it in. | | [`ETIMEDOUT`](https://rux-lang.dev/docs/api/macos/errors#etimedout) | `ETIMEDOUT`: the operation timed out. | | [`MaximumErrno`](https://rux-lang.dev/docs/api/macos/errors#maximum-errno) | The largest error number the normalized error range holds. | | [`StdIn`](https://rux-lang.dev/docs/api/macos/files#std-in) | The descriptor a process reads its input from, unless something reassigned it. | | [`StdOut`](https://rux-lang.dev/docs/api/macos/files#std-out) | The descriptor a process writes its output to. | | [`StdErr`](https://rux-lang.dev/docs/api/macos/files#std-err) | The descriptor a process writes its diagnostics to. | | [`AtFdCwd`](https://rux-lang.dev/docs/api/macos/files#at-fd-cwd) | `AT_FDCWD`: resolve a relative path against the current directory rather than a descriptor. | | [`OpenReadOnly`](https://rux-lang.dev/docs/api/macos/files#open-read-only) | `O_RDONLY`: open for reading only. | | [`OpenWriteOnly`](https://rux-lang.dev/docs/api/macos/files#open-write-only) | `O_WRONLY`: open for writing only. | | [`OpenReadWrite`](https://rux-lang.dev/docs/api/macos/files#open-read-write) | `O_RDWR`: open for both reading and writing. | | [`OpenCreate`](https://rux-lang.dev/docs/api/macos/files#open-create) | `O_CREAT`: create the file when it does not exist, which is when the mode argument is read. | | [`OpenExclusive`](https://rux-lang.dev/docs/api/macos/files#open-exclusive) | `O_EXCL`: with [`OpenCreate`](https://rux-lang.dev/docs/api/macos/files#open-create), fail rather than open a file that already exists. | | [`OpenTruncate`](https://rux-lang.dev/docs/api/macos/files#open-truncate) | `O_TRUNC`: truncate the file to nothing when opening it for writing. | | [`OpenAppend`](https://rux-lang.dev/docs/api/macos/files#open-append) | `O_APPEND`: every write goes to the end. | | [`OpenNonBlocking`](https://rux-lang.dev/docs/api/macos/files#open-non-blocking) | [`O_NONBLOCK`](https://rux-lang.dev/docs/api/macos/poll#o-nonblock): reads and writes report [`EAGAIN`](https://rux-lang.dev/docs/api/macos/errors#eagain) rather than waiting. | | [`OpenCloseOnExec`](https://rux-lang.dev/docs/api/macos/files#open-close-on-exec) | `O_CLOEXEC`: close this descriptor automatically when the process executes a new program. | | [`OpenDirectory`](https://rux-lang.dev/docs/api/macos/files#open-directory) | `O_DIRECTORY`: fail unless the target is a directory. | | [`SeekSet`](https://rux-lang.dev/docs/api/macos/files#seek-set) | `SEEK_SET`: measure the new offset from the start of the file. | | [`SeekCurrent`](https://rux-lang.dev/docs/api/macos/files#seek-current) | `SEEK_CUR`: measure the new offset from the current one. | | [`SeekEnd`](https://rux-lang.dev/docs/api/macos/files#seek-end) | `SEEK_END`: measure the new offset from the end of the file. | | [`RemoveDirectory`](https://rux-lang.dev/docs/api/macos/directories#remove-directory) | `AT_REMOVEDIR`: make [`UnlinkAt`](https://rux-lang.dev/docs/api/macos/directories#unlink-at) remove a directory rather than a file. | | [`SymlinkNoFollow`](https://rux-lang.dev/docs/api/macos/directories#symlink-no-follow) | `AT_SYMLINK_NOFOLLOW`: act on a symbolic link itself rather than on what it points at. | | [`FollowSymlinks`](https://rux-lang.dev/docs/api/macos/directories#follow-symlinks) | `AT_SYMLINK_FOLLOW`: make [`LinkAt`](https://rux-lang.dev/docs/api/macos/directories#link-at) link a symbolic link's target rather than the link. | | [`SystemLib`](https://rux-lang.dev/docs/api/macos/dynamic#system-lib) | The library every Darwin interface is reached through. | | [`ProtectionNone`](https://rux-lang.dev/docs/api/macos/memory#protection-none) | `PROT_NONE`: the pages may not be touched at all. | | [`ProtectionRead`](https://rux-lang.dev/docs/api/macos/memory#protection-read) | `PROT_READ`: the pages may be read. | | [`ProtectionWrite`](https://rux-lang.dev/docs/api/macos/memory#protection-write) | `PROT_WRITE`: the pages may be written. | | [`ProtectionExecute`](https://rux-lang.dev/docs/api/macos/memory#protection-execute) | `PROT_EXEC`: the pages may be executed. | | [`MapShared`](https://rux-lang.dev/docs/api/macos/memory#map-shared) | `MAP_SHARED`: writes are visible to other mappings of the same object and reach it. | | [`MapPrivate`](https://rux-lang.dev/docs/api/macos/memory#map-private) | `MAP_PRIVATE`: writes are private to this mapping and never reach the object. | | [`MapFixed`](https://rux-lang.dev/docs/api/macos/memory#map-fixed) | `MAP_FIXED`: place the mapping exactly at the requested address, replacing whatever was there. | | [`MapAnonymous`](https://rux-lang.dev/docs/api/macos/memory#map-anonymous) | `MAP_ANON`: the mapping is backed by zeroed pages rather than by a file. | | [`AdviseFree`](https://rux-lang.dev/docs/api/macos/memory#advise-free) | `MADV_FREE`: the pages may be reclaimed, and read back as zero if they are. | | [`AdviseDontNeed`](https://rux-lang.dev/docs/api/macos/memory#advise-dont-need) | `MADV_DONTNEED`: the pages are not needed soon. | | [`AdviseWillNeed`](https://rux-lang.dev/docs/api/macos/memory#advise-will-need) | `MADV_WILLNEED`: the pages will be read soon. | | [`F_GETFL`](https://rux-lang.dev/docs/api/macos/poll#f-getfl) | `F_GETFL`: the [`fcntl`](https://rux-lang.dev/docs/api/macos/spawn#fcntl) command that reads a descriptor's status flags. | | [`F_SETFL`](https://rux-lang.dev/docs/api/macos/poll#f-setfl) | `F_SETFL`: the [`fcntl`](https://rux-lang.dev/docs/api/macos/spawn#fcntl) command that sets a descriptor's status flags. | | [`O_NONBLOCK`](https://rux-lang.dev/docs/api/macos/poll#o-nonblock) | `O_NONBLOCK`: the status flag that makes a call fail with [`EAGAIN`](https://rux-lang.dev/docs/api/macos/errors#eagain) rather than wait. | | [`EVFILT_READ`](https://rux-lang.dev/docs/api/macos/poll#evfilt-read) | `EVFILT_READ`: the filter that reports a descriptor with something to read, or a connection to accept. | | [`EVFILT_WRITE`](https://rux-lang.dev/docs/api/macos/poll#evfilt-write) | `EVFILT_WRITE`: the filter that reports a descriptor a write would not wait on. | | [`EV_ADD`](https://rux-lang.dev/docs/api/macos/poll#ev-add) | `EV_ADD`: add the change's filter, or update it. | | [`EV_DELETE`](https://rux-lang.dev/docs/api/macos/poll#ev-delete) | `EV_DELETE`: remove the change's filter. | | [`EV_RECEIPT`](https://rux-lang.dev/docs/api/macos/poll#ev-receipt) | `EV_RECEIPT`: report each change as an event, with its outcome in `data`, rather than waiting. | | [`EV_ERROR`](https://rux-lang.dev/docs/api/macos/poll#ev-error) | `EV_ERROR`: set on an event that reports a failed change, with the error number in `data`. | | [`EV_EOF`](https://rux-lang.dev/docs/api/macos/poll#ev-eof) | `EV_EOF`: the peer has closed its side. | | [`AF_INET`](https://rux-lang.dev/docs/api/macos/socket#af-inet) | `AF_INET`: the IPv4 address family. | | [`AF_INET6`](https://rux-lang.dev/docs/api/macos/socket#af-inet6) | `AF_INET6`: the IPv6 address family. | | [`SOCK_STREAM`](https://rux-lang.dev/docs/api/macos/socket#sock-stream) | `SOCK_STREAM`: a connected byte stream. | | [`SOCK_DGRAM`](https://rux-lang.dev/docs/api/macos/socket#sock-dgram) | `SOCK_DGRAM`: individual datagrams. | | [`SOL_SOCKET`](https://rux-lang.dev/docs/api/macos/socket#sol-socket) | `SOL_SOCKET`: the level of the options every socket has. | | [`SO_REUSEADDR`](https://rux-lang.dev/docs/api/macos/socket#so-reuseaddr) | `SO_REUSEADDR`: let a listening address be bound again while old connections to it wind down. | | [`SO_RCVTIMEO`](https://rux-lang.dev/docs/api/macos/socket#so-rcvtimeo) | `SO_RCVTIMEO`: how long a receive waits. | | [`SO_SNDTIMEO`](https://rux-lang.dev/docs/api/macos/socket#so-sndtimeo) | `SO_SNDTIMEO`: how long a send waits. | | [`IPPROTO_TCP`](https://rux-lang.dev/docs/api/macos/socket#ipproto-tcp) | `IPPROTO_TCP`: the level of TCP's options. | | [`TCP_NODELAY`](https://rux-lang.dev/docs/api/macos/socket#tcp-nodelay) | `TCP_NODELAY`: send small writes at once rather than gathering them. | | [`IPPROTO_IPV6`](https://rux-lang.dev/docs/api/macos/socket#ipproto-ipv6) | `IPPROTO_IPV6`: the level of IPv6's options. | | [`IPV6_V6ONLY`](https://rux-lang.dev/docs/api/macos/socket#ipv6-v6only) | `IPV6_V6ONLY`: accept only IPv6 on an IPv6 socket. | | [`SO_NOSIGPIPE`](https://rux-lang.dev/docs/api/macos/socket#so-nosigpipe) | `SO_NOSIGPIPE`: report a closed peer as an error rather than with `SIGPIPE`. | | [`F_SETFD`](https://rux-lang.dev/docs/api/macos/spawn#f-setfd) | `F_SETFD`: the [`fcntl`](https://rux-lang.dev/docs/api/macos/spawn#fcntl) command that sets a descriptor's flags. | | [`FD_CLOEXEC`](https://rux-lang.dev/docs/api/macos/spawn#fd-cloexec) | `FD_CLOEXEC`: close the descriptor when the process starts another program. | | [`WNOHANG`](https://rux-lang.dev/docs/api/macos/spawn#wnohang) | `WNOHANG`: have [`waitpid`](https://rux-lang.dev/docs/api/macos/spawn#waitpid) return at once when the child has not finished. | | [`SIGKILL`](https://rux-lang.dev/docs/api/macos/spawn#sigkill) | `SIGKILL`: the signal that ends a process at once and cannot be caught. | | [`SC_NPROCESSORS_ONLN`](https://rux-lang.dev/docs/api/macos/thread#sc-nprocessors-onln) | `_SC_NPROCESSORS_ONLN`: the [`sysconf`](https://rux-lang.dev/docs/api/macos/thread#sysconf) name for the number of processors currently online. | | [`UL_COMPARE_AND_WAIT`](https://rux-lang.dev/docs/api/macos/ulock#ul-compare-and-wait) | `UL_COMPARE_AND_WAIT`: wait on a 32-bit word that holds the expected value. | | [`ULF_WAKE_ALL`](https://rux-lang.dev/docs/api/macos/ulock#ulf-wake-all) | `ULF_WAKE_ALL`: wake every thread waiting on the word rather than one. | | [`ULF_NO_ERRNO`](https://rux-lang.dev/docs/api/macos/ulock#ulf-no-errno) | `ULF_NO_ERRNO`: report failure as a negative error number rather than through errno. | # Timespec A duration or an instant, as seconds and nanoseconds. ```rux pub struct Timespec { pub seconds: int64; pub nanoseconds: int64; } ``` ## Fields | Name | Type | Description | | ------------- | ------- | --------------------------------------------------- | | `seconds` | `int64` | Whole seconds. | | `nanoseconds` | `int64` | Nanoseconds within the second, in `[0, 999999999]`. | # Timeval A duration or an instant, as seconds and microseconds. ```rux pub struct Timeval { pub seconds: int64; pub microseconds: int32; } ``` Darwin's x86-64 layout is an eight-byte `time_t` followed by a four-byte `suseconds_t`, and four bytes of trailing padding. The padding is why this is not two 64-bit fields, and why writing it as though it were corrupts nothing but reads back a microsecond count that is half stale. ## Fields | Name | Type | Description | | -------------- | ------- | ------------------------------------------------- | | `seconds` | `int64` | Whole seconds. | | `microseconds` | `int32` | Microseconds within the second, in `[0, 999999]`. | # Types macOS's scalar types for process, file and user identifiers. ## `FileDescriptor` ```rux pub type FileDescriptor = int32 ``` A file descriptor, as the kernel numbers one. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/Types.rux#L11){rel=""nofollow""} ## `FileMode` ```rux pub type FileMode = uint16 ``` A file's type and permission bits. Sixteen bits here, where Linux's `mode_t` is thirty-two. The bit meanings agree; the width does not. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/Types.rux#L20){rel=""nofollow""} ## `FileOffset` ```rux pub type FileOffset = int64 ``` A byte offset within a file, 64 bits on every supported Apple target. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/Types.rux#L15){rel=""nofollow""} ## `GroupId` ```rux pub type GroupId = uint32 ``` A group identifier. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/Types.rux#L28){rel=""nofollow""} ## `ProcessId` ```rux pub type ProcessId = int32 ``` A process identifier, as `getpid` reports one. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/Types.rux#L7){rel=""nofollow""} ## `UserId` ```rux pub type UserId = uint32 ``` A user identifier. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/Types.rux#L24){rel=""nofollow""} # Clocks Reading clocks and sleeping. ## `ClockRealtime` ```rux pub const ClockRealtime: int32 = 0; ``` `CLOCK_REALTIME`: wall-clock time, which can jump when the system clock is set. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/Clock.rux#L10){rel=""nofollow""} ## `ClockMonotonic` ```rux pub const ClockMonotonic: int32 = 6; ``` `CLOCK_MONOTONIC`: time since boot, which never goes backwards. Darwin numbers this 6, where Linux uses 1 and FreeBSD uses 4. No clock identifier means the same thing on any two of the three systems. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/Clock.rux#L16){rel=""nofollow""} ## `ClockMonotonicRaw` ```rux pub const ClockMonotonicRaw: int32 = 4; ``` `CLOCK_MONOTONIC_RAW`: like [`ClockMonotonic`](https://rux-lang.dev/docs/api/macos/clock#clock-monotonic), but not adjusted by time synchronization. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/Clock.rux#L20){rel=""nofollow""} ## `ClockGetTime` ```rux pub func ClockGetTime( clockId: int32, time: *var Timespec ) -> int64 ``` Reads `clockId` into `time`. Callers pass an explicit address, as they do on Linux and FreeBSD: `ClockGetTime(ClockMonotonic, @time)`. The call itself needs macOS 10.12 or later; an older release has no such symbol and the program will not launch. `time` must be non-null and writable for a whole [`Timespec`](https://rux-lang.dev/docs/api/macos/timespec). [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/Clock.rux#L30){rel=""nofollow""} **Parameters** | Name | Type | Description | | --------- | --------------- | ------------------------------------------------- | | `clockId` | `int32` | which clock to read, one of the identifiers above | | `time` | `*var Timespec` | receives the reading | **Returns**: zero, or a negative error number ## `ClockGetResolution` ```rux pub func ClockGetResolution( clockId: int32, resolution: *var Timespec ) -> int64 ``` Reads the resolution of `clockId` into `resolution`. The resolution is the granularity the clock advances by, not the cost of reading it and not a promise about accuracy. Like [`ClockGetTime`](https://rux-lang.dev/docs/api/macos/clock#clock-get-time), it needs macOS 10.12 or later. `resolution` must be non-null and writable for a whole [`Timespec`](https://rux-lang.dev/docs/api/macos/timespec). [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/Clock.rux#L42){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------------ | --------------- | ----------------------------------------------------- | | `clockId` | `int32` | which clock to describe, one of the identifiers above | | `resolution` | `*var Timespec` | receives the granularity | **Returns**: zero, or a negative error number ## `GetTimeOfDay` ```rux pub func GetTimeOfDay(time: *var Timeval) -> int64 ``` Reads the wall clock into `time`, to microsecond resolution. The second argument of the underlying call is an obsolete time-zone output that this passes as null. [`Timeval`](https://rux-lang.dev/docs/api/macos/timeval) has Darwin's layout: an eight-byte second count and a four-byte microsecond count, not two 64-bit fields. `time` must be non-null and writable for a whole [`Timeval`](https://rux-lang.dev/docs/api/macos/timeval). [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/Clock.rux#L54){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------ | -------------- | -------------------- | | `time` | `*var Timeval` | receives the reading | **Returns**: zero, or a negative error number ## `Nanosleep` ```rux pub func Nanosleep( request: *Timespec, remaining: *var Timespec ) -> int64 ``` Suspends the caller for the requested duration. [`EINTR`](https://rux-lang.dev/docs/api/macos/errors#eintr) with the unslept time left in `remaining` is how a signal cutting the wait short is reported. `request` must be non-null, and its nanoseconds must be under one second. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/Clock.rux#L65){rel=""nofollow""} **Parameters** | Name | Type | Description | | ----------- | --------------- | --------------------------------------------------------------------------- | | `request` | `*Timespec` | how long to wait | | `remaining` | `*var Timespec` | receives the unslept time when a signal cut the wait short, and may be null | **Returns**: zero, or a negative error number # Directories and links The working directory, directory entries, removal, renaming and links. ## `RemoveDirectory` ```rux pub const RemoveDirectory: int32 = 0x0080; ``` `AT_REMOVEDIR`: make [`UnlinkAt`](https://rux-lang.dev/docs/api/macos/directories#unlink-at) remove a directory rather than a file. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/File.rux#L84){rel=""nofollow""} ## `Getcwd` ```rux pub func Getcwd(buffer: *var char8, size: uint) -> int64 ``` Writes the current working directory's absolute path into `buffer`, NUL-terminated. Returns zero, or a negative error number. `ERANGE` where the buffer is too small for the answer. `buffer` must be writable for `size` bytes. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/File.rux#L151){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | ------------ | -------------------------------------------------------- | | `buffer` | `*var char8` | receives the working directory as a null-terminated path | | `size` | `uint` | how many bytes `buffer` holds | **Returns**: the bytes written including the terminator, or a negative error number ## `Chdir` ```rux pub func Chdir(path: *char8) -> int64 ``` Makes `path` the process's working directory. Returns zero, or a negative error number. The change is process-wide and immediately visible to every thread. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/File.rux#L161){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------ | -------- | ------------------------ | | `path` | `*char8` | the directory to move to | **Returns**: zero, or a negative error number ## `ReadlinkAt` ```rux pub func ReadlinkAt( directoryFd: FileDescriptor, path: *char8, buffer: *var char8, size: uint ) -> int64 ``` Reads the text a symbolic link holds into `buffer`. `directoryFd` is [`AtFdCwd`](https://rux-lang.dev/docs/api/macos/files#at-fd-cwd) for an ordinary path. Returns the number of bytes written, or a negative error number. The text is **not** NUL-terminated, and is silently truncated where it does not fit. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/File.rux#L174){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------------- | ---------------- | ----------------------------------------------------------------------------------------------------------------------------- | | `directoryFd` | `FileDescriptor` | the directory `path` is relative to, or [`AtFdCwd`](https://rux-lang.dev/docs/api/macos/files#at-fd-cwd) for an ordinary path | | `path` | `*char8` | the symbolic link to read | | `buffer` | `*var char8` | receives the link's text, without a terminator | | `size` | `uint` | how many bytes `buffer` holds | **Returns**: the bytes written, which equals `size` when the text was truncated, or a negative error number ## `SymlinkNoFollow` ```rux pub const SymlinkNoFollow: int32 = 0x0020; ``` `AT_SYMLINK_NOFOLLOW`: act on a symbolic link itself rather than on what it points at. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/File.rux#L180){rel=""nofollow""} ## `LinkAt` ```rux pub func LinkAt( oldDirectoryFd: FileDescriptor, oldPath: *char8, newDirectoryFd: FileDescriptor, newPath: *char8, flags: int32 ) -> int64 ``` Creates a hard link: `newPath` becomes a second name for the file `oldPath` names. Returns zero, or a negative error number. `flags` is zero to leave a symbolic link at `oldPath` unfollowed, or [`FollowSymlinks`](https://rux-lang.dev/docs/api/macos/directories#follow-symlinks) to link what it points at. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/File.rux#L245){rel=""nofollow""} **Parameters** | Name | Type | Description | | ---------------- | ---------------- | -------------------------------------------------------------------------------------------------------------------------------- | | `oldDirectoryFd` | `FileDescriptor` | the directory `oldPath` is relative to | | `oldPath` | `*char8` | the existing name | | `newDirectoryFd` | `FileDescriptor` | the directory `newPath` is relative to | | `newPath` | `*char8` | the new name for the same file | | `flags` | `int32` | zero, or [`FollowSymlinks`](https://rux-lang.dev/docs/api/macos/directories#follow-symlinks) to link what a final link points at | **Returns**: zero, or a negative error number ## `FollowSymlinks` ```rux pub const FollowSymlinks: int32 = 0x0040; ``` `AT_SYMLINK_FOLLOW`: make [`LinkAt`](https://rux-lang.dev/docs/api/macos/directories#link-at) link a symbolic link's target rather than the link. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/File.rux#L252){rel=""nofollow""} ## `SymlinkAt` ```rux pub func SymlinkAt( target: *char8, newDirectoryFd: FileDescriptor, linkPath: *char8 ) -> int64 ``` Creates a symbolic link at `linkPath` holding `target` as its text. Returns zero, or a negative error number. The target is stored, not checked: a dangling link is created as readily as a good one, which is a property callers rely on. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/File.rux#L262){rel=""nofollow""} **Parameters** | Name | Type | Description | | ---------------- | ---------------- | ------------------------------------------------- | | `target` | `*char8` | the text the link will hold, which need not exist | | `newDirectoryFd` | `FileDescriptor` | the directory `linkPath` is relative to | | `linkPath` | `*char8` | the link to create | **Returns**: zero, or a negative error number ## `Getdirentries64` ```rux pub func Getdirentries64( fd: FileDescriptor, buffer: *var opaque, count: uint, position: *var int64 ) -> int64 ``` Reads directory entries from `fd` into `buffer`, and returns the bytes filled, zero at the end, or a negative error number. The buffer holds packed 64-bit-inode `dirent` records: the inode at offset 0 (8 bytes), a seek cookie at 8 (8 bytes), the record's length at 16 (2 bytes), the name's length at 18 (2 bytes), the entry type at 20 (1 byte), and the name from 21. The kernel writes as many whole records as fit. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/File.rux#L277){rel=""nofollow""} **Parameters** | Name | Type | Description | | ---------- | ---------------- | --------------------------------------- | | `fd` | `FileDescriptor` | an open descriptor | | `buffer` | `*var opaque` | receives the packed directory records | | `count` | `uint` | how many bytes `buffer` holds | | `position` | `*var int64` | receives the position of the block read | **Returns**: the bytes filled, zero at the end of the directory, or a negative error number ## `UnlinkAt` ```rux pub func UnlinkAt( directoryFd: FileDescriptor, path: *char8, flags: int32 ) -> int64 ``` Removes the name `path` from its directory. `flags` is zero for a file or [`RemoveDirectory`](https://rux-lang.dev/docs/api/macos/directories#remove-directory) for an empty directory. Removing a name does not free the file. `path` must be non-null and terminated. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/File.rux#L311){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------------- | ---------------- | ----------------------------------------------------------------------------------------------------------------------------- | | `directoryFd` | `FileDescriptor` | the directory `path` is relative to, or [`AtFdCwd`](https://rux-lang.dev/docs/api/macos/files#at-fd-cwd) for an ordinary path | | `path` | `*char8` | the name to remove | | `flags` | `int32` | zero for a file, or [`RemoveDirectory`](https://rux-lang.dev/docs/api/macos/directories#remove-directory) for a directory | **Returns**: zero, or a negative error number ## `MkdirAt` ```rux pub func MkdirAt( directoryFd: FileDescriptor, path: *char8, mode: FileMode ) -> int64 ``` Creates a directory named `path` with permission bits `mode`. Reports [`EEXIST`](https://rux-lang.dev/docs/api/macos/errors#eexist) when the name is taken. `path` must be non-null and terminated. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/File.rux#L323){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------------- | ---------------- | ----------------------------------------------------------------------------------------------------------------------------- | | `directoryFd` | `FileDescriptor` | the directory `path` is relative to, or [`AtFdCwd`](https://rux-lang.dev/docs/api/macos/files#at-fd-cwd) for an ordinary path | | `path` | `*char8` | the directory to create | | `mode` | `FileMode` | the permission bits for it | **Returns**: zero, or a negative error number ## `RenameAt` ```rux pub func RenameAt( oldDirectoryFd: FileDescriptor, oldPath: *char8, newDirectoryFd: FileDescriptor, newPath: *char8 ) -> int64 ``` Renames `oldPath` to `newPath`, each resolved against its own directory descriptor. Within one file system this replaces any existing `newPath` atomically. Across file systems it reports [`EXDEV`](https://rux-lang.dev/docs/api/macos/errors#exdev). Both paths must be non-null and terminated. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/File.rux#L336){rel=""nofollow""} **Parameters** | Name | Type | Description | | ---------------- | ---------------- | -------------------------------------- | | `oldDirectoryFd` | `FileDescriptor` | the directory `oldPath` is relative to | | `oldPath` | `*char8` | the name to move | | `newDirectoryFd` | `FileDescriptor` | the directory `newPath` is relative to | | `newPath` | `*char8` | the name to move it to | **Returns**: zero, or a negative error number # GetRandom Fills `length` bytes of `buffer` with unpredictable bytes. ```rux pub func GetRandom(buffer: *var opaque, length: uint) ``` `buffer` is borrowed and written; `length` is read by value. Returns nothing, because this cannot fail: the generator is seeded before any user code runs and never blocks. Suitable for a key, a token, or anything an adversary would like to guess. Runs in time proportional to `length` and allocates nothing. `buffer` must be writable for `length` bytes. ## Parameters | Name | Type | Description | | -------- | ------------- | ----------------------- | | `buffer` | `*var opaque` | receives the bytes | | `length` | `uint` | how many bytes to write | # Process Ending the process and asking its identifier. ## `_NSGetArgc` ```rux pub extern func _NSGetArgc() -> *int32 ``` The address of the process's argument count. dyld fills it before the program starts, from the stack the kernel built. The count belongs to the process for its whole life and must not be written. **See also**: <https://keith.github.io/xcode-man-pages/environ.7.html>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/LibSystem.rux#L178){rel=""nofollow""} **Returns**: the address of the argument count, which is never null ## `_NSGetArgv` ```rux pub extern func _NSGetArgv() -> ***char8 ``` The address of the process's argument vector. The vector holds the argument count's worth of NUL-terminated byte strings followed by a null, all owned by the process for its whole life. **See also**: <https://keith.github.io/xcode-man-pages/environ.7.html>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/LibSystem.rux#L186){rel=""nofollow""} **Returns**: the address of the argument vector, which is never null ## `_NSGetExecutablePath` ```rux pub extern func _NSGetExecutablePath( buffer: *var char8, size: *var uint32 ) -> int32 ``` Copies the path of the process's executable into `buffer`, NUL-terminated. The path is the one the executable was loaded by, which may be relative or pass through symbolic links. When `buffer` is too short nothing is copied and `size` is set to the size needed. **See also**: <https://keith.github.io/xcode-man-pages/dyld.3.html>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/LibSystem.rux#L196){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | ------------- | ------------------------------------------------------------------- | | `buffer` | `*var char8` | receives the path | | `size` | `*var uint32` | the buffer's size in bytes, or the size needed when it is too short | **Returns**: zero on success, or -1 when the buffer is too short ## `_NSGetEnviron` ```rux pub extern func _NSGetEnviron() -> ***char8 ``` The address of the process's environment vector. The vector holds NUL-terminated `name=value` byte strings ended by a null. It is the C library's own `environ`, so a call that changes the environment may replace the vector it points to. **See also**: <https://keith.github.io/xcode-man-pages/environ.7.html>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/LibSystem.rux#L204){rel=""nofollow""} **Returns**: the address of the environment vector, which is never null ## `Exit` ```rux pub func Exit(code: int32) ``` Ends the calling process with `code`. Only the low eight bits reach a waiting parent. Does not return. This is `_exit` rather than `exit`: nothing registered with `atexit` runs and no stream is flushed, which matches what the Linux and FreeBSD packages do and is what a raw binding should do. A program wanting the other behaviour should call C's `exit` through `Rux/C`. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/Process.rux#L12){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------ | ------- | ---------------------------------- | | `code` | `int32` | the status to report to the parent | ## `GetPid` ```rux pub func GetPid() -> ProcessId ``` The calling process's own identifier. Cannot fail. Runs in constant time and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/Process.rux#L20){rel=""nofollow""} **Returns**: the calling process's identifier # Name resolution [`getaddrinfo`](https://rux-lang.dev/docs/api/macos/resolve#getaddrinfo) and the list of addresses it returns. ## `AddressInfo` ```rux pub struct AddressInfo { pub flags: int32; pub family: int32; pub socketType: int32; pub protocol: int32; pub addressLength: uint32; pub canonicalName: *char8; pub address: *opaque; pub next: *var AddressInfo; } ``` The C library's `addrinfo`: one result of [`getaddrinfo`](https://rux-lang.dev/docs/api/macos/resolve#getaddrinfo), linked to the next. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/Socket.rux#L217){rel=""nofollow""} **Fields** | Name | Type | Description | | --------------- | ------------------ | ---------------------------------------- | | `flags` | `int32` | Flags such as `AI_PASSIVE`. | | `family` | `int32` | The address family, or zero for any. | | `socketType` | `int32` | The socket type, or zero for any. | | `protocol` | `int32` | The protocol, or zero for any. | | `addressLength` | `uint32` | The size of `address` in bytes. | | `canonicalName` | `*char8` | The host's canonical name, or null. | | `address` | `*opaque` | The address, a `sockaddr`. | | `next` | `*var AddressInfo` | The next result, or null after the last. | ## `getaddrinfo` ```rux pub extern func getaddrinfo( node: *char8, service: *char8, hints: *AddressInfo, result: *var *var AddressInfo ) -> int32 ``` Looks up the addresses of a host and service. **See also**: <https://keith.github.io/xcode-man-pages/getaddrinfo.3.html>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/Socket.rux#L246){rel=""nofollow""} **Parameters** | Name | Type | Description | | --------- | ----------------------- | ---------------------------------------------------------------------------------------------------------------- | | `node` | `*char8` | the host name or numeric address, NUL-terminated, or null | | `service` | `*char8` | the service name or port number, NUL-terminated, or null | | `hints` | `*AddressInfo` | what kind of results are wanted, or null for every kind | | `result` | `*var *var AddressInfo` | receives the first result, freed with [`freeaddrinfo`](https://rux-lang.dev/docs/api/macos/resolve#freeaddrinfo) | **Returns**: zero, or an `EAI_*` code ## `freeaddrinfo` ```rux pub extern func freeaddrinfo(info: *var AddressInfo) ``` Frees the results of [`getaddrinfo`](https://rux-lang.dev/docs/api/macos/resolve#getaddrinfo). **See also**: <https://keith.github.io/xcode-man-pages/freeaddrinfo.3.html>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/Socket.rux#L252){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------ | ------------------ | ---------------- | | `info` | `*var AddressInfo` | the first result | # Starting processes `posix_spawn` and its file actions, and waiting for and signalling a child. ## `SpawnFileActions` ```rux pub struct SpawnFileActions { // private fields } ``` Room for a `posix_spawn_file_actions_t`, which each C library sizes its own way and none larger than this. Only ever passed by address to the `posix_spawn_file_actions_*` calls, which initialize and read it. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/Spawn.rux#L13){rel=""nofollow""} **Constructors** ### `SpawnFileActions` ```rux pub func SpawnFileActions() -> SpawnFileActions ``` Zeroed storage for [`posix_spawn_file_actions_init`](https://rux-lang.dev/docs/api/macos/spawn#posix-spawn-file-actions-init) to initialize. **Returns**: the storage [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/Spawn.rux#L21){rel=""nofollow""} ## `F_SETFD` ```rux pub const F_SETFD: int32 = 2; ``` `F_SETFD`: the [`fcntl`](https://rux-lang.dev/docs/api/macos/spawn#fcntl) command that sets a descriptor's flags. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/Spawn.rux#L29){rel=""nofollow""} ## `FD_CLOEXEC` ```rux pub const FD_CLOEXEC: int32 = 1; ``` `FD_CLOEXEC`: close the descriptor when the process starts another program. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/Spawn.rux#L34){rel=""nofollow""} ## `WNOHANG` ```rux pub const WNOHANG: int32 = 1; ``` `WNOHANG`: have [`waitpid`](https://rux-lang.dev/docs/api/macos/spawn#waitpid) return at once when the child has not finished. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/Spawn.rux#L39){rel=""nofollow""} ## `SIGKILL` ```rux pub const SIGKILL: int32 = 9; ``` `SIGKILL`: the signal that ends a process at once and cannot be caught. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/Spawn.rux#L44){rel=""nofollow""} ## `posix_spawnp` ```rux pub extern func posix_spawnp( pid: *var int32, file: *char8, fileActions: *SpawnFileActions, attributes: *opaque, arguments: **char8, environment: **char8 ) -> int32 ``` Starts `file`, found through `PATH` when it has no slash, as a child process. **See also**: <https://keith.github.io/xcode-man-pages/posix_spawn.3.html>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/Spawn.rux#L58){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------------- | ------------------- | ---------------------------------------------------------------------- | | `pid` | `*var int32` | receives the child's process identifier | | `file` | `*char8` | the program, NUL-terminated | | `fileActions` | `*SpawnFileActions` | the descriptor and directory setup to run in the child first, or null | | `attributes` | `*opaque` | spawn attributes, or null for the defaults | | `arguments` | `**char8` | the argument vector, its first entry the program's name, ended by null | | `environment` | `**char8` | the environment, `NAME=VALUE` entries ended by null | **Returns**: zero, or an error number ## `posix_spawn_file_actions_init` ```rux pub extern func posix_spawn_file_actions_init(actions: *var SpawnFileActions) -> int32 ``` Initializes an empty list of file actions. **See also**: <https://keith.github.io/xcode-man-pages/posix_spawn_file_actions_init.3.html>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/Spawn.rux#L66){rel=""nofollow""} **Parameters** | Name | Type | Description | | --------- | ----------------------- | ------------------------- | | `actions` | `*var SpawnFileActions` | the storage to initialize | **Returns**: zero, or an error number ## `posix_spawn_file_actions_destroy` ```rux pub extern func posix_spawn_file_actions_destroy(actions: *var SpawnFileActions) -> int32 ``` Releases what [`posix_spawn_file_actions_init`](https://rux-lang.dev/docs/api/macos/spawn#posix-spawn-file-actions-init) and the actions added since set up. **See also**: <https://keith.github.io/xcode-man-pages/posix_spawn_file_actions_destroy.3.html>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/Spawn.rux#L73){rel=""nofollow""} **Parameters** | Name | Type | Description | | --------- | ----------------------- | ------------------------ | | `actions` | `*var SpawnFileActions` | initialized file actions | **Returns**: zero, or an error number ## `posix_spawn_file_actions_adddup2` ```rux pub extern func posix_spawn_file_actions_adddup2( actions: *var SpawnFileActions, fd: int32, newFd: int32 ) -> int32 ``` Adds an action duplicating `fd` onto `newFd` in the child. **See also**: <https://keith.github.io/xcode-man-pages/posix_spawn_file_actions_adddup2.3.html>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/Spawn.rux#L82){rel=""nofollow""} **Parameters** | Name | Type | Description | | --------- | ----------------------- | --------------------------- | | `actions` | `*var SpawnFileActions` | initialized file actions | | `fd` | `int32` | the descriptor to duplicate | | `newFd` | `int32` | the descriptor it becomes | **Returns**: zero, or an error number ## `posix_spawn_file_actions_addopen` ```rux pub extern func posix_spawn_file_actions_addopen( actions: *var SpawnFileActions, fd: int32, path: *char8, flags: int32, mode: FileMode ) -> int32 ``` Adds an action opening `path` as `fd` in the child. **See also**: <https://keith.github.io/xcode-man-pages/posix_spawn_file_actions_addopen.3.html>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/Spawn.rux#L93){rel=""nofollow""} **Parameters** | Name | Type | Description | | --------- | ----------------------- | ------------------------------------------ | | `actions` | `*var SpawnFileActions` | initialized file actions | | `fd` | `int32` | the descriptor the file becomes | | `path` | `*char8` | the file, NUL-terminated | | `flags` | `int32` | the open flags | | `mode` | `FileMode` | the permissions of a file the open creates | **Returns**: zero, or an error number ## `posix_spawn_file_actions_addchdir_np` ```rux pub extern func posix_spawn_file_actions_addchdir_np( actions: *var SpawnFileActions, path: *char8 ) -> int32 ``` Adds an action changing the child's working directory to `path`. **See also**: <https://keith.github.io/xcode-man-pages/posix_spawn_file_actions_addchdir_np.3.html>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/Spawn.rux#L102){rel=""nofollow""} **Parameters** | Name | Type | Description | | --------- | ----------------------- | ----------------------------- | | `actions` | `*var SpawnFileActions` | initialized file actions | | `path` | `*char8` | the directory, NUL-terminated | **Returns**: zero, or an error number ## `waitpid` ```rux pub extern func waitpid( pid: int32, status: *var int32, options: int32 ) -> int32 ``` Waits for a child to change state, and reports how it finished. **See also**: <https://keith.github.io/xcode-man-pages/waitpid.2.html>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/Spawn.rux#L111){rel=""nofollow""} **Parameters** | Name | Type | Description | | --------- | ------------ | --------------------------------------------------------------------------------------------------------------------------------- | | `pid` | `int32` | the child's process identifier | | `status` | `*var int32` | receives the encoded status | | `options` | `int32` | zero to wait, or [`WNOHANG`](https://rux-lang.dev/docs/api/macos/spawn#wnohang) to return at once when the child is still running | **Returns**: the child's identifier, zero with [`WNOHANG`](https://rux-lang.dev/docs/api/macos/spawn#wnohang) when it is still running, or -1 with the reason in errno ## `kill` ```rux pub extern func kill(pid: int32, signal: int32) -> int32 ``` Sends a signal to a process. **See also**: <https://keith.github.io/xcode-man-pages/kill.2.html>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/Spawn.rux#L119){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | ------- | ----------------------------------------------------------------------------------------- | | `pid` | `int32` | the process | | `signal` | `int32` | the signal number, such as [`SIGKILL`](https://rux-lang.dev/docs/api/macos/spawn#sigkill) | **Returns**: zero, or -1 with the reason in errno ## `fcntl` ```rux pub extern func fcntl( fd: int32, command: int32, ... ) -> int32 ``` Performs a control operation on a descriptor, such as setting its flags with [`F_SETFD`](https://rux-lang.dev/docs/api/macos/spawn#f-setfd). **See also**: <https://keith.github.io/xcode-man-pages/fcntl.2.html>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/Spawn.rux#L127){rel=""nofollow""} **Parameters** | Name | Type | Description | | --------- | ------- | -------------- | | `fd` | `int32` | the descriptor | | `command` | `int32` | the operation | | `...` | | | **Returns**: the operation's result, or -1 with the reason in errno # Threads POSIX threads: starting, joining and detaching them, their stack size, and the processor count. ## `PThread` ```rux pub type PThread = uint64 ``` A thread as the C library names it, `pthread_t`. Every system this package family binds keeps it in one word. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/Thread.rux#L13){rel=""nofollow""} ## `PThreadAttributes` ```rux pub struct PThreadAttributes { // private fields } ``` Room for a `pthread_attr_t`, which each C library sizes its own way and none larger than this. Only ever passed by address to the `pthread_attr_*` calls, which initialize and read it. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/Thread.rux#L18){rel=""nofollow""} **Constructors** ### `PThreadAttributes` ```rux pub func PThreadAttributes() -> PThreadAttributes ``` Zeroed storage for [`pthread_attr_init`](https://rux-lang.dev/docs/api/macos/thread#pthread-attr-init) to initialize. **Returns**: the storage [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/Thread.rux#L26){rel=""nofollow""} ## `SC_NPROCESSORS_ONLN` ```rux pub const SC_NPROCESSORS_ONLN: int32 = 58; ``` `_SC_NPROCESSORS_ONLN`: the [`sysconf`](https://rux-lang.dev/docs/api/macos/thread#sysconf) name for the number of processors currently online. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/Thread.rux#L34){rel=""nofollow""} ## `pthread_create` ```rux pub extern func pthread_create( thread: *var PThread, attributes: *PThreadAttributes, start: *opaque, argument: *var opaque ) -> int32 ``` Starts a thread running `start(argument)`. **See also**: <https://keith.github.io/xcode-man-pages/pthread_create.3.html>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/Thread.rux#L46){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------------ | -------------------- | --------------------------------------------------------------------- | | `thread` | `*var PThread` | receives the new thread | | `attributes` | `*PThreadAttributes` | initialized attributes, or null for the defaults | | `start` | `*opaque` | the thread's entry point, a function taking and returning one pointer | | `argument` | `*var opaque` | the value handed to the entry point | **Returns**: zero, or an error number ## `pthread_join` ```rux pub extern func pthread_join( thread: PThread, result: *var *var opaque ) -> int32 ``` Waits for a thread to finish and releases it. **See also**: <https://keith.github.io/xcode-man-pages/pthread_join.3.html>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/Thread.rux#L55){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | ------------------ | ----------------------------------------------------------------- | | `thread` | `PThread` | a thread nothing has joined or detached | | `result` | `*var *var opaque` | receives the value its entry point returned, or null to ignore it | **Returns**: zero, or an error number ## `pthread_detach` ```rux pub extern func pthread_detach(thread: PThread) -> int32 ``` Lets a thread release itself when it finishes, so nothing has to join it. **See also**: <https://keith.github.io/xcode-man-pages/pthread_detach.3.html>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/Thread.rux#L62){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | --------- | --------------------------------------- | | `thread` | `PThread` | a thread nothing has joined or detached | **Returns**: zero, or an error number ## `pthread_attr_init` ```rux pub extern func pthread_attr_init(attributes: *var PThreadAttributes) -> int32 ``` Initializes thread attributes to the defaults. **See also**: <https://keith.github.io/xcode-man-pages/pthread_attr_init.3.html>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/Thread.rux#L69){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------------ | ------------------------ | ------------------------- | | `attributes` | `*var PThreadAttributes` | the storage to initialize | **Returns**: zero, or an error number ## `pthread_attr_setstacksize` ```rux pub extern func pthread_attr_setstacksize( attributes: *var PThreadAttributes, size: uint ) -> int32 ``` Sets the stack size a thread started with these attributes gets. **See also**: <https://keith.github.io/xcode-man-pages/pthread_attr_setstacksize.3.html>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/Thread.rux#L77){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------------ | ------------------------ | ------------------------------------------------------ | | `attributes` | `*var PThreadAttributes` | initialized attributes | | `size` | `uint` | the stack size in bytes, at least the system's minimum | **Returns**: zero, or an error number ## `pthread_attr_destroy` ```rux pub extern func pthread_attr_destroy(attributes: *var PThreadAttributes) -> int32 ``` Releases what [`pthread_attr_init`](https://rux-lang.dev/docs/api/macos/thread#pthread-attr-init) set up. **See also**: <https://keith.github.io/xcode-man-pages/pthread_attr_destroy.3.html>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/Thread.rux#L84){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------------ | ------------------------ | ---------------------- | | `attributes` | `*var PThreadAttributes` | initialized attributes | **Returns**: zero, or an error number ## `pthread_threadid_np` ```rux pub extern func pthread_threadid_np( thread: PThread, id: *var uint64 ) -> int32 ``` Reads the system-wide identifier of a thread, or of the calling thread when `thread` is zero. **See also**: <https://keith.github.io/xcode-man-pages/pthread_threadid_np.3.html>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/Thread.rux#L92){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | ------------- | ------------------------------------------------------- | | `thread` | `PThread` | the thread to ask about, or zero for the calling thread | | `id` | `*var uint64` | receives the identifier | **Returns**: zero, or an error number ## `sched_yield` ```rux pub extern func sched_yield() -> int32 ``` Gives up the processor so another ready thread can run. **See also**: <https://keith.github.io/xcode-man-pages/sched_yield.2.html>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/Thread.rux#L98){rel=""nofollow""} **Returns**: zero, or -1 with the reason in errno ## `sysconf` ```rux pub extern func sysconf(name: int32) -> int64 ``` Reads a system configuration value. **See also**: <https://keith.github.io/xcode-man-pages/sysconf.3.html>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/Thread.rux#L105){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------ | ------- | ------------------------------------------------------------------------------------------------------------------ | | `name` | `int32` | the value to read, such as [`SC_NPROCESSORS_ONLN`](https://rux-lang.dev/docs/api/macos/thread#sc-nprocessors-onln) | **Returns**: the value, or -1 when the system has no limit or does not know the name # Dynamic loading libSystem, and the mode flags [`dlopen`](https://rux-lang.dev/docs/api/macos/dynamic#dlopen) takes. ## `RTLD_LAZY` ```rux pub const RTLD_LAZY: int32 = 1; ``` `RTLD_LAZY`: resolve a function symbol the first time it is called rather than at load. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/Dynamic.rux#L8){rel=""nofollow""} ## `RTLD_NOW` ```rux pub const RTLD_NOW: int32 = 2; ``` `RTLD_NOW`: resolve every symbol before [`dlopen`](https://rux-lang.dev/docs/api/macos/dynamic#dlopen) returns. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/Dynamic.rux#L13){rel=""nofollow""} ## `RTLD_LOCAL` ```rux pub const RTLD_LOCAL: int32 = 4; ``` `RTLD_LOCAL`: keep this object's symbols to itself, which is Darwin's default. Darwin numbers this 4 and [`RTLD_GLOBAL`](https://rux-lang.dev/docs/api/macos/dynamic#rtld-global) 8, where both Linux and FreeBSD use 0 and 256. Carrying either value between packages selects the opposite of what was meant. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/Dynamic.rux#L20){rel=""nofollow""} ## `RTLD_GLOBAL` ```rux pub const RTLD_GLOBAL: int32 = 8; ``` `RTLD_GLOBAL`: make this object's symbols available to objects loaded afterwards. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/Dynamic.rux#L25){rel=""nofollow""} ## `SystemLib` ```rux pub const SystemLib = "libSystem.B.dylib"; ``` The library every Darwin interface is reached through. A single dynamic library re-exporting libc, libm, libpthread and the rest; there is no separate `libc.dylib` to link on Apple platforms. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/LibSystem.rux#L15){rel=""nofollow""} ## `dlopen` ```rux pub extern func dlopen( filename: *char8, flags: int32 ) -> *var opaque ``` Loads a shared object and returns a handle to it, or null on failure. A name without a slash is resolved by the loader's own search rules, and one with a slash as a path. A second call for an object already loaded returns the same handle and raises its reference count rather than loading it twice. Failure is reported through [`dlerror`](https://rux-lang.dev/docs/api/macos/dynamic#dlerror), not errno. **See also**: <https://keith.github.io/xcode-man-pages/dlopen.3.html>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/LibSystem.rux#L215){rel=""nofollow""} **Parameters** | Name | Type | Description | | ---------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `filename` | `*char8` | a NUL-terminated name or path, or null for the main program | | `flags` | `int32` | [`RTLD_LAZY`](https://rux-lang.dev/docs/api/macos/dynamic#rtld-lazy) or [`RTLD_NOW`](https://rux-lang.dev/docs/api/macos/dynamic#rtld-now), combined with the other `RTLD_*` flags | **Returns**: a handle for [`dlsym`](https://rux-lang.dev/docs/api/macos/dynamic#dlsym) and [`dlclose`](https://rux-lang.dev/docs/api/macos/dynamic#dlclose), or null with the reason in [`dlerror`](https://rux-lang.dev/docs/api/macos/dynamic#dlerror) ## `dlsym` ```rux pub extern func dlsym( handle: *var opaque, symbol: *char8 ) -> *var opaque ``` Finds a symbol in a loaded object and returns its address, or null. A null return is ambiguous, since a symbol whose address is legitimately zero exists. Clear [`dlerror`](https://rux-lang.dev/docs/api/macos/dynamic#dlerror) by calling it, then call this, then read [`dlerror`](https://rux-lang.dev/docs/api/macos/dynamic#dlerror) again to tell the two apart. **See also**: <https://keith.github.io/xcode-man-pages/dlsym.3.html>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/LibSystem.rux#L225){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | ------------- | ---------------------------------------------------------------------------- | | `handle` | `*var opaque` | a handle from [`dlopen`](https://rux-lang.dev/docs/api/macos/dynamic#dlopen) | | `symbol` | `*char8` | the NUL-terminated symbol name | **Returns**: the symbol's address, or null ## `dlclose` ```rux pub extern func dlclose(handle: *var opaque) -> int32 ``` Drops one reference to a loaded object, unloading it when the last one goes. Every address obtained from the object through [`dlsym`](https://rux-lang.dev/docs/api/macos/dynamic#dlsym) becomes invalid once it is actually unloaded, which this gives no way to observe. **See also**: <https://keith.github.io/xcode-man-pages/dlclose.3.html>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/LibSystem.rux#L234){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | ------------- | ---------------------------------------------------------------------------- | | `handle` | `*var opaque` | a handle from [`dlopen`](https://rux-lang.dev/docs/api/macos/dynamic#dlopen) | **Returns**: zero on success, and non-zero with the reason in [`dlerror`](https://rux-lang.dev/docs/api/macos/dynamic#dlerror) ## `dlerror` ```rux pub extern func dlerror() -> *char8 ``` Reports the most recent loader error and clears it, or returns null when there is none. The message points at storage the loader owns and a later call may reuse. Reading it clears the error, so two calls in a row report the second as no error at all. **See also**: <https://keith.github.io/xcode-man-pages/dlerror.3.html>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/LibSystem.rux#L242){rel=""nofollow""} **Returns**: a NUL-terminated message, or null # Errors The error numbers, and telling a raw result from an error. ## `EPERM` ```rux pub const EPERM: int64 = 1; ``` `EPERM`: the operation is not permitted to this caller. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/Errors.rux#L12){rel=""nofollow""} ## `ENOENT` ```rux pub const ENOENT: int64 = 2; ``` `ENOENT`: no such file or directory. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/Errors.rux#L17){rel=""nofollow""} ## `ESRCH` ```rux pub const ESRCH: int64 = 3; ``` `ESRCH`: no process has that identifier. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/Errors.rux#L22){rel=""nofollow""} ## `EINTR` ```rux pub const EINTR: int64 = 4; ``` `EINTR`: the call was interrupted by a signal before it did anything. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/Errors.rux#L27){rel=""nofollow""} ## `EIO` ```rux pub const EIO: int64 = 5; ``` `EIO`: a low-level input or output error. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/Errors.rux#L32){rel=""nofollow""} ## `ENXIO` ```rux pub const ENXIO: int64 = 6; ``` `ENXIO`: no such device or address. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/Errors.rux#L37){rel=""nofollow""} ## `EBADF` ```rux pub const EBADF: int64 = 9; ``` `EBADF`: the file descriptor is not open, or is not open for what was asked. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/Errors.rux#L42){rel=""nofollow""} ## `ENOMEM` ```rux pub const ENOMEM: int64 = 12; ``` `ENOMEM`: not enough memory to satisfy the request. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/Errors.rux#L47){rel=""nofollow""} ## `EACCES` ```rux pub const EACCES: int64 = 13; ``` `EACCES`: permission denied. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/Errors.rux#L52){rel=""nofollow""} ## `EFAULT` ```rux pub const EFAULT: int64 = 14; ``` `EFAULT`: an address the call was given is outside the caller's address space. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/Errors.rux#L57){rel=""nofollow""} ## `EBUSY` ```rux pub const EBUSY: int64 = 16; ``` `EBUSY`: the resource is in use by something else. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/Errors.rux#L62){rel=""nofollow""} ## `EEXIST` ```rux pub const EEXIST: int64 = 17; ``` `EEXIST`: the file already exists. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/Errors.rux#L67){rel=""nofollow""} ## `EXDEV` ```rux pub const EXDEV: int64 = 18; ``` `EXDEV`: the two paths are on different file systems. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/Errors.rux#L72){rel=""nofollow""} ## `ENOTDIR` ```rux pub const ENOTDIR: int64 = 20; ``` `ENOTDIR`: a path component that had to be a directory is not one. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/Errors.rux#L77){rel=""nofollow""} ## `EISDIR` ```rux pub const EISDIR: int64 = 21; ``` `EISDIR`: the target is a directory and the operation is not one a directory accepts. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/Errors.rux#L82){rel=""nofollow""} ## `EINVAL` ```rux pub const EINVAL: int64 = 22; ``` `EINVAL`: an argument is not valid. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/Errors.rux#L87){rel=""nofollow""} ## `EMFILE` ```rux pub const EMFILE: int64 = 24; ``` `EMFILE`: this process has too many descriptors open. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/Errors.rux#L92){rel=""nofollow""} ## `ENOSPC` ```rux pub const ENOSPC: int64 = 28; ``` `ENOSPC`: the device has no room left. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/Errors.rux#L97){rel=""nofollow""} ## `ESPIPE` ```rux pub const ESPIPE: int64 = 29; ``` `ESPIPE`: the descriptor is a pipe or socket and cannot be seeked. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/Errors.rux#L102){rel=""nofollow""} ## `EROFS` ```rux pub const EROFS: int64 = 30; ``` `EROFS`: the file system is mounted read-only. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/Errors.rux#L107){rel=""nofollow""} ## `EPIPE` ```rux pub const EPIPE: int64 = 32; ``` `EPIPE`: the reading end of the pipe is closed. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/Errors.rux#L112){rel=""nofollow""} ## `EAGAIN` ```rux pub const EAGAIN: int64 = 35; ``` `EAGAIN`: the operation would block, and the descriptor was set not to. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/Errors.rux#L117){rel=""nofollow""} ## `ELOOP` ```rux pub const ELOOP: int64 = 62; ``` `ELOOP`: too many symbolic links were followed resolving the path. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/Errors.rux#L122){rel=""nofollow""} ## `ENAMETOOLONG` ```rux pub const ENAMETOOLONG: int64 = 63; ``` `ENAMETOOLONG`: the path or a component of it is too long. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/Errors.rux#L127){rel=""nofollow""} ## `ENOSYS` ```rux pub const ENOSYS: int64 = 78; ``` `ENOSYS`: the system does not implement this call. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/Errors.rux#L132){rel=""nofollow""} ## `EOVERFLOW` ```rux pub const EOVERFLOW: int64 = 84; ``` `EOVERFLOW`: a value is too large for the type the call reports it in. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/Errors.rux#L137){rel=""nofollow""} ## `ETIMEDOUT` ```rux pub const ETIMEDOUT: int64 = 60; ``` `ETIMEDOUT`: the operation timed out. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/Errors.rux#L142){rel=""nofollow""} ## `MaximumErrno` ```rux pub const MaximumErrno: int64 = 4095; ``` The largest error number the normalized error range holds. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/Errors.rux#L146){rel=""nofollow""} ## `CurrentErrno` ```rux pub func CurrentErrno() -> int64 ``` The calling thread's current `errno` value. Takes nothing and returns the value by copy. Meaningful only immediately after a call that failed: nothing on Darwin clears it on success, so a value left over from an earlier failure is still there. Cannot fail. Runs in constant time and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/Errors.rux#L154){rel=""nofollow""} **Returns**: the calling thread's current `errno` ## `Normalize` ```rux pub func Normalize(result: int64) -> int64 ``` Folds a libSystem result and the thread's `errno` into one value. `result` is read by value. A result of `-1` becomes the negative of whatever `errno` holds; anything else is returned unchanged. That is what makes every wrapper in this package report the way the Linux and FreeBSD ones do, so a caller reads all three with [`IsError`](https://rux-lang.dev/docs/api/macos/errors#is-error) and [`Errno`](https://rux-lang.dev/docs/api/macos/errors#errno). A call that legitimately returns `-1` would be misread, which is why nothing here wraps one. Cannot fail. Runs in constant time and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/Errors.rux#L167){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | ------- | ---------------------------- | | `result` | `int64` | the libSystem result to fold | **Returns**: the result unchanged, or the negative of `errno` when it was -1 ## `IsError` ```rux pub func IsError(result: int64) -> bool ``` Whether a normalized result is one of the reserved error values. `result` is read by value. True for `-4095` through `-1`. Cannot fail. Runs in constant time and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/Errors.rux#L179){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | ------- | ---------------------- | | `result` | `int64` | the raw result to test | **Returns**: whether it is one of the reserved error values ## `Errno` ```rux pub func Errno(result: int64) -> int64 ``` The error number a normalized result carries, or zero when it carries none. `result` is read by value; the number is returned positive, as a man page names it. Cannot fail. Runs in constant time and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/Errors.rux#L189){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | ------- | ---------------------- | | `result` | `int64` | the raw result to read | **Returns**: the error number, positive, or zero when the result carries none # Files Opening, reading, writing and inspecting files through descriptors. ## `StdIn` ```rux pub const StdIn: int32 = 0; ``` The descriptor a process reads its input from, unless something reassigned it. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/File.rux#L14){rel=""nofollow""} ## `StdOut` ```rux pub const StdOut: int32 = 1; ``` The descriptor a process writes its output to. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/File.rux#L18){rel=""nofollow""} ## `StdErr` ```rux pub const StdErr: int32 = 2; ``` The descriptor a process writes its diagnostics to. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/File.rux#L22){rel=""nofollow""} ## `AtFdCwd` ```rux pub const AtFdCwd: int32 = -2; ``` `AT_FDCWD`: resolve a relative path against the current directory rather than a descriptor. Darwin spells this `-2`, where Linux and FreeBSD both use `-100`. Carrying the value between packages produces a descriptor number, not an error. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/File.rux#L28){rel=""nofollow""} ## `OpenReadOnly` ```rux pub const OpenReadOnly: int32 = 0x0000; ``` `O_RDONLY`: open for reading only. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/File.rux#L32){rel=""nofollow""} ## `OpenWriteOnly` ```rux pub const OpenWriteOnly: int32 = 0x0001; ``` `O_WRONLY`: open for writing only. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/File.rux#L36){rel=""nofollow""} ## `OpenReadWrite` ```rux pub const OpenReadWrite: int32 = 0x0002; ``` `O_RDWR`: open for both reading and writing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/File.rux#L40){rel=""nofollow""} ## `OpenCreate` ```rux pub const OpenCreate: int32 = 0x0200; ``` `O_CREAT`: create the file when it does not exist, which is when the mode argument is read. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/File.rux#L44){rel=""nofollow""} ## `OpenExclusive` ```rux pub const OpenExclusive: int32 = 0x0800; ``` `O_EXCL`: with [`OpenCreate`](https://rux-lang.dev/docs/api/macos/files#open-create), fail rather than open a file that already exists. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/File.rux#L48){rel=""nofollow""} ## `OpenTruncate` ```rux pub const OpenTruncate: int32 = 0x0400; ``` `O_TRUNC`: truncate the file to nothing when opening it for writing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/File.rux#L52){rel=""nofollow""} ## `OpenAppend` ```rux pub const OpenAppend: int32 = 0x0008; ``` `O_APPEND`: every write goes to the end. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/File.rux#L56){rel=""nofollow""} ## `OpenNonBlocking` ```rux pub const OpenNonBlocking: int32 = 0x0004; ``` [`O_NONBLOCK`](https://rux-lang.dev/docs/api/macos/poll#o-nonblock): reads and writes report [`EAGAIN`](https://rux-lang.dev/docs/api/macos/errors#eagain) rather than waiting. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/File.rux#L60){rel=""nofollow""} ## `OpenCloseOnExec` ```rux pub const OpenCloseOnExec: int32 = 0x01000000; ``` `O_CLOEXEC`: close this descriptor automatically when the process executes a new program. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/File.rux#L64){rel=""nofollow""} ## `OpenDirectory` ```rux pub const OpenDirectory: int32 = 0x00100000; ``` `O_DIRECTORY`: fail unless the target is a directory. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/File.rux#L68){rel=""nofollow""} ## `SeekSet` ```rux pub const SeekSet: int32 = 0; ``` `SEEK_SET`: measure the new offset from the start of the file. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/File.rux#L72){rel=""nofollow""} ## `SeekCurrent` ```rux pub const SeekCurrent: int32 = 1; ``` `SEEK_CUR`: measure the new offset from the current one. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/File.rux#L76){rel=""nofollow""} ## `SeekEnd` ```rux pub const SeekEnd: int32 = 2; ``` `SEEK_END`: measure the new offset from the end of the file. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/File.rux#L80){rel=""nofollow""} ## `Read` ```rux pub func Read( fd: FileDescriptor, buffer: *var opaque, count: uint ) -> int64 ``` Reads up to `count` bytes from `fd` into `buffer`. `buffer` is borrowed and written. Returns the number of bytes read, zero at end of file, or a negative error number. A short count is ordinary. `buffer` must be writable for `count` bytes. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/File.rux#L95){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | ---------------- | ------------------------- | | `fd` | `FileDescriptor` | an open descriptor | | `buffer` | `*var opaque` | receives the bytes | | `count` | `uint` | how many bytes to ask for | **Returns**: the bytes read, zero at end of file, or a negative error number ## `Write` ```rux pub func Write( fd: FileDescriptor, buffer: *opaque, count: uint ) -> int64 ``` Writes up to `count` bytes from `buffer` to `fd`. `buffer` is borrowed and read. Returns the number of bytes written, or a negative error number. A short count is ordinary and the rest has to be written by calling again. `buffer` must be readable for `count` bytes. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/File.rux#L108){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | ---------------- | ----------------------- | | `fd` | `FileDescriptor` | an open descriptor | | `buffer` | `*opaque` | the bytes to write | | `count` | `uint` | how many bytes to offer | **Returns**: the bytes written, or a negative error number ## `Close` ```rux pub func Close(fd: FileDescriptor) -> int64 ``` Closes `fd` and releases what the kernel held for it. Returns zero, or a negative error number. A failure does not mean the descriptor is still open. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/File.rux#L117){rel=""nofollow""} **Parameters** | Name | Type | Description | | ---- | ---------------- | ------------------ | | `fd` | `FileDescriptor` | an open descriptor | **Returns**: zero, or a negative error number ## `OpenAt` ```rux pub func OpenAt( directoryFd: FileDescriptor, path: *char8, flags: int32, mode: FileMode ) -> int64 ``` Opens `path` relative to `directoryFd` and returns a descriptor, or a negative error number. `directoryFd` is [`AtFdCwd`](https://rux-lang.dev/docs/api/macos/files#at-fd-cwd) for an ordinary path. `mode` is read only when [`OpenCreate`](https://rux-lang.dev/docs/api/macos/files#open-create) is set. `path` must be non-null and terminated. The mode is masked by the process umask. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/File.rux#L130){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------------- | ---------------- | ----------------------------------------------------------------------------------------------------------------------------- | | `directoryFd` | `FileDescriptor` | the directory `path` is relative to, or [`AtFdCwd`](https://rux-lang.dev/docs/api/macos/files#at-fd-cwd) for an ordinary path | | `path` | `*char8` | the path to open, as a null-terminated byte string | | `flags` | `int32` | the access mode and the open flags, combined with `|` | | `mode` | `FileMode` | the permission bits for a file this creates, ignored otherwise | **Returns**: the new descriptor, or a negative error number ## `Lseek` ```rux pub func Lseek( fd: FileDescriptor, offset: FileOffset, whence: int32 ) -> int64 ``` Moves the file offset of `fd` and returns where it ended up, or a negative error number. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/File.rux#L140){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | ---------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `fd` | `FileDescriptor` | an open descriptor | | `offset` | `FileOffset` | how far to move, interpreted according to `whence` | | `whence` | `int32` | [`SeekSet`](https://rux-lang.dev/docs/api/macos/files#seek-set), [`SeekCurrent`](https://rux-lang.dev/docs/api/macos/files#seek-current) or [`SeekEnd`](https://rux-lang.dev/docs/api/macos/files#seek-end) | **Returns**: the resulting offset from the start, or a negative error number ## `Fstat` ```rux pub func Fstat( fd: FileDescriptor, statBuffer: *var opaque ) -> int64 ``` Fills `statBuffer` with what the kernel knows about the file behind `fd`. Returns zero, or a negative error number. `statBuffer` must be writable for the whole of the 64-bit-inode `struct stat`, which is 144 bytes. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/File.rux#L189){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------------ | ---------------- | ----------------------------------------- | | `fd` | `FileDescriptor` | an open descriptor | | `statBuffer` | `*var opaque` | receives the architecture's `struct stat` | **Returns**: zero, or a negative error number ## `FstatAt` ```rux pub func FstatAt( directoryFd: FileDescriptor, path: *char8, statBuffer: *var opaque, flags: int32 ) -> int64 ``` Fills `statBuffer` with what the kernel knows about the file `path` names. `directoryFd` is [`AtFdCwd`](https://rux-lang.dev/docs/api/macos/files#at-fd-cwd) for an ordinary path. `flags` is zero to follow a symbolic link at the end of the path, or [`SymlinkNoFollow`](https://rux-lang.dev/docs/api/macos/directories#symlink-no-follow) to describe the link itself. Returns zero, or a negative error number. `statBuffer` must be writable for the whole of the 64-bit-inode `struct stat`, which is 144 bytes and whose layout this package does not model. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/File.rux#L204){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------------- | ---------------- | ------------------------------------------------------------------------------------------------------------------------------- | | `directoryFd` | `FileDescriptor` | the directory `path` is relative to, or [`AtFdCwd`](https://rux-lang.dev/docs/api/macos/files#at-fd-cwd) for an ordinary path | | `path` | `*char8` | the path to describe | | `statBuffer` | `*var opaque` | receives the architecture's `struct stat` | | `flags` | `int32` | zero to follow a final symbolic link, or [`SymlinkNoFollow`](https://rux-lang.dev/docs/api/macos/directories#symlink-no-follow) | **Returns**: zero, or a negative error number ## `FchmodAt` ```rux pub func FchmodAt( directoryFd: FileDescriptor, path: *char8, mode: FileMode, flags: int32 ) -> int64 ``` Sets the permission bits of the file `path` names. `directoryFd` is [`AtFdCwd`](https://rux-lang.dev/docs/api/macos/files#at-fd-cwd) for an ordinary path. `flags` may carry [`SymlinkNoFollow`](https://rux-lang.dev/docs/api/macos/directories#symlink-no-follow). Returns zero, or a negative error number. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/File.rux#L217){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------------- | ---------------- | ----------------------------------------------------------------------------------------------------------------------------- | | `directoryFd` | `FileDescriptor` | the directory `path` is relative to, or [`AtFdCwd`](https://rux-lang.dev/docs/api/macos/files#at-fd-cwd) for an ordinary path | | `path` | `*char8` | the path whose bits are set | | `mode` | `FileMode` | the permission bits to set | | `flags` | `int32` | zero, or [`SymlinkNoFollow`](https://rux-lang.dev/docs/api/macos/directories#symlink-no-follow) where the system supports it | **Returns**: zero, or a negative error number ## `UtimensAt` ```rux pub func UtimensAt( directoryFd: FileDescriptor, path: *char8, times: *opaque, flags: int32 ) -> int64 ``` Sets the access and modification times of the file `path` names. `times` is borrowed and holds two `timespec` values — access first, then modification — each a whole-second count and a nanosecond fraction, both 8 bytes. A null `times` sets both to now. `flags` may carry [`SymlinkNoFollow`](https://rux-lang.dev/docs/api/macos/directories#symlink-no-follow). Returns zero, or a negative error number. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/File.rux#L231){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------------- | ---------------- | ------------------------------------------------------------------------------------------------------------------------------- | | `directoryFd` | `FileDescriptor` | the directory `path` is relative to, or [`AtFdCwd`](https://rux-lang.dev/docs/api/macos/files#at-fd-cwd) for an ordinary path | | `path` | `*char8` | the path whose times are set | | `times` | `*opaque` | two `timespec` values, or null for now | | `flags` | `int32` | zero to follow a final symbolic link, or [`SymlinkNoFollow`](https://rux-lang.dev/docs/api/macos/directories#symlink-no-follow) | **Returns**: zero, or a negative error number ## `Fsync` ```rux pub func Fsync(fd: FileDescriptor) -> int64 ``` Flushes everything written to `fd` toward the storage device. Returns zero, or a negative error number. This is weaker on Darwin than everywhere else: it hands the data to the device without waiting for the device to commit it, so a power failure can still lose a write this reported as flushed. `F_FULLFSYNC` through [`fcntl`](https://rux-lang.dev/docs/api/macos/spawn#fcntl) is what actually waits, and this package does not wrap it. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/File.rux#L289){rel=""nofollow""} **Parameters** | Name | Type | Description | | ---- | ---------------- | ------------------ | | `fd` | `FileDescriptor` | an open descriptor | **Returns**: zero, or a negative error number ## `Ftruncate` ```rux pub func Ftruncate( fd: FileDescriptor, length: FileOffset ) -> int64 ``` Sets the length of the file behind `fd` to `length`. Growing creates a hole rather than allocating, so a later write into it can still fail with [`ENOSPC`](https://rux-lang.dev/docs/api/macos/errors#enospc). [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/File.rux#L299){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | ---------------- | ---------------------------------------- | | `fd` | `FileDescriptor` | an open descriptor | | `length` | `FileOffset` | the size the file should have afterwards | **Returns**: zero, or a negative error number ## `Dup2` ```rux pub func Dup2( oldFd: FileDescriptor, newFd: FileDescriptor ) -> int64 ``` Makes `newFd` a copy of `oldFd`, closing whatever `newFd` was. Returns `newFd`, or a negative error number. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/File.rux#L347){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------- | ---------------- | ------------------------------------ | | `oldFd` | `FileDescriptor` | the descriptor to duplicate | | `newFd` | `FileDescriptor` | the number the duplicate should have | **Returns**: `newFd`, or a negative error number ## `Pipe` ```rux pub func Pipe(descriptors: *var int32) -> int64 ``` Creates a pipe and writes its two descriptors into `descriptors`. The reading end lands at index zero and the writing end at index one. Darwin has no `pipe2`, so close-on-exec has to be set afterwards through [`fcntl`](https://rux-lang.dev/docs/api/macos/spawn#fcntl) — which leaves a window another thread can execute through. `descriptors` must be writable for two `int32` values. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/File.rux#L358){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------------- | ------------ | ------------------------------------------------------------------ | | `descriptors` | `*var int32` | receives the read end at index zero and the write end at index one | **Returns**: zero, or a negative error number # Memory Mapping, protecting and advising on pages of memory. ## `getpagesize` ```rux pub extern func getpagesize() -> int32 ``` Reports the system page size, in bytes. Darwin's page size is not the same on every machine: Apple Silicon uses 16 KiB where x86-64 uses 4 KiB, which is why this is asked rather than assumed. Cannot fail — a process that could not be told its own page size could not have been started. `Memory::QueryPageSize` is the wrapper to call; this is the raw entry point it binds, and is the only declaration in this block that is reachable from outside the package. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/LibSystem.rux#L142){rel=""nofollow""} **Returns**: the page size in bytes ## `ProtectionNone` ```rux pub const ProtectionNone: int32 = 0x00; ``` `PROT_NONE`: the pages may not be touched at all. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/Memory.rux#L10){rel=""nofollow""} ## `ProtectionRead` ```rux pub const ProtectionRead: int32 = 0x01; ``` `PROT_READ`: the pages may be read. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/Memory.rux#L14){rel=""nofollow""} ## `ProtectionWrite` ```rux pub const ProtectionWrite: int32 = 0x02; ``` `PROT_WRITE`: the pages may be written. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/Memory.rux#L18){rel=""nofollow""} ## `ProtectionExecute` ```rux pub const ProtectionExecute: int32 = 0x04; ``` `PROT_EXEC`: the pages may be executed. Apple Silicon refuses a mapping that is writable and executable at once unless the process carries the `com.apple.security.cs.allow-jit` entitlement and uses `MAP_JIT`, which this package does not wrap. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/Memory.rux#L24){rel=""nofollow""} ## `MapShared` ```rux pub const MapShared: int32 = 0x0001; ``` `MAP_SHARED`: writes are visible to other mappings of the same object and reach it. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/Memory.rux#L28){rel=""nofollow""} ## `MapPrivate` ```rux pub const MapPrivate: int32 = 0x0002; ``` `MAP_PRIVATE`: writes are private to this mapping and never reach the object. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/Memory.rux#L32){rel=""nofollow""} ## `MapFixed` ```rux pub const MapFixed: int32 = 0x0010; ``` `MAP_FIXED`: place the mapping exactly at the requested address, replacing whatever was there. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/Memory.rux#L36){rel=""nofollow""} ## `MapAnonymous` ```rux pub const MapAnonymous: int32 = 0x1000; ``` `MAP_ANON`: the mapping is backed by zeroed pages rather than by a file. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/Memory.rux#L40){rel=""nofollow""} ## `AdviseFree` ```rux pub const AdviseFree: int32 = 5; ``` `MADV_FREE`: the pages may be reclaimed, and read back as zero if they are. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/Memory.rux#L44){rel=""nofollow""} ## `AdviseDontNeed` ```rux pub const AdviseDontNeed: int32 = 4; ``` `MADV_DONTNEED`: the pages are not needed soon. Advisory on Darwin, as on FreeBSD. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/Memory.rux#L48){rel=""nofollow""} ## `AdviseWillNeed` ```rux pub const AdviseWillNeed: int32 = 3; ``` `MADV_WILLNEED`: the pages will be read soon. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/Memory.rux#L52){rel=""nofollow""} ## `Mmap` ```rux pub func Mmap( address: *opaque, length: uint, protection: int32, flags: int32, fd: int32, offset: uint64 ) -> int64 ``` Creates a mapping and returns its address, or a negative error number. `address` is a hint unless [`MapFixed`](https://rux-lang.dev/docs/api/macos/memory#map-fixed) is set. `fd` is the object to map, or `-1` with [`MapAnonymous`](https://rux-lang.dev/docs/api/macos/memory#map-anonymous). libSystem reports failure here as `MAP_FAILED`, which is `-1` cast to a pointer rather than a small negative number, so the failure is folded into the same normalized form every other wrapper uses. Test the result with [`IsError`](https://rux-lang.dev/docs/api/macos/errors#is-error), not for a sign: a valid address may have its top bit set. [`MapFixed`](https://rux-lang.dev/docs/api/macos/memory#map-fixed) replaces whatever occupies the address, including a mapping this program depends on. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/Memory.rux#L68){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------------ | --------- | ------------------------------------------------------------------------------------------------------ | | `address` | `*opaque` | a hint for where to map, or null to let the kernel choose | | `length` | `uint` | how many bytes, rounded up to whole pages | | `protection` | `int32` | what may be done with the pages, as `Protection*` flags | | `flags` | `int32` | the mapping flags, as `Map*` values | | `fd` | `int32` | the file to map, or -1 with [`MapAnonymous`](https://rux-lang.dev/docs/api/macos/memory#map-anonymous) | | `offset` | `uint64` | where in the file the mapping starts | **Returns**: the mapping's address, or a negative error number ## `Munmap` ```rux pub func Munmap(address: *opaque, length: uint) -> int64 ``` Releases the mapping that begins at `address` and spans `length` bytes. Returns zero, or a negative error number. Every pointer into the range becomes invalid. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/Memory.rux#L80){rel=""nofollow""} **Parameters** | Name | Type | Description | | --------- | --------- | -------------------------------------- | | `address` | `*opaque` | a page-aligned address to release from | | `length` | `uint` | how many bytes to release | **Returns**: zero, or a negative error number ## `Mprotect` ```rux pub func Mprotect( address: *opaque, length: uint, protection: int32 ) -> int64 ``` Changes what may be done with the pages covering a range. `address` must be page-aligned. Returns zero, or a negative error number. Apple Silicon refuses to make a range writable and executable at once without the JIT entitlement. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/Memory.rux#L92){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------------ | --------- | ----------------------------------------- | | `address` | `*opaque` | a page-aligned address | | `length` | `uint` | how many bytes, rounded up to whole pages | | `protection` | `int32` | what may be done with them afterwards | **Returns**: zero, or a negative error number ## `Madvise` ```rux pub func Madvise( address: *opaque, length: uint, advice: int32 ) -> int64 ``` Tells the kernel how the pages covering a range are about to be used. Advice is advice, with the exception of [`AdviseFree`](https://rux-lang.dev/docs/api/macos/memory#advise-free), which actually releases. [`AdviseFree`](https://rux-lang.dev/docs/api/macos/memory#advise-free) loses whatever the range held. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/Memory.rux#L104){rel=""nofollow""} **Parameters** | Name | Type | Description | | --------- | --------- | -------------------------------- | | `address` | `*opaque` | a page-aligned address | | `length` | `uint` | how many bytes the advice covers | | `advice` | `int32` | one of the `Advise*` values | **Returns**: zero, or a negative error number ## `QueryPageSize` ```rux pub func QueryPageSize() -> int64 ``` The size of a page, asked of libSystem. Darwin's page size is not the same on every machine: Apple Silicon uses 16 KiB where x86-64 uses 4 KiB, so this is asked rather than assumed. The underlying call cannot fail, which is why this one cannot either — the negative-error return exists so that one call shape reaches all three POSIX systems, not because Darwin has a failure to report. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/Memory.rux#L114){rel=""nofollow""} **Returns**: the page size in bytes, always positive on this system # Polling Descriptor flags and the kqueue filters a poller waits with. ## `F_GETFL` ```rux pub const F_GETFL: int32 = 3; ``` `F_GETFL`: the [`fcntl`](https://rux-lang.dev/docs/api/macos/spawn#fcntl) command that reads a descriptor's status flags. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/Poll.rux#L11){rel=""nofollow""} ## `F_SETFL` ```rux pub const F_SETFL: int32 = 4; ``` `F_SETFL`: the [`fcntl`](https://rux-lang.dev/docs/api/macos/spawn#fcntl) command that sets a descriptor's status flags. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/Poll.rux#L16){rel=""nofollow""} ## `O_NONBLOCK` ```rux pub const O_NONBLOCK: int32 = 0x4; ``` `O_NONBLOCK`: the status flag that makes a call fail with [`EAGAIN`](https://rux-lang.dev/docs/api/macos/errors#eagain) rather than wait. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/Poll.rux#L21){rel=""nofollow""} ## `EVFILT_READ` ```rux pub const EVFILT_READ: int16 = -1; ``` `EVFILT_READ`: the filter that reports a descriptor with something to read, or a connection to accept. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/Poll.rux#L26){rel=""nofollow""} ## `EVFILT_WRITE` ```rux pub const EVFILT_WRITE: int16 = -2; ``` `EVFILT_WRITE`: the filter that reports a descriptor a write would not wait on. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/Poll.rux#L31){rel=""nofollow""} ## `EV_ADD` ```rux pub const EV_ADD: uint16 = 0x1; ``` `EV_ADD`: add the change's filter, or update it. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/Poll.rux#L36){rel=""nofollow""} ## `EV_DELETE` ```rux pub const EV_DELETE: uint16 = 0x2; ``` `EV_DELETE`: remove the change's filter. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/Poll.rux#L41){rel=""nofollow""} ## `EV_RECEIPT` ```rux pub const EV_RECEIPT: uint16 = 0x40; ``` `EV_RECEIPT`: report each change as an event, with its outcome in `data`, rather than waiting. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/Poll.rux#L46){rel=""nofollow""} ## `EV_ERROR` ```rux pub const EV_ERROR: uint16 = 0x4000; ``` `EV_ERROR`: set on an event that reports a failed change, with the error number in `data`. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/Poll.rux#L51){rel=""nofollow""} ## `EV_EOF` ```rux pub const EV_EOF: uint16 = 0x8000; ``` `EV_EOF`: the peer has closed its side. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/Poll.rux#L56){rel=""nofollow""} ## `Kevent` ```rux pub struct Kevent { pub ident: uint64; pub filter: int16; pub flags: uint16; pub filterFlags: uint32; pub data: int64; pub userData: uint64; } ``` One `struct kevent` as 64-bit macOS lays it out: a change to register or an event to report. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/Poll.rux#L60){rel=""nofollow""} **Fields** | Name | Type | Description | | ------------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `ident` | `uint64` | The descriptor. | | `filter` | `int16` | [`EVFILT_READ`](https://rux-lang.dev/docs/api/macos/poll#evfilt-read) or [`EVFILT_WRITE`](https://rux-lang.dev/docs/api/macos/poll#evfilt-write). | | `flags` | `uint16` | [`EV_ADD`](https://rux-lang.dev/docs/api/macos/poll#ev-add), [`EV_DELETE`](https://rux-lang.dev/docs/api/macos/poll#ev-delete) and the flags reported back, such as [`EV_EOF`](https://rux-lang.dev/docs/api/macos/poll#ev-eof) and [`EV_ERROR`](https://rux-lang.dev/docs/api/macos/poll#ev-error). | | `filterFlags` | `uint32` | Filter-specific flags. | | `data` | `int64` | Filter-specific data: bytes ready, or an error number. | | `userData` | `uint64` | The word the caller chose, reported back with every event. | **Associated functions** ### `Of` ```rux pub func Of( ident: uint64, filter: int16, flags: uint16, userData: uint64 ) -> Kevent ``` A change or an empty event: `filter` on `ident` with `flags`, reporting `userData`. | Name | Type | Description | | ---------- | -------- | ------------------------------------------------------------------- | | `ident` | `uint64` | the descriptor | | `filter` | `int16` | the filter | | `flags` | `uint16` | such as [`EV_ADD`](https://rux-lang.dev/docs/api/macos/poll#ev-add) | | `userData` | `uint64` | the word to report | **Returns**: the kevent [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/Poll.rux#L83){rel=""nofollow""} ## `FcntlInt` ```rux pub func FcntlInt( fd: FileDescriptor, command: int32, argument: int64 ) -> int64 ``` Performs `command` on a descriptor with an integer argument. **See also**: <https://keith.github.io/xcode-man-pages/fcntl.2.html>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/Poll.rux#L102){rel=""nofollow""} **Parameters** | Name | Type | Description | | ---------- | ---------------- | -------------------------------------------------------------------------------------------------------------------------------------- | | `fd` | `FileDescriptor` | the descriptor | | `command` | `int32` | such as [`F_GETFL`](https://rux-lang.dev/docs/api/macos/poll#f-getfl) or [`F_SETFL`](https://rux-lang.dev/docs/api/macos/poll#f-setfl) | | `argument` | `int64` | the command's argument, or zero | **Returns**: the command's result, or a negative error number ## `Kqueue` ```rux pub func Kqueue() -> int64 ``` Opens a kqueue. **See also**: <https://keith.github.io/xcode-man-pages/kqueue.2.html>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/Poll.rux#L110){rel=""nofollow""} **Returns**: the kqueue's descriptor, or a negative error number ## `KeventCall` ```rux pub func KeventCall( queue: FileDescriptor, changes: *Kevent, changeCount: int32, events: *var Kevent, eventCount: int32, timeout: *Timespec ) -> int64 ``` Applies `changeCount` changes, then waits until an event is ready or `timeout` passes, filling `events`. **See also**: <https://keith.github.io/xcode-man-pages/kevent.2.html>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/Poll.rux#L124){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------------- | ---------------- | --------------------------------------------- | | `queue` | `FileDescriptor` | the kqueue | | `changes` | `*Kevent` | the changes to apply, or null | | `changeCount` | `int32` | how many changes there are | | `events` | `*var Kevent` | room for `eventCount` events, or null | | `eventCount` | `int32` | how many events fit | | `timeout` | `*Timespec` | how long to wait, or null to wait without end | **Returns**: how many events were filled, or a negative error number # Sockets Address families, socket types and options, and the calls that open, bind and connect sockets. ## `AF_INET` ```rux pub const AF_INET: int32 = 2; ``` `AF_INET`: the IPv4 address family. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/Socket.rux#L10){rel=""nofollow""} ## `AF_INET6` ```rux pub const AF_INET6: int32 = 30; ``` `AF_INET6`: the IPv6 address family. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/Socket.rux#L15){rel=""nofollow""} ## `SOCK_STREAM` ```rux pub const SOCK_STREAM: int32 = 1; ``` `SOCK_STREAM`: a connected byte stream. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/Socket.rux#L20){rel=""nofollow""} ## `SOCK_DGRAM` ```rux pub const SOCK_DGRAM: int32 = 2; ``` `SOCK_DGRAM`: individual datagrams. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/Socket.rux#L25){rel=""nofollow""} ## `SOL_SOCKET` ```rux pub const SOL_SOCKET: int32 = 0xffff; ``` `SOL_SOCKET`: the level of the options every socket has. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/Socket.rux#L30){rel=""nofollow""} ## `SO_REUSEADDR` ```rux pub const SO_REUSEADDR: int32 = 4; ``` `SO_REUSEADDR`: let a listening address be bound again while old connections to it wind down. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/Socket.rux#L35){rel=""nofollow""} ## `SO_RCVTIMEO` ```rux pub const SO_RCVTIMEO: int32 = 0x1006; ``` `SO_RCVTIMEO`: how long a receive waits. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/Socket.rux#L40){rel=""nofollow""} ## `SO_SNDTIMEO` ```rux pub const SO_SNDTIMEO: int32 = 0x1005; ``` `SO_SNDTIMEO`: how long a send waits. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/Socket.rux#L45){rel=""nofollow""} ## `IPPROTO_TCP` ```rux pub const IPPROTO_TCP: int32 = 6; ``` `IPPROTO_TCP`: the level of TCP's options. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/Socket.rux#L50){rel=""nofollow""} ## `TCP_NODELAY` ```rux pub const TCP_NODELAY: int32 = 1; ``` `TCP_NODELAY`: send small writes at once rather than gathering them. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/Socket.rux#L55){rel=""nofollow""} ## `IPPROTO_IPV6` ```rux pub const IPPROTO_IPV6: int32 = 41; ``` `IPPROTO_IPV6`: the level of IPv6's options. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/Socket.rux#L60){rel=""nofollow""} ## `IPV6_V6ONLY` ```rux pub const IPV6_V6ONLY: int32 = 27; ``` `IPV6_V6ONLY`: accept only IPv6 on an IPv6 socket. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/Socket.rux#L65){rel=""nofollow""} ## `SO_NOSIGPIPE` ```rux pub const SO_NOSIGPIPE: int32 = 0x1022; ``` `SO_NOSIGPIPE`: report a closed peer as an error rather than with `SIGPIPE`. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/Socket.rux#L70){rel=""nofollow""} ## `Socket` ```rux pub func Socket( domain: int32, kind: int32, protocol: int32 ) -> int64 ``` Opens a socket. **See also**: <https://keith.github.io/xcode-man-pages/socket.2.html>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/Socket.rux#L94){rel=""nofollow""} **Parameters** | Name | Type | Description | | ---------- | ------- | ------------------------------------------------------------------------------------------------------------------------------ | | `domain` | `int32` | the address family, such as [`AF_INET`](https://rux-lang.dev/docs/api/macos/socket#af-inet) | | `kind` | `int32` | the socket type, such as [`SOCK_STREAM`](https://rux-lang.dev/docs/api/macos/socket#sock-stream), combined with `SOCK_CLOEXEC` | | `protocol` | `int32` | the protocol, or zero for the family's default | **Returns**: the new descriptor, or a negative error number ## `Connect` ```rux pub func Connect( fd: FileDescriptor, address: *opaque, length: uint32 ) -> int64 ``` Connects a socket to `address`, waiting for a stream connection to be made. **See also**: <https://keith.github.io/xcode-man-pages/connect.2.html>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/Socket.rux#L105){rel=""nofollow""} **Parameters** | Name | Type | Description | | --------- | ---------------- | --------------------------- | | `fd` | `FileDescriptor` | the socket | | `address` | `*opaque` | the address, a `sockaddr` | | `length` | `uint32` | the address's size in bytes | **Returns**: zero, or a negative error number ## `Bind` ```rux pub func Bind( fd: FileDescriptor, address: *opaque, length: uint32 ) -> int64 ``` Gives a socket its local address. **See also**: <https://keith.github.io/xcode-man-pages/bind.2.html>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/Socket.rux#L116){rel=""nofollow""} **Parameters** | Name | Type | Description | | --------- | ---------------- | --------------------------- | | `fd` | `FileDescriptor` | the socket | | `address` | `*opaque` | the address, a `sockaddr` | | `length` | `uint32` | the address's size in bytes | **Returns**: zero, or a negative error number ## `Listen` ```rux pub func Listen(fd: FileDescriptor, backlog: int32) -> int64 ``` Makes a bound stream socket accept connections. **See also**: <https://keith.github.io/xcode-man-pages/listen.2.html>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/Socket.rux#L126){rel=""nofollow""} **Parameters** | Name | Type | Description | | --------- | ---------------- | -------------------------------------------- | | `fd` | `FileDescriptor` | the socket | | `backlog` | `int32` | how many connections may wait to be accepted | **Returns**: zero, or a negative error number ## `Accept4` ```rux pub func Accept4( fd: FileDescriptor, address: *var opaque, length: *var uint32, flags: int32 ) -> int64 ``` Accepts a waiting connection as a new socket. **See also**: <https://keith.github.io/xcode-man-pages/accept.2.html>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/Socket.rux#L138){rel=""nofollow""} **Parameters** | Name | Type | Description | | --------- | ---------------- | --------------------------------------------------------------------------------------------- | | `fd` | `FileDescriptor` | the listening socket | | `address` | `*var opaque` | receives the peer's address, or null | | `length` | `*var uint32` | the address buffer's size, then the address's, or null | | `flags` | `int32` | ignored: macOS has no `accept4`, and the new socket is closed on exec by the caller if wanted | **Returns**: the new descriptor, or a negative error number ## `SendTo` ```rux pub func SendTo( fd: FileDescriptor, buffer: *opaque, count: uint, flags: int32, address: *opaque, length: uint32 ) -> int64 ``` Sends bytes on a socket, to `address` when it is not connected. **See also**: <https://keith.github.io/xcode-man-pages/sendto.2.html>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/Socket.rux#L152){rel=""nofollow""} **Parameters** | Name | Type | Description | | --------- | ---------------- | ----------------------------------------------- | | `fd` | `FileDescriptor` | the socket | | `buffer` | `*opaque` | the bytes | | `count` | `uint` | how many | | `flags` | `int32` | flags such as `MSG_NOSIGNAL` | | `address` | `*opaque` | the destination, or null for a connected socket | | `length` | `uint32` | the destination's size | **Returns**: the bytes sent, or a negative error number ## `ReceiveFrom` ```rux pub func ReceiveFrom( fd: FileDescriptor, buffer: *var opaque, count: uint, flags: int32, address: *var opaque, length: *var uint32 ) -> int64 ``` Receives bytes from a socket, and where they came from. **See also**: <https://keith.github.io/xcode-man-pages/recvfrom.2.html>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/Socket.rux#L166){rel=""nofollow""} **Parameters** | Name | Type | Description | | --------- | ---------------- | ------------------------------------------------------ | | `fd` | `FileDescriptor` | the socket | | `buffer` | `*var opaque` | receives the bytes | | `count` | `uint` | how many fit | | `flags` | `int32` | flags, or zero | | `address` | `*var opaque` | receives the sender's address, or null | | `length` | `*var uint32` | the address buffer's size, then the address's, or null | **Returns**: the bytes received, zero once a stream's peer closed it, or a negative error number ## `Shutdown` ```rux pub func Shutdown(fd: FileDescriptor, how: int32) -> int64 ``` Ends one or both directions of a connection. **See also**: <https://keith.github.io/xcode-man-pages/shutdown.2.html>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/Socket.rux#L176){rel=""nofollow""} **Parameters** | Name | Type | Description | | ----- | ---------------- | ----------------------------------- | | `fd` | `FileDescriptor` | the socket | | `how` | `int32` | `SHUT_RD`, `SHUT_WR` or `SHUT_RDWR` | **Returns**: zero, or a negative error number ## `SetSocketOption` ```rux pub func SetSocketOption( fd: FileDescriptor, level: int32, name: int32, value: *opaque, length: uint32 ) -> int64 ``` Sets a socket option. **See also**: <https://keith.github.io/xcode-man-pages/setsockopt.2.html>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/Socket.rux#L189){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | ---------------- | ------------------------------------------------------------------------------------------------- | | `fd` | `FileDescriptor` | the socket | | `level` | `int32` | the option's level, such as [`SOL_SOCKET`](https://rux-lang.dev/docs/api/macos/socket#sol-socket) | | `name` | `int32` | the option | | `value` | `*opaque` | the option's value | | `length` | `uint32` | the value's size in bytes | **Returns**: zero, or a negative error number ## `GetSocketName` ```rux pub func GetSocketName( fd: FileDescriptor, address: *var opaque, length: *var uint32 ) -> int64 ``` Reads a socket's local address. **See also**: <https://keith.github.io/xcode-man-pages/getsockname.2.html>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/Socket.rux#L200){rel=""nofollow""} **Parameters** | Name | Type | Description | | --------- | ---------------- | ------------------------------------- | | `fd` | `FileDescriptor` | the socket | | `address` | `*var opaque` | receives the address | | `length` | `*var uint32` | the buffer's size, then the address's | **Returns**: zero, or a negative error number ## `GetPeerName` ```rux pub func GetPeerName( fd: FileDescriptor, address: *var opaque, length: *var uint32 ) -> int64 ``` Reads the address of a connected socket's peer. **See also**: <https://keith.github.io/xcode-man-pages/getpeername.2.html>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/Socket.rux#L211){rel=""nofollow""} **Parameters** | Name | Type | Description | | --------- | ---------------- | ------------------------------------- | | `fd` | `FileDescriptor` | the socket | | `address` | `*var opaque` | receives the address | | `length` | `*var uint32` | the buffer's size, then the address's | **Returns**: zero, or a negative error number # Address waits Waiting on a word and waking its waiters through [`__ulock_wait`](https://rux-lang.dev/docs/api/macos/ulock#ulock-wait) and [`__ulock_wake`](https://rux-lang.dev/docs/api/macos/ulock#ulock-wake). ## `UL_COMPARE_AND_WAIT` ```rux pub const UL_COMPARE_AND_WAIT: uint32 = 1; ``` `UL_COMPARE_AND_WAIT`: wait on a 32-bit word that holds the expected value. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/Ulock.rux#L11){rel=""nofollow""} ## `ULF_WAKE_ALL` ```rux pub const ULF_WAKE_ALL: uint32 = 0x100; ``` `ULF_WAKE_ALL`: wake every thread waiting on the word rather than one. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/Ulock.rux#L16){rel=""nofollow""} ## `ULF_NO_ERRNO` ```rux pub const ULF_NO_ERRNO: uint32 = 0x01000000; ``` `ULF_NO_ERRNO`: report failure as a negative error number rather than through errno. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/Ulock.rux#L21){rel=""nofollow""} ## `__ulock_wait` ```rux pub extern func __ulock_wait( operation: uint32, address: *opaque, value: uint64, timeout: uint32 ) -> int32 ``` Sleeps while `*address` equals `value`, until a wake, a signal or the timeout. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/Ulock.rux#L32){rel=""nofollow""} **Parameters** | Name | Type | Description | | ----------- | --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `operation` | `uint32` | [`UL_COMPARE_AND_WAIT`](https://rux-lang.dev/docs/api/macos/ulock#ul-compare-and-wait), combined with [`ULF_NO_ERRNO`](https://rux-lang.dev/docs/api/macos/ulock#ulf-no-errno) | | `address` | `*opaque` | the word to wait on, four-byte aligned | | `value` | `uint64` | the value the caller last saw there | | `timeout` | `uint32` | microseconds to wait at most, or zero to wait without a limit | **Returns**: the number of waiters left, or a failure: [`EINTR`](https://rux-lang.dev/docs/api/macos/errors#eintr), [`ETIMEDOUT`](https://rux-lang.dev/docs/api/macos/errors#etimedout), or [`EFAULT`](https://rux-lang.dev/docs/api/macos/errors#efault) when the word moved ## `__ulock_wake` ```rux pub extern func __ulock_wake( operation: uint32, address: *opaque, wakeValue: uint64 ) -> int32 ``` Wakes a thread, or all of them with [`ULF_WAKE_ALL`](https://rux-lang.dev/docs/api/macos/ulock#ulf-wake-all), sleeping on `address`. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/macOS/Src/Ulock.rux#L40){rel=""nofollow""} **Parameters** | Name | Type | Description | | ----------- | --------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `operation` | `uint32` | [`UL_COMPARE_AND_WAIT`](https://rux-lang.dev/docs/api/macos/ulock#ul-compare-and-wait), combined with [`ULF_WAKE_ALL`](https://rux-lang.dev/docs/api/macos/ulock#ulf-wake-all) and [`ULF_NO_ERRNO`](https://rux-lang.dev/docs/api/macos/ulock#ulf-no-errno) | | `address` | `*opaque` | the word they wait on | | `wakeValue` | `uint64` | zero | **Returns**: zero, or a failure: [`ENOENT`](https://rux-lang.dev/docs/api/macos/errors#enoent) when nothing was waiting # Windows Windows platform bindings. ## Installation Add `Windows` to the `[Dependencies]` table of your package's `Rux.toml`: ```toml [Dependencies] Windows = { Namespace = "Rux", Version = "0.1.0" } ``` Standard packages are declared by hand: the registry does not serve them, so `rux add Rux/Windows` cannot add them. ## Guide Windows platform bindings: Win32 declarations linked straight against `Kernel32.dll`, with no C runtime in between. ### What it provides | Module | Covers | | ---------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `Types` | [`Handle`](https://rux-lang.dev/docs/api/windows/types#handle), [`ModuleHandle`](https://rux-lang.dev/docs/api/windows/types#module-handle), [`Bool`](https://rux-lang.dev/docs/api/windows/types#bool), [`Dword`](https://rux-lang.dev/docs/api/windows/types#dword), [`WideChar`](https://rux-lang.dev/docs/api/windows/types#wide-char), [`NtStatus`](https://rux-lang.dev/docs/api/windows/types#nt-status), [`FileTime`](https://rux-lang.dev/docs/api/windows/file-time), [`SystemTime`](https://rux-lang.dev/docs/api/windows/system-time), and [`InvalidHandleValue`](https://rux-lang.dev/docs/api/windows/types#invalid-handle-value) | | `Constants` | the code pages and the file-creation dispositions | | `Kernel` | the Kernel32 entry points, including the `A` forms kept for compatibility | | `File` | the Unicode `W` file, directory and console entry points, with the access, share and move flags | | `Memory` | [`VirtualAlloc`](https://rux-lang.dev/docs/api/windows/memory#virtual-alloc), [`VirtualFree`](https://rux-lang.dev/docs/api/windows/memory#virtual-free), [`VirtualProtect`](https://rux-lang.dev/docs/api/windows/memory#virtual-protect), [`VirtualLock`](https://rux-lang.dev/docs/api/windows/memory#virtual-lock), and the state and protection flags | | `Entropy` | `BCryptGenRandom` behind a [`GetRandom`](https://rux-lang.dev/docs/api/windows/get-random) that either fills the buffer or fails | | `Clock` | [`QueryPerformanceCounter`](https://rux-lang.dev/docs/api/windows/clock#query-performance-counter), [`QueryPerformanceFrequency`](https://rux-lang.dev/docs/api/windows/clock#query-performance-frequency), the precise wall clock, and the epoch conversion | | `Shell` | [`CommandLineToArgvW`](https://rux-lang.dev/docs/api/windows/process#command-line-to-argv-w), which splits the command line into arguments the way the C runtime does | | `Synch` | [`WaitOnAddress`](https://rux-lang.dev/docs/api/windows/synch#wait-on-address), [`WakeByAddressSingle`](https://rux-lang.dev/docs/api/windows/synch#wake-by-address-single) and [`WakeByAddressAll`](https://rux-lang.dev/docs/api/windows/synch#wake-by-address-all), from the synchronization API set | | `ProcessControl` | [`CreateProcessW`](https://rux-lang.dev/docs/api/windows/process-control#create-process-w) and its structures, [`CreatePipe`](https://rux-lang.dev/docs/api/windows/process-control#create-pipe), handle inheritance, [`GetExitCodeProcess`](https://rux-lang.dev/docs/api/windows/process-control#get-exit-code-process), [`TerminateProcess`](https://rux-lang.dev/docs/api/windows/process-control#terminate-process) and [`SetEnvironmentVariableW`](https://rux-lang.dev/docs/api/windows/process-control#set-environment-variable-w) | | `TimeZone` | [`GetTimeZoneInformation`](https://rux-lang.dev/docs/api/windows/time-zone#get-time-zone-information), [`TimeZoneInformation`](https://rux-lang.dev/docs/api/windows/time-zone#time-zone-information) and [`TimeZoneRuleDate`](https://rux-lang.dev/docs/api/windows/time-zone#time-zone-rule-date) | | `Winsock` | [`WSAStartup`](https://rux-lang.dev/docs/api/windows/winsock#wsa-startup), [`WSAGetLastError`](https://rux-lang.dev/docs/api/windows/winsock#wsa-get-last-error), the Ws2\_32 socket calls, [`ioctlsocket`](https://rux-lang.dev/docs/api/windows/winsock#ioctlsocket) with [`FIONBIO`](https://rux-lang.dev/docs/api/windows/winsock#fionbio), [`WSAPoll`](https://rux-lang.dev/docs/api/windows/winsock#wsa-poll) with [`WsaPollFd`](https://rux-lang.dev/docs/api/windows/winsock#wsa-poll-fd) and the `POLL*` flags, [`getaddrinfo`](https://rux-lang.dev/docs/api/windows/winsock#getaddrinfo) and [`freeaddrinfo`](https://rux-lang.dev/docs/api/windows/winsock#freeaddrinfo), [`WsaData`](https://rux-lang.dev/docs/api/windows/winsock#wsa-data), [`AddressInfo`](https://rux-lang.dev/docs/api/windows/winsock#address-info) and the socket constants | The module names describe where each declaration comes from; they are not part of an import path. **Prefer the `W` entry points.** The `A` forms convert through the process code page, which cannot express every name a file system can hold and differs between machines — so a path that works on one system fails on another for reasons the program cannot see. A path is text a user or a file system chose, not text the program chose. The `A` forms stay declared because existing callers use them, and each is now marked. Two failure sentinels, and they are not the same. A handle-returning call reports [`InvalidHandleValue`](https://rux-lang.dev/docs/api/windows/types#invalid-handle-value), which is `-1` cast to a pointer; a memory-returning call reports null; and [`GetFileAttributesW`](https://rux-lang.dev/docs/api/windows/file-system#get-file-attributes-w) reports a third value again, [`INVALID_FILE_ATTRIBUTES`](https://rux-lang.dev/docs/api/windows/file-system#invalid-file-attributes). Testing a handle against null, or an allocation against [`InvalidHandleValue`](https://rux-lang.dev/docs/api/windows/types#invalid-handle-value), reads a failure as a success. `BCryptGenRandom` reports none of them — it returns an `NTSTATUS`, which [`GetLastError`](https://rux-lang.dev/docs/api/windows/errors#get-last-error) knows nothing about, so [`GetRandom`](https://rux-lang.dev/docs/api/windows/get-random)'s boolean is the only thing a caller may read after it. A successful draw leaves whatever Win32 code was already standing exactly where it was. **`CloseHandle(InvalidHandleValue)` succeeds.** `(HANDLE)-1` is the current process's pseudo-handle, not an invalid one, and closing a pseudo-handle is a no-op that reports success — where closing null or an arbitrary number fails with [`ERROR_INVALID_HANDLE`](https://rux-lang.dev/docs/api/windows/errors#error-invalid-handle). A cleanup path that closes the sentinel defensively is therefore not caught by its return value; it silently does nothing. This is asserted in `Tests/Packages/Windows/Failures`, because it is not what the name suggests. Windows separates reserving address space from committing storage to it, which no other supported system does. A reserved page may not be touched; committing is what makes it usable. [`MEM_RELEASE`](https://rux-lang.dev/docs/api/windows/memory#mem-release) requires a size of zero and the exact base address the reservation returned. Releasing a reservation twice **fails**, with [`ERROR_INVALID_ADDRESS`](https://rux-lang.dev/docs/api/windows/errors#error-invalid-address), where POSIX's `munmap` on an already-unmapped range succeeds — so code that treats a double release as harmless is portable in one direction only. ### What is tested `Tests/Packages/Windows/Failures` covers the three sentinels, the Win32 code each kind of failure leaves behind, the different codes the virtual allocator and the heap give for the same impossible size, the release rules, and the `NTSTATUS` domain staying clear of [`GetLastError`](https://rux-lang.dev/docs/api/windows/errors#get-last-error). `Tests/Packages/Windows/Platform` covers the reserve-then-commit split, protection, the entropy source and the clocks; `Tests/Packages/Windows/Constants` covers the enumerated values. `Tests/Unit/PlatformBindingContractTests.cpp` additionally checks, on any host, that the sentinels differ, that every `ERROR_` constant holds its published value, and that no two of them share a number. Unlike the three POSIX packages, all of this runs where it is developed, so every number in it was read out of a running program rather than out of documentation. ### Values and pointers Win32 records such as [`FileTime`](https://rux-lang.dev/docs/api/windows/file-time) and [`SystemTime`](https://rux-lang.dev/docs/api/windows/system-time) are structural values and copy by value. Package-owned inspection helpers borrow them, so call `FileTimeTicks(stamp)` with the value itself. Imported Win32 declarations retain raw pointers for handles, optional arguments, buffers, and OS-owned addresses because null and sentinel values are part of those contracts. A raw handle or pointer never transfers ownership automatically; close or release it with the matching Win32 function. ### Platform Windows only. Guard use behind a compile-time check, so a build for another target never resolves these declarations: ```rux import Core::{ #target }; when #target.os == .Windows { import Windows::{ GetStdHandle, StdOutputHandle, WriteConsoleA }; } ``` ## Index ### Types | Name | Summary | | ------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | [`CodePage`](https://rux-lang.dev/docs/api/windows/code-page) | The `CodePage` values exposed by this package. | | [`CreationDisposition`](https://rux-lang.dev/docs/api/windows/creation-disposition) | The `CreationDisposition` values exposed by this package. | | [`SecurityAttributes`](https://rux-lang.dev/docs/api/windows/process-control#security-attributes) | The `SECURITY_ATTRIBUTES` a pipe or file is created with: here only whether its handle is inheritable. | | [`StartupInfo`](https://rux-lang.dev/docs/api/windows/process-control#startup-info) | The `STARTUPINFOW` a new process is started with; this package fills in its standard handles. | | [`ProcessInformation`](https://rux-lang.dev/docs/api/windows/process-control#process-information) | The `PROCESS_INFORMATION` [`CreateProcessW`](https://rux-lang.dev/docs/api/windows/process-control#create-process-w) fills in: the new process and its first thread. | | [`TimeZoneRuleDate`](https://rux-lang.dev/docs/api/windows/time-zone#time-zone-rule-date) | When a time-zone rule takes effect, in the layout of `SYSTEMTIME` but read as a rule, not a date. | | [`TimeZoneInformation`](https://rux-lang.dev/docs/api/windows/time-zone#time-zone-information) | Win32's `TIME_ZONE_INFORMATION`: a zone's offsets and when its daylight time starts and ends. | | [`Handle`](https://rux-lang.dev/docs/api/windows/types#handle) | An opaque kernel object reference. | | [`ModuleHandle`](https://rux-lang.dev/docs/api/windows/types#module-handle) | A module reference, as `LoadLibraryW` returns one. | | [`Bool`](https://rux-lang.dev/docs/api/windows/types#bool) | Win32's `BOOL`: a 32-bit integer where zero is false and anything else is true. | | [`Dword`](https://rux-lang.dev/docs/api/windows/types#dword) | Win32's `DWORD`: a 32-bit unsigned integer. | | [`WideChar`](https://rux-lang.dev/docs/api/windows/types#wide-char) | A UTF-16 code unit, which is what every `*W` entry point takes. | | [`NtStatus`](https://rux-lang.dev/docs/api/windows/types#nt-status) | An `NTSTATUS`: the status code the native and cryptographic interfaces report with. | | [`FileTime`](https://rux-lang.dev/docs/api/windows/file-time) | Win32's `FILETIME`: a count of 100-nanosecond ticks since the start of 1601, UTC. | | [`SystemTime`](https://rux-lang.dev/docs/api/windows/system-time) | Win32's `SYSTEMTIME`: a broken-down date and time, one field per component. | | [`Win32FindDataA`](https://rux-lang.dev/docs/api/windows/win32-find-data-a) | Win32's `WIN32_FIND_DATAA`: one directory entry, as [`FindFirstFileA`](https://rux-lang.dev/docs/api/windows/file-system#find-first-file-a) and [`FindNextFileA`](https://rux-lang.dev/docs/api/windows/file-system#find-next-file-a) fill it. | | [`SystemInfo`](https://rux-lang.dev/docs/api/windows/system-info) | What [`GetSystemInfo`](https://rux-lang.dev/docs/api/windows/system-info#get-system-info) reports about the machine. | | [`WsaData`](https://rux-lang.dev/docs/api/windows/winsock#wsa-data) | Room for a `WSADATA`, which [`WSAStartup`](https://rux-lang.dev/docs/api/windows/winsock#wsa-startup) fills and nothing here reads. | | [`AddressInfo`](https://rux-lang.dev/docs/api/windows/winsock#address-info) | Winsock's `addrinfo`: one result of [`getaddrinfo`](https://rux-lang.dev/docs/api/windows/winsock#getaddrinfo), linked to the next. | | [`WsaPollFd`](https://rux-lang.dev/docs/api/windows/winsock#wsa-poll-fd) | `WSAPOLLFD`: one socket [`WSAPoll`](https://rux-lang.dev/docs/api/windows/winsock#wsa-poll) watches, the events wanted, and the events it reports. | ### Functions | Name | Summary | | -------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------- | | [`QueryPerformanceCounter`](https://rux-lang.dev/docs/api/windows/clock#query-performance-counter) | Reads the monotonic performance counter. | | [`QueryPerformanceFrequency`](https://rux-lang.dev/docs/api/windows/clock#query-performance-frequency) | Reads how many performance-counter ticks make one second. | | [`GetSystemTimePreciseAsFileTime`](https://rux-lang.dev/docs/api/windows/clock#get-system-time-precise-as-file-time) | Reads the current wall-clock time at the highest resolution the system offers. | | [`GetSystemTimeAsFileTime`](https://rux-lang.dev/docs/api/windows/clock#get-system-time-as-file-time) | Reads the current wall-clock time at the system tick's resolution. | | [`FileTimeTicks`](https://rux-lang.dev/docs/api/windows/file-time#file-time-ticks) | The whole 64-bit value a [`FileTime`](https://rux-lang.dev/docs/api/windows/file-time) splits across two fields. | | [`GetRandom`](https://rux-lang.dev/docs/api/windows/get-random) | Fills `length` bytes of `buffer` with unpredictable bytes. | | [`CreateFileW`](https://rux-lang.dev/docs/api/windows/files#create-file-w) | Creates or opens a file or device, taking a UTF-16 path. | | [`FindFirstFileW`](https://rux-lang.dev/docs/api/windows/file-system#find-first-file-w) | Begins a directory enumeration matching a UTF-16 pattern. | | [`FindNextFileW`](https://rux-lang.dev/docs/api/windows/file-system#find-next-file-w) | Continues a directory enumeration; fails with ERROR\_NO\_MORE\_FILES at its end. | | [`CreateHardLinkW`](https://rux-lang.dev/docs/api/windows/file-system#create-hard-link-w) | Creates a hard link: a second name for an existing file's contents. | | [`CreateSymbolicLinkW`](https://rux-lang.dev/docs/api/windows/file-system#create-symbolic-link-w) | Creates a symbolic link; returns a BOOLEAN, so only the low byte is meaningful. | | [`GetFileInformationByHandle`](https://rux-lang.dev/docs/api/windows/files#get-file-information-by-handle) | Fills a BY\_HANDLE\_FILE\_INFORMATION record for an open handle. | | [`SetFileTime`](https://rux-lang.dev/docs/api/windows/files#set-file-time) | Sets the creation, last-access and last-write times of an open handle. | | [`GetFinalPathNameByHandleW`](https://rux-lang.dev/docs/api/windows/files#get-final-path-name-by-handle-w) | Writes the final, resolved path of an open handle: symbolic links followed, short names expanded, case as the filesystem stores it. | | [`GetTempPathW`](https://rux-lang.dev/docs/api/windows/file-system#get-temp-path-w) | Writes the path of the directory designated for temporary files. | | [`DeleteFileW`](https://rux-lang.dev/docs/api/windows/file-system#delete-file-w) | Deletes a file, taking a UTF-16 path. | | [`MoveFileExW`](https://rux-lang.dev/docs/api/windows/file-system#move-file-ex-w) | Moves or renames a file or directory, taking UTF-16 paths. | | [`CopyFileW`](https://rux-lang.dev/docs/api/windows/file-system#copy-file-w) | Copies a file, taking UTF-16 paths. | | [`CreateDirectoryW`](https://rux-lang.dev/docs/api/windows/file-system#create-directory-w) | Creates a directory, taking a UTF-16 path. | | [`RemoveDirectoryW`](https://rux-lang.dev/docs/api/windows/file-system#remove-directory-w) | Removes an empty directory, taking a UTF-16 path. | | [`GetFileAttributesW`](https://rux-lang.dev/docs/api/windows/file-system#get-file-attributes-w) | Reads a file's attributes, taking a UTF-16 path. | | [`SetFileAttributesW`](https://rux-lang.dev/docs/api/windows/file-system#set-file-attributes-w) | Sets a file's attributes, taking a UTF-16 path. | | [`GetCurrentDirectoryW`](https://rux-lang.dev/docs/api/windows/file-system#get-current-directory-w) | Reads the current directory into a UTF-16 buffer. | | [`SetCurrentDirectoryW`](https://rux-lang.dev/docs/api/windows/file-system#set-current-directory-w) | Sets the current directory, taking a UTF-16 path. | | [`FlushFileBuffers`](https://rux-lang.dev/docs/api/windows/files#flush-file-buffers) | Flushes a file handle's writes to the device. | | [`SetEndOfFile`](https://rux-lang.dev/docs/api/windows/files#set-end-of-file) | Sets the size of a file to the handle's current position. | | [`WriteConsoleW`](https://rux-lang.dev/docs/api/windows/console#write-console-w) | Writes a character string to a console screen buffer beginning at the current cursor location. | | [`ReadConsoleW`](https://rux-lang.dev/docs/api/windows/console#read-console-w) | Reads UTF-16 from a console input buffer. | | [`AllocConsole`](https://rux-lang.dev/docs/api/windows/console#alloc-console) | Allocates a new console for the calling process. | | [`Beep`](https://rux-lang.dev/docs/api/windows/console#beep) | Generates simple tones on the speaker. | | [`CloseHandle`](https://rux-lang.dev/docs/api/windows/files#close-handle) | Closes an open object handle. | | [`CopyFileA`](https://rux-lang.dev/docs/api/windows/file-system#copy-file-a) | Copies an existing file to a new file. | | [`CreateDirectoryA`](https://rux-lang.dev/docs/api/windows/file-system#create-directory-a) | Creates a new directory. | | [`CreateFileA`](https://rux-lang.dev/docs/api/windows/files#create-file-a) | Creates or opens a file or I/O device. | | [`DeleteFileA`](https://rux-lang.dev/docs/api/windows/file-system#delete-file-a) | Deletes an existing file. | | [`ExitProcess`](https://rux-lang.dev/docs/api/windows/process#exit-process) | Ends the calling process and all its threads. | | [`FindClose`](https://rux-lang.dev/docs/api/windows/file-system#find-close) | Closes a file search handle opened by the FindFirstFile, FindFirstFileEx, FindFirstFileNameW,. | | [`FindFirstFileA`](https://rux-lang.dev/docs/api/windows/file-system#find-first-file-a) | Searches a directory for a file or subdirectory with a name that matches a specific name (or partial name if wildcards are used). | | [`FindNextFileA`](https://rux-lang.dev/docs/api/windows/file-system#find-next-file-a) | Continues a file search from a previous call to the FindFirstFile, FindFirstFileEx, or FindFirstFileTransacted functions. | | [`FreeLibrary`](https://rux-lang.dev/docs/api/windows/process#free-library) | Frees the loaded dynamic-link library (DLL) module and, if necessary, decrements its reference count. | | [`GetConsoleMode`](https://rux-lang.dev/docs/api/windows/console#get-console-mode) | Retrieves the current input or output mode of a console screen buffer. | | [`GetCommandLineW`](https://rux-lang.dev/docs/api/windows/process#get-command-line-w) | Retrieves the command line the process was started with, as one string. | | [`GetModuleFileNameW`](https://rux-lang.dev/docs/api/windows/process#get-module-file-name-w) | Retrieves the full path of the file a module was loaded from; a null module is the process's executable. | | [`GetCurrentDirectoryA`](https://rux-lang.dev/docs/api/windows/file-system#get-current-directory-a) | Retrieves the current directory. | | [`GetEnvironmentStringsW`](https://rux-lang.dev/docs/api/windows/process#get-environment-strings-w) | Copies the calling process's environment block. | | [`GetCurrentProcessId`](https://rux-lang.dev/docs/api/windows/process#get-current-process-id) | Retrieves the process identifier of the calling process. | | [`GetActiveProcessorCount`](https://rux-lang.dev/docs/api/windows/process#get-active-processor-count) | Retrieves the number of active processors in a processor group, or in all of them. | | [`GetCurrentThreadId`](https://rux-lang.dev/docs/api/windows/process#get-current-thread-id) | Retrieves the thread identifier of the calling thread. | | [`GetFileAttributesA`](https://rux-lang.dev/docs/api/windows/file-system#get-file-attributes-a) | Retrieves file attributes. | | [`GetFileSizeEx`](https://rux-lang.dev/docs/api/windows/files#get-file-size-ex) | Retrieves the size of the specified file. | | [`GetSystemInfo`](https://rux-lang.dev/docs/api/windows/system-info#get-system-info) | Reads what the system reports about the machine, including its page size. | | [`GetLastError`](https://rux-lang.dev/docs/api/windows/errors#get-last-error) | Retrieves the calling thread's last-error code value. | | [`GetLocalTime`](https://rux-lang.dev/docs/api/windows/clock#get-local-time) | Retrieves the current local date and time. | | [`GetProcAddress`](https://rux-lang.dev/docs/api/windows/process#get-proc-address) | Retrieves the address of an exported symbol. | | [`GetProcessHeap`](https://rux-lang.dev/docs/api/windows/memory#get-process-heap) | Retrieves a handle to the default heap of the calling process. | | [`GetStdHandle`](https://rux-lang.dev/docs/api/windows/console#get-std-handle) | Retrieves a handle to the specified standard device (standard input, standard output, or standard error). | | [`GetSystemTime`](https://rux-lang.dev/docs/api/windows/clock#get-system-time) | Retrieves the current system date and time in Coordinated Universal Time (UTC) format. | | [`GetTickCount64`](https://rux-lang.dev/docs/api/windows/clock#get-tick-count64) | Retrieves the number of milliseconds that have elapsed since the system was started. | | [`HeapAlloc`](https://rux-lang.dev/docs/api/windows/memory#heap-alloc) | Allocates a block of memory from a heap. | | [`HeapFree`](https://rux-lang.dev/docs/api/windows/memory#heap-free) | Frees a memory block allocated from a heap by the HeapAlloc or HeapReAlloc function. | | [`HeapReAlloc`](https://rux-lang.dev/docs/api/windows/memory#heap-re-alloc) | Reallocates a block of memory from a heap. | | [`LoadLibraryA`](https://rux-lang.dev/docs/api/windows/process#load-library-a) | Loads a DLL into the calling process. | | [`MoveFileA`](https://rux-lang.dev/docs/api/windows/file-system#move-file-a) | Moves an existing file or directory. | | [`MultiByteToWideChar`](https://rux-lang.dev/docs/api/windows/text#multi-byte-to-wide-char) | Maps a character string to a UTF-16 wide character string. | | [`ReadConsoleA`](https://rux-lang.dev/docs/api/windows/console#read-console-a) | Reads characters from a console input buffer. | | [`ReadFile`](https://rux-lang.dev/docs/api/windows/files#read-file) | Reads data from the specified file or input/output (I/O) device. | | [`RemoveDirectoryA`](https://rux-lang.dev/docs/api/windows/file-system#remove-directory-a) | Deletes an existing empty directory. | | [`RtlCompareMemory`](https://rux-lang.dev/docs/api/windows/memory#rtl-compare-memory) | Compares two blocks of memory and returns the number of bytes that match until the first difference. | | [`RtlCopyMemory`](https://rux-lang.dev/docs/api/windows/memory#rtl-copy-memory) | Copies a block of memory from one location to another. | | [`RtlFillMemory`](https://rux-lang.dev/docs/api/windows/memory#rtl-fill-memory) | Fills a block of memory with the specified fill value. | | [`RtlZeroMemory`](https://rux-lang.dev/docs/api/windows/memory#rtl-zero-memory) | Fills a block of memory with zeros, given a pointer to the block and the length in bytes. | | [`SetCurrentDirectoryA`](https://rux-lang.dev/docs/api/windows/file-system#set-current-directory-a) | Changes the current directory. | | [`SetFileAttributesA`](https://rux-lang.dev/docs/api/windows/file-system#set-file-attributes-a) | Sets file attributes. | | [`SetFilePointerEx`](https://rux-lang.dev/docs/api/windows/files#set-file-pointer-ex) | Moves the file pointer of the specified file. | | [`CreateThread`](https://rux-lang.dev/docs/api/windows/process#create-thread) | Creates a thread to execute within the virtual address space of the calling process. | | [`Sleep`](https://rux-lang.dev/docs/api/windows/process#sleep) | Suspends the execution of the current thread until the time-out interval elapses. | | [`SwitchToThread`](https://rux-lang.dev/docs/api/windows/process#switch-to-thread) | Causes the calling thread to yield execution to another thread that is ready to run. | | [`WaitForSingleObject`](https://rux-lang.dev/docs/api/windows/process#wait-for-single-object) | Waits until the specified object is in the signaled state or the time-out interval elapses. | | [`WideCharToMultiByte`](https://rux-lang.dev/docs/api/windows/text#wide-char-to-multi-byte) | Converts UTF-16 text to another code page. | | [`WriteConsoleA`](https://rux-lang.dev/docs/api/windows/console#write-console-a) | Writes a character string to a console screen buffer beginning at the current cursor location. | | [`WriteFile`](https://rux-lang.dev/docs/api/windows/files#write-file) | Writes data to the specified file or input/output (I/O) device. | | [`VirtualAlloc`](https://rux-lang.dev/docs/api/windows/memory#virtual-alloc) | Reserves, commits, or changes the state of a region of pages. | | [`VirtualFree`](https://rux-lang.dev/docs/api/windows/memory#virtual-free) | Releases, decommits, or both, a region of pages. | | [`VirtualProtect`](https://rux-lang.dev/docs/api/windows/memory#virtual-protect) | Changes the protection on a region of committed pages. | | [`VirtualLock`](https://rux-lang.dev/docs/api/windows/memory#virtual-lock) | Locks a region into physical memory so it is never written to the page file. | | [`VirtualUnlock`](https://rux-lang.dev/docs/api/windows/memory#virtual-unlock) | Unlocks a region previously locked into physical memory. | | [`CreateProcessW`](https://rux-lang.dev/docs/api/windows/process-control#create-process-w) | Starts a program as a new process. | | [`GetExitCodeProcess`](https://rux-lang.dev/docs/api/windows/process-control#get-exit-code-process) | Reads a process's exit code, or `STILL_ACTIVE` while it runs. | | [`TerminateProcess`](https://rux-lang.dev/docs/api/windows/process-control#terminate-process) | Ends a process and all its threads. | | [`CreatePipe`](https://rux-lang.dev/docs/api/windows/process-control#create-pipe) | Creates an anonymous pipe. | | [`SetHandleInformation`](https://rux-lang.dev/docs/api/windows/process-control#set-handle-information) | Changes a handle's flags, such as whether it is inherited. | | [`DuplicateHandle`](https://rux-lang.dev/docs/api/windows/process-control#duplicate-handle) | Duplicates a handle, here into the same process with different inheritance. | | [`GetCurrentProcess`](https://rux-lang.dev/docs/api/windows/process-control#get-current-process) | Returns a pseudo-handle for the calling process, which needs no closing. | | [`SetEnvironmentVariableW`](https://rux-lang.dev/docs/api/windows/process-control#set-environment-variable-w) | Sets or removes an environment variable of the calling process. | | [`CommandLineToArgvW`](https://rux-lang.dev/docs/api/windows/process#command-line-to-argv-w) | Splits a command line into arguments the way the C runtime does. | | [`WaitOnAddress`](https://rux-lang.dev/docs/api/windows/synch#wait-on-address) | Waits for the value at an address to change. | | [`WakeByAddressSingle`](https://rux-lang.dev/docs/api/windows/synch#wake-by-address-single) | Wakes one thread waiting on an address. | | [`WakeByAddressAll`](https://rux-lang.dev/docs/api/windows/synch#wake-by-address-all) | Wakes every thread waiting on an address. | | [`GetTimeZoneInformation`](https://rux-lang.dev/docs/api/windows/time-zone#get-time-zone-information) | Reads the system's current time zone. | | [`WSAStartup`](https://rux-lang.dev/docs/api/windows/winsock#wsa-startup) | Starts Winsock for this process. | | [`WSAGetLastError`](https://rux-lang.dev/docs/api/windows/winsock#wsa-get-last-error) | The calling thread's last Winsock error. | | [`socket`](https://rux-lang.dev/docs/api/windows/winsock#socket) | Opens a socket. | | [`connect`](https://rux-lang.dev/docs/api/windows/winsock#connect) | Connects a socket to `address`. | | [`bind`](https://rux-lang.dev/docs/api/windows/winsock#bind) | Gives a socket its local address. | | [`listen`](https://rux-lang.dev/docs/api/windows/winsock#listen) | Makes a bound stream socket accept connections. | | [`accept`](https://rux-lang.dev/docs/api/windows/winsock#accept) | Accepts a waiting connection. | | [`sendto`](https://rux-lang.dev/docs/api/windows/winsock#sendto) | Sends bytes on a socket, to `address` when it is not connected. | | [`recvfrom`](https://rux-lang.dev/docs/api/windows/winsock#recvfrom) | Receives bytes from a socket, and where they came from. | | [`closesocket`](https://rux-lang.dev/docs/api/windows/winsock#closesocket) | Closes a socket. | | [`shutdown`](https://rux-lang.dev/docs/api/windows/winsock#shutdown) | Ends one or both directions of a connection. | | [`setsockopt`](https://rux-lang.dev/docs/api/windows/winsock#setsockopt) | Sets a socket option. | | [`getsockname`](https://rux-lang.dev/docs/api/windows/winsock#getsockname) | Reads a socket's local address. | | [`getpeername`](https://rux-lang.dev/docs/api/windows/winsock#getpeername) | Reads the address of a connected socket's peer. | | [`getaddrinfo`](https://rux-lang.dev/docs/api/windows/winsock#getaddrinfo) | Looks up the addresses of a host and service. | | [`freeaddrinfo`](https://rux-lang.dev/docs/api/windows/winsock#freeaddrinfo) | Frees the results of [`getaddrinfo`](https://rux-lang.dev/docs/api/windows/winsock#getaddrinfo). | | [`ioctlsocket`](https://rux-lang.dev/docs/api/windows/winsock#ioctlsocket) | Sets a socket's mode, such as non-blocking with [`FIONBIO`](https://rux-lang.dev/docs/api/windows/winsock#fionbio). | | [`WSAPoll`](https://rux-lang.dev/docs/api/windows/winsock#wsa-poll) | Waits until one of `count` sockets is ready or `timeout` milliseconds pass, filling each one's `returned`. | ### Constants | Name | Summary | | ------------------------------------------------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | [`FileTimeTicksPerSecond`](https://rux-lang.dev/docs/api/windows/file-time#file-time-ticks-per-second) | How many [`FileTime`](https://rux-lang.dev/docs/api/windows/file-time) ticks make one second. | | [`FileTimeToUnixEpochSeconds`](https://rux-lang.dev/docs/api/windows/file-time#file-time-to-unix-epoch-seconds) | Seconds between the [`FileTime`](https://rux-lang.dev/docs/api/windows/file-time) epoch of 1601 and the Unix epoch of 1970. | | [`ALL_PROCESSOR_GROUPS`](https://rux-lang.dev/docs/api/windows/process#all-processor-groups) | `ALL_PROCESSOR_GROUPS`: asks [`GetActiveProcessorCount`](https://rux-lang.dev/docs/api/windows/process#get-active-processor-count) about every processor group at once. | | [`STACK_SIZE_PARAM_IS_A_RESERVATION`](https://rux-lang.dev/docs/api/windows/process#stack-size-param-is-a-reservation) | `STACK_SIZE_PARAM_IS_A_RESERVATION`: [`CreateThread`](https://rux-lang.dev/docs/api/windows/process#create-thread) takes its stack size as the space to reserve rather than to commit, which is what a stack size usually means. | | [`INFINITE`](https://rux-lang.dev/docs/api/windows/process#infinite) | `INFINITE`: a wait with no time-out. | | [`BCRYPT_USE_SYSTEM_PREFERRED_RNG`](https://rux-lang.dev/docs/api/windows/get-random#bcrypt-use-system-preferred-rng) | `BCRYPT_USE_SYSTEM_PREFERRED_RNG`: draw from the system's preferred generator rather than a named algorithm. | | [`STATUS_SUCCESS`](https://rux-lang.dev/docs/api/windows/get-random#status-success) | `STATUS_SUCCESS`: the status an [`NtStatus`](https://rux-lang.dev/docs/api/windows/types#nt-status)-reporting call gives when it worked. | | [`ERROR_SUCCESS`](https://rux-lang.dev/docs/api/windows/errors#error-success) | `ERROR_SUCCESS`: the operation succeeded, which is the value [`GetLastError`](https://rux-lang.dev/docs/api/windows/errors#get-last-error) reports when nothing has failed. | | [`ERROR_FILE_NOT_FOUND`](https://rux-lang.dev/docs/api/windows/errors#error-file-not-found) | `ERROR_FILE_NOT_FOUND`: the named file does not exist. | | [`ERROR_PATH_NOT_FOUND`](https://rux-lang.dev/docs/api/windows/errors#error-path-not-found) | `ERROR_PATH_NOT_FOUND`: a directory along the path does not exist. | | [`ERROR_ACCESS_DENIED`](https://rux-lang.dev/docs/api/windows/errors#error-access-denied) | `ERROR_ACCESS_DENIED`: the caller does not have the rights the operation needs. | | [`ERROR_INVALID_HANDLE`](https://rux-lang.dev/docs/api/windows/errors#error-invalid-handle) | `ERROR_INVALID_HANDLE`: the handle is not one this operation can use. | | [`ERROR_NOT_ENOUGH_MEMORY`](https://rux-lang.dev/docs/api/windows/errors#error-not-enough-memory) | `ERROR_NOT_ENOUGH_MEMORY`: not enough storage to complete the operation. | | [`ERROR_OUTOFMEMORY`](https://rux-lang.dev/docs/api/windows/errors#error-out-of-memory) | `ERROR_OUTOFMEMORY`: not enough storage to complete the operation. | | [`ERROR_NOT_SUPPORTED`](https://rux-lang.dev/docs/api/windows/errors#error-not-supported) | `ERROR_NOT_SUPPORTED`: the operation is not supported on this object or this system. | | [`ERROR_FILE_EXISTS`](https://rux-lang.dev/docs/api/windows/errors#error-file-exists) | `ERROR_FILE_EXISTS`: the file already exists, and the call was told not to replace it. | | [`ERROR_INVALID_PARAMETER`](https://rux-lang.dev/docs/api/windows/errors#error-invalid-parameter) | `ERROR_INVALID_PARAMETER`: an argument is not valid. | | [`ERROR_DISK_FULL`](https://rux-lang.dev/docs/api/windows/errors#error-disk-full) | `ERROR_DISK_FULL`: the volume has no room left. | | [`ERROR_PRIVILEGE_NOT_HELD`](https://rux-lang.dev/docs/api/windows/errors#error-privilege-not-held) | `ERROR_PRIVILEGE_NOT_HELD`: the account lacks a privilege the operation requires. | | [`ERROR_NO_MORE_FILES`](https://rux-lang.dev/docs/api/windows/errors#error-no-more-files) | `ERROR_NO_MORE_FILES`: a directory enumeration has handed over its last entry. | | [`ERROR_ALREADY_EXISTS`](https://rux-lang.dev/docs/api/windows/errors#error-already-exists) | `ERROR_ALREADY_EXISTS`: the object already exists. | | [`ERROR_INVALID_ADDRESS`](https://rux-lang.dev/docs/api/windows/errors#error-invalid-address) | `ERROR_INVALID_ADDRESS`: the address is not one the operation can use. | | [`ERROR_COMMITMENT_LIMIT`](https://rux-lang.dev/docs/api/windows/errors#error-commitment-limit) | `ERROR_COMMITMENT_LIMIT`: the system's commit limit is reached, so nothing more can be backed. | | [`GENERIC_READ`](https://rux-lang.dev/docs/api/windows/files#generic-read) | `GENERIC_READ`: the handle may read. | | [`GENERIC_WRITE`](https://rux-lang.dev/docs/api/windows/files#generic-write) | `GENERIC_WRITE`: the handle may write. | | [`FILE_APPEND_DATA`](https://rux-lang.dev/docs/api/windows/files#file-append-data) | `FILE_APPEND_DATA`: the handle may append, and only append. | | [`FILE_SHARE_READ`](https://rux-lang.dev/docs/api/windows/files#file-share-read) | `FILE_SHARE_READ`: other openers may read while this handle is open. | | [`FILE_SHARE_WRITE`](https://rux-lang.dev/docs/api/windows/files#file-share-write) | `FILE_SHARE_WRITE`: other openers may write while this handle is open. | | [`FILE_SHARE_DELETE`](https://rux-lang.dev/docs/api/windows/files#file-share-delete) | `FILE_SHARE_DELETE`: the file may be renamed or deleted while this handle is open. | | [`FILE_ATTRIBUTE_NORMAL`](https://rux-lang.dev/docs/api/windows/files#file-attribute-normal) | `FILE_ATTRIBUTE_NORMAL`: no attributes beyond being an ordinary file. | | [`FILE_ATTRIBUTE_READONLY`](https://rux-lang.dev/docs/api/windows/file-system#file-attribute-readonly) | `FILE_ATTRIBUTE_READONLY`: the file may not be opened for writing or deleted. | | [`FILE_ATTRIBUTE_DIRECTORY`](https://rux-lang.dev/docs/api/windows/file-system#file-attribute-directory) | `FILE_ATTRIBUTE_DIRECTORY`: the name is a directory. | | [`FILE_ATTRIBUTE_REPARSE_POINT`](https://rux-lang.dev/docs/api/windows/file-system#file-attribute-reparse-point) | `FILE_ATTRIBUTE_REPARSE_POINT`: the name carries a reparse point, which is what a symbolic link is. | | [`INVALID_FILE_ATTRIBUTES`](https://rux-lang.dev/docs/api/windows/file-system#invalid-file-attributes) | `INVALID_FILE_ATTRIBUTES`: what [`GetFileAttributesW`](https://rux-lang.dev/docs/api/windows/file-system#get-file-attributes-w) returns when it could not answer. | | [`FILE_FLAG_BACKUP_SEMANTICS`](https://rux-lang.dev/docs/api/windows/files#file-flag-backup-semantics) | `FILE_FLAG_BACKUP_SEMANTICS`: let [`CreateFileW`](https://rux-lang.dev/docs/api/windows/files#create-file-w) open a directory. | | [`FILE_FLAG_OPEN_REPARSE_POINT`](https://rux-lang.dev/docs/api/windows/files#file-flag-open-reparse-point) | `FILE_FLAG_OPEN_REPARSE_POINT`: open the symbolic link itself rather than what it points at. | | [`FILE_FLAG_DELETE_ON_CLOSE`](https://rux-lang.dev/docs/api/windows/files#file-flag-delete-on-close) | `FILE_FLAG_DELETE_ON_CLOSE`: remove the file when its last handle closes. | | [`FILE_FLAG_WRITE_THROUGH`](https://rux-lang.dev/docs/api/windows/files#file-flag-write-through) | `FILE_FLAG_WRITE_THROUGH`: writes reach the device before the call returns. | | [`SYMBOLIC_LINK_FLAG_DIRECTORY`](https://rux-lang.dev/docs/api/windows/file-system#symbolic-link-flag-directory) | `SYMBOLIC_LINK_FLAG_DIRECTORY`: the link's target is a directory. | | [`SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE`](https://rux-lang.dev/docs/api/windows/file-system#symbolic-link-flag-allow-unprivileged-create) | `SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE`: let a Developer Mode machine create the link without the privilege older systems demand. | | [`MOVEFILE_REPLACE_EXISTING`](https://rux-lang.dev/docs/api/windows/file-system#move-file-replace-existing) | `MOVEFILE_REPLACE_EXISTING`: let the move overwrite an existing target. | | [`MOVEFILE_WRITE_THROUGH`](https://rux-lang.dev/docs/api/windows/file-system#move-file-write-through) | `MOVEFILE_WRITE_THROUGH`: do not return until the move has reached the disk. | | [`MEM_COMMIT`](https://rux-lang.dev/docs/api/windows/memory#mem-commit) | `MEM_COMMIT`: back the range with storage. | | [`MEM_RESERVE`](https://rux-lang.dev/docs/api/windows/memory#mem-reserve) | `MEM_RESERVE`: take the address space without backing it. | | [`MEM_RESET`](https://rux-lang.dev/docs/api/windows/memory#mem-reset) | `MEM_RESET`: the contents are no longer of interest and need not be written to the page file. | | [`MEM_RELEASE`](https://rux-lang.dev/docs/api/windows/memory#mem-release) | `MEM_RELEASE`: give back the whole reservation, which [`VirtualFree`](https://rux-lang.dev/docs/api/windows/memory#virtual-free) requires a size of zero for. | | [`MEM_DECOMMIT`](https://rux-lang.dev/docs/api/windows/memory#mem-decommit) | `MEM_DECOMMIT`: take back the storage but keep the reservation. | | [`PAGE_NOACCESS`](https://rux-lang.dev/docs/api/windows/memory#page-no-access) | `PAGE_NOACCESS`: the pages may not be touched at all. | | [`PAGE_READONLY`](https://rux-lang.dev/docs/api/windows/memory#page-read-only) | `PAGE_READONLY`: the pages may be read. | | [`PAGE_READWRITE`](https://rux-lang.dev/docs/api/windows/memory#page-read-write) | `PAGE_READWRITE`: the pages may be read and written. | | [`PAGE_EXECUTE`](https://rux-lang.dev/docs/api/windows/memory#page-execute) | `PAGE_EXECUTE`: the pages may be executed. | | [`PAGE_EXECUTE_READ`](https://rux-lang.dev/docs/api/windows/memory#page-execute-read) | `PAGE_EXECUTE_READ`: the pages may be executed and read. | | [`PAGE_EXECUTE_READWRITE`](https://rux-lang.dev/docs/api/windows/memory#page-execute-read-write) | `PAGE_EXECUTE_READWRITE`: the pages may be executed, read and written. | | [`PAGE_GUARD`](https://rux-lang.dev/docs/api/windows/memory#page-guard) | `PAGE_GUARD`: the next touch raises a one-shot guard exception and then clears the flag. | | [`STARTF_USESTDHANDLES`](https://rux-lang.dev/docs/api/windows/process-control#startf-usestdhandles) | `STARTF_USESTDHANDLES`: the standard handles in [`StartupInfo`](https://rux-lang.dev/docs/api/windows/process-control#startup-info) are the child's. | | [`CREATE_UNICODE_ENVIRONMENT`](https://rux-lang.dev/docs/api/windows/process-control#create-unicode-environment) | `CREATE_UNICODE_ENVIRONMENT`: the environment block is UTF-16. | | [`HANDLE_FLAG_INHERIT`](https://rux-lang.dev/docs/api/windows/process-control#handle-flag-inherit) | `HANDLE_FLAG_INHERIT`: the handle is inherited by child processes. | | [`DUPLICATE_SAME_ACCESS`](https://rux-lang.dev/docs/api/windows/process-control#duplicate-same-access) | `DUPLICATE_SAME_ACCESS`: a duplicated handle has the access of the original. | | [`WAIT_TIMEOUT`](https://rux-lang.dev/docs/api/windows/process-control#wait-timeout) | `WAIT_TIMEOUT`: a wait ended because its time ran out. | | [`ERROR_BROKEN_PIPE`](https://rux-lang.dev/docs/api/windows/process-control#error-broken-pipe) | `ERROR_BROKEN_PIPE`: the other end of the pipe was closed. | | [`InvalidHandleValue`](https://rux-lang.dev/docs/api/windows/types#invalid-handle-value) | The value a handle-returning call reports failure with. | | [`StdInputHandle`](https://rux-lang.dev/docs/api/windows/console#std-input-handle) | The public `StdInputHandle` value. | | [`StdOutputHandle`](https://rux-lang.dev/docs/api/windows/console#std-output-handle) | The public `StdOutputHandle` value. | | [`StdErrorHandle`](https://rux-lang.dev/docs/api/windows/console#std-error-handle) | The public `StdErrorHandle` value. | | [`AF_INET`](https://rux-lang.dev/docs/api/windows/winsock#af-inet) | `AF_INET`: the IPv4 address family. | | [`AF_INET6`](https://rux-lang.dev/docs/api/windows/winsock#af-inet6) | `AF_INET6`: the IPv6 address family. | | [`SOCK_STREAM`](https://rux-lang.dev/docs/api/windows/winsock#sock-stream) | `SOCK_STREAM`: a connected byte stream. | | [`SOCK_DGRAM`](https://rux-lang.dev/docs/api/windows/winsock#sock-dgram) | `SOCK_DGRAM`: individual datagrams. | | [`SOL_SOCKET`](https://rux-lang.dev/docs/api/windows/winsock#sol-socket) | `SOL_SOCKET`: the level of the options every socket has. | | [`SO_RCVTIMEO`](https://rux-lang.dev/docs/api/windows/winsock#so-rcvtimeo) | `SO_RCVTIMEO`: how long a receive waits, in milliseconds. | | [`SO_SNDTIMEO`](https://rux-lang.dev/docs/api/windows/winsock#so-sndtimeo) | `SO_SNDTIMEO`: how long a send waits, in milliseconds. | | [`IPPROTO_TCP`](https://rux-lang.dev/docs/api/windows/winsock#ipproto-tcp) | `IPPROTO_TCP`: the level of TCP's options. | | [`TCP_NODELAY`](https://rux-lang.dev/docs/api/windows/winsock#tcp-nodelay) | `TCP_NODELAY`: send small writes at once rather than gathering them. | | [`IPPROTO_IPV6`](https://rux-lang.dev/docs/api/windows/winsock#ipproto-ipv6) | `IPPROTO_IPV6`: the level of IPv6's options. | | [`IPV6_V6ONLY`](https://rux-lang.dev/docs/api/windows/winsock#ipv6-v6only) | `IPV6_V6ONLY`: accept only IPv6 on an IPv6 socket. | | [`INVALID_SOCKET`](https://rux-lang.dev/docs/api/windows/winsock#invalid-socket) | `INVALID_SOCKET`: what a call that makes a socket returns on failure. | | [`FIONBIO`](https://rux-lang.dev/docs/api/windows/winsock#fionbio) | `FIONBIO`: the [`ioctlsocket`](https://rux-lang.dev/docs/api/windows/winsock#ioctlsocket) command that turns a socket's non-blocking mode on or off. | | [`POLLRDNORM`](https://rux-lang.dev/docs/api/windows/winsock#pollrdnorm) | `POLLRDNORM`: [`WSAPoll`](https://rux-lang.dev/docs/api/windows/winsock#wsa-poll) reports a socket with data to read, or a connection to accept. | | [`POLLWRNORM`](https://rux-lang.dev/docs/api/windows/winsock#pollwrnorm) | `POLLWRNORM`: [`WSAPoll`](https://rux-lang.dev/docs/api/windows/winsock#wsa-poll) reports a socket a write would not wait on. | | [`POLLERR`](https://rux-lang.dev/docs/api/windows/winsock#pollerr) | `POLLERR`: the socket has an error pending; always reported. | | [`POLLHUP`](https://rux-lang.dev/docs/api/windows/winsock#pollhup) | `POLLHUP`: the connection was closed; always reported. | | [`POLLNVAL`](https://rux-lang.dev/docs/api/windows/winsock#pollnval) | `POLLNVAL`: the socket is not valid; always reported. | # CodePage The `CodePage` values exposed by this package. ```rux pub enum CodePage: uint32 { IbmEbcdicUsCanada = 37, OemUnitedStates = 437, IbmEbcdicInternational = 500, OemArabic = 708, OemArabicAsmo720 = 720, OemGreek = 737, OemBaltic = 775, OemWesternEuropean = 850, OemCentralEuropean = 852, OemCyrillicRussian = 855, OemTurkish = 857, OemWesternEuropeanEuro = 858, OemPortuguese = 860, OemIcelandic = 861, OemHebrew = 862, OemFrenchCanadian = 863, OemArabic864 = 864, OemNordic = 865, OemCyrillicDos = 866, OemModernGreek = 869, IbmEbcdicMultilingualLatin2 = 870, Windows874 = 874, IbmEbcdicGreekModern = 875, ShiftJis = 932, Gb2312 = 936, KsC5601 = 949, Big5 = 950, IbmEbcdicLatinOpen = 1047, IbmEbcdicUsCanadaEuro = 1140, IbmEbcdicGermanyEuro = 1141, IbmEbcdicDenmarkNorwayEuro = 1142, IbmEbcdicFinlandSwedenEuro = 1143, IbmEbcdicItalyEuro = 1144, IbmEbcdicSpainEuro = 1145, IbmEbcdicUkEuro = 1146, IbmEbcdicFranceEuro = 1147, IbmEbcdicInternationalEuro = 1148, IbmEbcdicIcelandicEuro = 1149, Utf16Le = 1200, Utf16Be = 1201, Windows1250 = 1250, Windows1251 = 1251, Windows1252 = 1252, Windows1253 = 1253, Windows1254 = 1254, Windows1255 = 1255, Windows1256 = 1256, Windows1257 = 1257, Windows1258 = 1258, Johab = 1361, MacRoman = 10000, MacJapanese = 10001, MacChineseTraditional = 10002, MacKorean = 10003, MacArabic = 10004, MacHebrew = 10005, MacGreek = 10006, MacCyrillic = 10007, MacChineseSimplified = 10008, MacRomanian = 10010, MacUkrainian = 10017, MacThai = 10021, MacCentralEuropean = 10029, MacIcelandic = 10079, MacTurkish = 10081, MacCroatian = 10082, Utf32Le = 12000, Utf32Be = 12001, CnsTraditionalChinese = 20000, TcaTaiwan = 20001, EtenTraditionalChinese = 20002, Ibm5550Taiwan = 20003, TeleTextTaiwan = 20004, WangTaiwan = 20005, Ia5 = 20105, Ia5German = 20106, Ia5Swedish = 20107, Ia5Norwegian = 20108, UsAscii = 20127, T61 = 20261, Iso6937 = 20269, IbmEbcdicGermany = 20273, IbmEbcdicDenmarkNorway = 20277, IbmEbcdicFinlandSweden = 20278, IbmEbcdicItaly = 20280, IbmEbcdicLatinAmericaSpain = 20284, IbmEbcdicUnitedKingdom = 20285, IbmEbcdicJapaneseKatakana = 20290, IbmEbcdicFrance = 20297, IbmEbcdicArabic = 20420, IbmEbcdicGreek = 20423, IbmEbcdicHebrew = 20424, IbmEbcdicKoreanExtended = 20833, IbmEbcdicThai = 20838, Koi8R = 20866, IbmEbcdicIcelandic = 20871, IbmEbcdicCyrillicRussian = 20880, IbmEbcdicTurkish = 20905, IbmEbcdicLatinOpenEuro = 20924, EucJpJis = 20932, SimplifiedChineseGb2312 = 20936, KoreanWansung = 20949, IbmEbcdicCyrillicSerbianBulgarian = 21025, Koi8U = 21866, Iso8859Part1 = 28591, Iso8859Part2 = 28592, Iso8859Part3 = 28593, Iso8859Part4 = 28594, Iso8859Part5 = 28595, Iso8859Part6 = 28596, Iso8859Part7 = 28597, Iso8859Part8 = 28598, Iso8859Part9 = 28599, Iso8859Part13 = 28603, Iso8859Part15 = 28605, Europa3 = 29001, Iso8859Part8Logical = 38598, Iso2022Jp = 50220, Iso2022JpKana = 50221, Iso2022JpKanaSoSi = 50222, Iso2022Kr = 50225, Iso2022SimplifiedChinese = 50227, EucJp = 51932, EucCn = 51936, EucKr = 51949, HzGb2312 = 52936, Gb18030 = 54936, IsciiDevanagari = 57002, IsciiBangla = 57003, IsciiTamil = 57004, IsciiTelugu = 57005, IsciiAssamese = 57006, IsciiOdia = 57007, IsciiKannada = 57008, IsciiMalayalam = 57009, IsciiGujarati = 57010, IsciiPunjabi = 57011, Utf7 = 65000, Utf8 = 65001 } ``` ## Cases | Name | Value | Description | | ----------------------------------- | ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `IbmEbcdicUsCanada` | `37` | `37`: EBCDIC US and Canada. | | `OemUnitedStates` | `437` | `437`: The original IBM PC character set, US English. | | `IbmEbcdicInternational` | `500` | `500`: EBCDIC international, Latin-1 repertoire. | | `OemArabic` | `708` | `708`: Arabic, ASMO 708. | | `OemArabicAsmo720` | `720` | `720`: Arabic, DOS transparent ASMO. | | `OemGreek` | `737` | `737`: Greek, DOS 437G. | | `OemBaltic` | `775` | `775`: Baltic, DOS. | | `OemWesternEuropean` | `850` | `850`: Western European, DOS multilingual Latin-1. | | `OemCentralEuropean` | `852` | `852`: Central European, DOS Slavic Latin-2. | | `OemCyrillicRussian` | `855` | `855`: Cyrillic, DOS; not the Russian page, which is 866. | | `OemTurkish` | `857` | `857`: Turkish, DOS. | | `OemWesternEuropeanEuro` | `858` | `858`: Western European DOS multilingual with the euro sign in place of the dotless i. | | `OemPortuguese` | `860` | `860`: Portuguese, DOS. | | `OemIcelandic` | `861` | `861`: Icelandic, DOS. | | `OemHebrew` | `862` | `862`: Hebrew, DOS. | | `OemFrenchCanadian` | `863` | `863`: French Canadian, DOS. | | `OemArabic864` | `864` | `864`: Arabic, DOS. | | `OemNordic` | `865` | `865`: Nordic, DOS. | | `OemCyrillicDos` | `866` | `866`: Cyrillic Russian, DOS; the page Russian MS-DOS actually used. | | `OemModernGreek` | `869` | `869`: Modern Greek, DOS. | | `IbmEbcdicMultilingualLatin2` | `870` | `870`: EBCDIC multilingual, Latin-2 repertoire. | | `Windows874` | `874` | `874`: Thai, Windows. | | `IbmEbcdicGreekModern` | `875` | `875`: EBCDIC modern Greek. | | `ShiftJis` | `932` | `932`: Japanese, Shift-JIS. | | `Gb2312` | `936` | `936`: Simplified Chinese, GBK; a superset of GB2312 despite the name. | | `KsC5601` | `949` | `949`: Korean, Unified Hangul Code; a superset of KS C 5601. | | `Big5` | `950` | `950`: Traditional Chinese, Big5. | | `IbmEbcdicLatinOpen` | `1047` | `1047`: EBCDIC Latin-1 open systems. | | `IbmEbcdicUsCanadaEuro` | `1140` | `1140`: EBCDIC US and Canada with the euro sign. | | `IbmEbcdicGermanyEuro` | `1141` | `1141`: EBCDIC Germany with the euro sign. | | `IbmEbcdicDenmarkNorwayEuro` | `1142` | `1142`: EBCDIC Denmark and Norway with the euro sign. | | `IbmEbcdicFinlandSwedenEuro` | `1143` | `1143`: EBCDIC Finland and Sweden with the euro sign. | | `IbmEbcdicItalyEuro` | `1144` | `1144`: EBCDIC Italy with the euro sign. | | `IbmEbcdicSpainEuro` | `1145` | `1145`: EBCDIC Latin America and Spain with the euro sign. | | `IbmEbcdicUkEuro` | `1146` | `1146`: EBCDIC United Kingdom with the euro sign. | | `IbmEbcdicFranceEuro` | `1147` | `1147`: EBCDIC France with the euro sign. | | `IbmEbcdicInternationalEuro` | `1148` | `1148`: EBCDIC international with the euro sign. | | `IbmEbcdicIcelandicEuro` | `1149` | `1149`: EBCDIC Icelandic with the euro sign. | | `Utf16Le` | `1200` | `1200`: UTF-16, little-endian. An identifier only: the conversion calls refuse it, since their output is already UTF-16. | | `Utf16Be` | `1201` | `1201`: UTF-16, big-endian. An identifier only, refused by the conversion calls for the same reason as 1200. | | `Windows1250` | `1250` | `1250`: Central European, Windows. | | `Windows1251` | `1251` | `1251`: Cyrillic, Windows. | | `Windows1252` | `1252` | `1252`: Western European, Windows; the page Latin-1 text is usually mislabelled as. | | `Windows1253` | `1253` | `1253`: Greek, Windows. | | `Windows1254` | `1254` | `1254`: Turkish, Windows. | | `Windows1255` | `1255` | `1255`: Hebrew, Windows. | | `Windows1256` | `1256` | `1256`: Arabic, Windows. | | `Windows1257` | `1257` | `1257`: Baltic, Windows. | | `Windows1258` | `1258` | `1258`: Vietnamese, Windows. | | `Johab` | `1361` | `1361`: Korean, Johab. | | `MacRoman` | `10000` | `10000`: Western European, Macintosh Roman. | | `MacJapanese` | `10001` | `10001`: Japanese, Macintosh. | | `MacChineseTraditional` | `10002` | `10002`: Traditional Chinese, Macintosh. | | `MacKorean` | `10003` | `10003`: Korean, Macintosh. | | `MacArabic` | `10004` | `10004`: Arabic, Macintosh. | | `MacHebrew` | `10005` | `10005`: Hebrew, Macintosh. | | `MacGreek` | `10006` | `10006`: Greek, Macintosh. | | `MacCyrillic` | `10007` | `10007`: Cyrillic, Macintosh. | | `MacChineseSimplified` | `10008` | `10008`: Simplified Chinese, Macintosh. | | `MacRomanian` | `10010` | `10010`: Romanian, Macintosh. | | `MacUkrainian` | `10017` | `10017`: Ukrainian, Macintosh. | | `MacThai` | `10021` | `10021`: Thai, Macintosh. | | `MacCentralEuropean` | `10029` | `10029`: Central European, Macintosh Latin-2. | | `MacIcelandic` | `10079` | `10079`: Icelandic, Macintosh. | | `MacTurkish` | `10081` | `10081`: Turkish, Macintosh. | | `MacCroatian` | `10082` | `10082`: Croatian, Macintosh. | | `Utf32Le` | `12000` | `12000`: UTF-32, little-endian. An identifier only; the conversion calls do not accept it. | | `Utf32Be` | `12001` | `12001`: UTF-32, big-endian. An identifier only; the conversion calls do not accept it. | | `CnsTraditionalChinese` | `20000` | `20000`: Traditional Chinese, CNS 11643. | | `TcaTaiwan` | `20001` | `20001`: Traditional Chinese, TCA Taiwan. | | `EtenTraditionalChinese` | `20002` | `20002`: Traditional Chinese, Eten. | | `Ibm5550Taiwan` | `20003` | `20003`: Traditional Chinese, IBM 5550 Taiwan. | | `TeleTextTaiwan` | `20004` | `20004`: Traditional Chinese, TeleText Taiwan. | | `WangTaiwan` | `20005` | `20005`: Traditional Chinese, Wang Taiwan. | | `Ia5` | `20105` | `20105`: IA5, the seven-bit international reference version. | | `Ia5German` | `20106` | `20106`: IA5, German national variant. | | `Ia5Swedish` | `20107` | `20107`: IA5, Swedish national variant. | | `Ia5Norwegian` | `20108` | `20108`: IA5, Norwegian national variant. | | `UsAscii` | `20127` | `20127`: US-ASCII, seven bits. | | `T61` | `20261` | `20261`: T.61, the teletex character set. | | `Iso6937` | `20269` | `20269`: ISO 6937, the non-spacing accent set. | | `IbmEbcdicGermany` | `20273` | `20273`: EBCDIC Germany. | | `IbmEbcdicDenmarkNorway` | `20277` | `20277`: EBCDIC Denmark and Norway. | | `IbmEbcdicFinlandSweden` | `20278` | `20278`: EBCDIC Finland and Sweden. | | `IbmEbcdicItaly` | `20280` | `20280`: EBCDIC Italy. | | `IbmEbcdicLatinAmericaSpain` | `20284` | `20284`: EBCDIC Latin America and Spain. | | `IbmEbcdicUnitedKingdom` | `20285` | `20285`: EBCDIC United Kingdom. | | `IbmEbcdicJapaneseKatakana` | `20290` | `20290`: EBCDIC Japanese katakana extended. | | `IbmEbcdicFrance` | `20297` | `20297`: EBCDIC France. | | `IbmEbcdicArabic` | `20420` | `20420`: EBCDIC Arabic. | | `IbmEbcdicGreek` | `20423` | `20423`: EBCDIC Greek. | | `IbmEbcdicHebrew` | `20424` | `20424`: EBCDIC Hebrew. | | `IbmEbcdicKoreanExtended` | `20833` | `20833`: EBCDIC Korean extended. | | `IbmEbcdicThai` | `20838` | `20838`: EBCDIC Thai. | | `Koi8R` | `20866` | `20866`: Cyrillic, KOI8-R; the Russian one. | | `IbmEbcdicIcelandic` | `20871` | `20871`: EBCDIC Icelandic. | | `IbmEbcdicCyrillicRussian` | `20880` | `20880`: EBCDIC Cyrillic Russian. | | `IbmEbcdicTurkish` | `20905` | `20905`: EBCDIC Turkish. | | `IbmEbcdicLatinOpenEuro` | `20924` | `20924`: EBCDIC Latin-1 open systems with the euro sign. | | `EucJpJis` | `20932` | `20932`: Japanese, JIS X 0208-1990 and JIS X 0212-1990. | | `SimplifiedChineseGb2312` | `20936` | `20936`: Simplified Chinese, GB2312 proper rather than the GBK superset at 936. | | `KoreanWansung` | `20949` | `20949`: Korean, Wansung. | | `IbmEbcdicCyrillicSerbianBulgarian` | `21025` | `21025`: EBCDIC Cyrillic Serbian and Bulgarian. | | `Koi8U` | `21866` | `21866`: Cyrillic, KOI8-U; the Ukrainian one. | | `Iso8859Part1` | `28591` | `28591`: ISO 8859-1, Latin-1. Not the same as 1252, which fills the C1 range with printable characters. | | `Iso8859Part2` | `28592` | `28592`: ISO 8859-2, Central European. | | `Iso8859Part3` | `28593` | `28593`: ISO 8859-3, Latin-3. | | `Iso8859Part4` | `28594` | `28594`: ISO 8859-4, Baltic. | | `Iso8859Part5` | `28595` | `28595`: ISO 8859-5, Cyrillic. | | `Iso8859Part6` | `28596` | `28596`: ISO 8859-6, Arabic. | | `Iso8859Part7` | `28597` | `28597`: ISO 8859-7, Greek. | | `Iso8859Part8` | `28598` | `28598`: ISO 8859-8, Hebrew in visual order. | | `Iso8859Part9` | `28599` | `28599`: ISO 8859-9, Turkish Latin-5. | | `Iso8859Part13` | `28603` | `28603`: ISO 8859-13, Estonian. | | `Iso8859Part15` | `28605` | `28605`: ISO 8859-15, Latin-9. | | `Europa3` | `29001` | `29001`: Europa 3. | | `Iso8859Part8Logical` | `38598` | `38598`: ISO 8859-8, Hebrew in logical order. | | `Iso2022Jp` | `50220` | `50220`: ISO 2022 Japanese, no halfwidth katakana. | | `Iso2022JpKana` | `50221` | `50221`: ISO 2022 Japanese, with halfwidth katakana. | | `Iso2022JpKanaSoSi` | `50222` | `50222`: ISO 2022 Japanese, halfwidth katakana reached through shift-out and shift-in. | | `Iso2022Kr` | `50225` | `50225`: ISO 2022 Korean. | | `Iso2022SimplifiedChinese` | `50227` | `50227`: ISO 2022 simplified Chinese. | | `EucJp` | `51932` | `51932`: EUC-JP. | | `EucCn` | `51936` | `51936`: EUC-CN, simplified Chinese. | | `EucKr` | `51949` | `51949`: EUC-KR, Korean. | | `HzGb2312` | `52936` | `52936`: HZ-GB2312, simplified Chinese. | | `Gb18030` | `54936` | `54936`: GB18030, which covers every Unicode scalar value. | | `IsciiDevanagari` | `57002` | `57002`: ISCII Devanagari. | | `IsciiBangla` | `57003` | `57003`: ISCII Bangla. | | `IsciiTamil` | `57004` | `57004`: ISCII Tamil. | | `IsciiTelugu` | `57005` | `57005`: ISCII Telugu. | | `IsciiAssamese` | `57006` | `57006`: ISCII Assamese. | | `IsciiOdia` | `57007` | `57007`: ISCII Odia. | | `IsciiKannada` | `57008` | `57008`: ISCII Kannada. | | `IsciiMalayalam` | `57009` | `57009`: ISCII Malayalam. | | `IsciiGujarati` | `57010` | `57010`: ISCII Gujarati. | | `IsciiPunjabi` | `57011` | `57011`: ISCII Punjabi. | | `Utf7` | `65000` | `65000`: UTF-7. Deprecated and unsafe to accept from anywhere untrusted: one character has more than one encoding, so a filter that inspects the bytes can be walked past. | | `Utf8` | `65001` | `65001`: UTF-8. The one to use for anything new. | # CreationDisposition The `CreationDisposition` values exposed by this package. ```rux pub enum CreationDisposition: uint32 { CreateNew = 1, CreateAlways = 2, OpenExisting = 3, OpenAlways = 4, TruncateExisting = 5 } ``` ## Cases | Name | Value | Description | | ------------------ | ----- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `CreateNew` | `1` | Create the file, and fail with [`ERROR_FILE_EXISTS`](https://rux-lang.dev/docs/api/windows/errors#error-file-exists) if the name is taken. | | `CreateAlways` | `2` | Create the file, truncating whatever is there. Succeeds either way, and reports [`ERROR_ALREADY_EXISTS`](https://rux-lang.dev/docs/api/windows/errors#error-already-exists) through [`GetLastError`](https://rux-lang.dev/docs/api/windows/errors#get-last-error) when it truncated rather than created. | | `OpenExisting` | `3` | Open the file, and fail with [`ERROR_FILE_NOT_FOUND`](https://rux-lang.dev/docs/api/windows/errors#error-file-not-found) if it is not there. | | `OpenAlways` | `4` | Open the file, creating it if it is not there. Reports [`ERROR_ALREADY_EXISTS`](https://rux-lang.dev/docs/api/windows/errors#error-already-exists) when it opened rather than created. | | `TruncateExisting` | `5` | Open the file and truncate it, failing if it is not there. Needs write access. | # FileTime Win32's `FILETIME`: a count of 100-nanosecond ticks since the start of 1601, UTC. ```rux pub struct FileTime { pub lowDateTime: uint32; pub highDateTime: uint32; } ``` Split across two 32-bit halves because the record predates a 64-bit integer being ordinary, and the halves are not aligned as one — [`FileTimeTicks`](https://rux-lang.dev/docs/api/windows/file-time#file-time-ticks) joins them, and reading the pair as a `uint64` is what a caller must not do. The epoch is not the Unix one. [`FileTimeToUnixEpochSeconds`](https://rux-lang.dev/docs/api/windows/file-time#file-time-to-unix-epoch-seconds) is the difference. **See also**: <https://learn.microsoft.com/windows/win32/api/minwinbase/ns-minwinbase-filetime>{rel=""nofollow""} ## Fields | Name | Type | Description | | -------------- | -------- | ----------------------------------- | | `lowDateTime` | `uint32` | The low 32 bits of the tick count. | | `highDateTime` | `uint32` | The high 32 bits of the tick count. | ## Related ### `FileTimeTicksPerSecond` ```rux pub const FileTimeTicksPerSecond: uint64 = 10000000; ``` How many [`FileTime`](https://rux-lang.dev/docs/api/windows/file-time) ticks make one second. A [`FileTime`](https://rux-lang.dev/docs/api/windows/file-time) counts 100-nanosecond intervals, so this is ten million. It is the conversion every wall-clock reading here needs. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Clock.rux#L16){rel=""nofollow""} ### `FileTimeToUnixEpochSeconds` ```rux pub const FileTimeToUnixEpochSeconds: uint64 = 11644473600; ``` Seconds between the [`FileTime`](https://rux-lang.dev/docs/api/windows/file-time) epoch of 1601 and the Unix epoch of 1970. Windows counts from a different year than everything else, and this is what converts between them. The gap includes the leap days of the intervening centuries, which is why it is not a round number. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Clock.rux#L22){rel=""nofollow""} ### `FileTimeTicks` ```rux pub func FileTimeTicks(time: &FileTime) -> uint64 ``` The whole 64-bit value a [`FileTime`](https://rux-lang.dev/docs/api/windows/file-time) splits across two fields. `time` is borrowed and read, so callers pass the value directly. Win32 splits the count into a high and a low word because the structure predates 64-bit alignment guarantees; this puts it back together. Cannot fail. Runs in constant time and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Clock.rux#L66){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------ | ----------- | --------------------- | | `time` | `&FileTime` | the file time to read | **Returns**: its two halves joined into one count of 100-nanosecond ticks since 1601 # SystemInfo What [`GetSystemInfo`](https://rux-lang.dev/docs/api/windows/system-info#get-system-info) reports about the machine. ```rux pub struct SystemInfo { pub pageSize: uint32; // private fields } ``` The two granularities are not the same and the difference matters: `pageSize` is what protection is applied at, while `allocationGranularity` is what a reservation's base address is rounded to, and on every Windows release it is 64 KiB rather than a page. A reservation therefore wastes address space that a page-granular system would not. ## Fields | Name | Type | Description | | ---------- | -------- | ------------------------------------------------------------------ | | `pageSize` | `uint32` | The size of a page, which is what memory protection is applied at. | ## Related ### `GetSystemInfo` ```rux pub extern func GetSystemInfo(info: *var SystemInfo) ``` Reads what the system reports about the machine, including its page size. Cannot fail and reports nothing: the structure is always filled. **See also**: <https://learn.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-getsysteminfo>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Kernel.rux#L231){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------ | ----------------- | ------------------------------- | | `info` | `*var SystemInfo` | receives the system information | # SystemTime Win32's `SYSTEMTIME`: a broken-down date and time, one field per component. ```rux pub struct SystemTime { // private fields } ``` Whether it is UTC or local time is decided by the call that filled it, not by the record — [`GetSystemTime`](https://rux-lang.dev/docs/api/windows/clock#get-system-time) gives one and [`GetLocalTime`](https://rux-lang.dev/docs/api/windows/clock#get-local-time) the other, and nothing here distinguishes them afterwards. The fields are private: `Rux/Time` is the calendar interface, and this exists so a Win32 signature can name the record it takes. **See also**: <https://learn.microsoft.com/windows/win32/api/minwinbase/ns-minwinbase-systemtime>{rel=""nofollow""} # Time zone The system's time zone rules, read through [`GetTimeZoneInformation`](https://rux-lang.dev/docs/api/windows/time-zone#get-time-zone-information). ## `TimeZoneRuleDate` ```rux pub struct TimeZoneRuleDate { pub year: uint16; pub month: uint16; pub dayOfWeek: uint16; pub day: uint16; pub hour: uint16; pub minute: uint16; pub second: uint16; pub milliseconds: uint16; } ``` When a time-zone rule takes effect, in the layout of `SYSTEMTIME` but read as a rule, not a date. A rule with `year` zero recurs every year: in `month`, on the `day`th occurrence of `dayOfWeek` (Sunday is zero), where the fifth occurrence means the last, at `hour`:`minute` local time. A zero `month` means the zone has no daylight time. **See also**: <https://learn.microsoft.com/en-us/windows/win32/api/timezoneapi/ns-timezoneapi-time_zone_information>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/TimeZone.rux#L9){rel=""nofollow""} **Fields** | Name | Type | Description | | -------------- | -------- | ---------------------------------------------------------------------------- | | `year` | `uint16` | The year for a one-time change, or zero for a rule that recurs. | | `month` | `uint16` | The month, 1 through 12, or zero when there is no change. | | `dayOfWeek` | `uint16` | The day of the week, Sunday being zero. | | `day` | `uint16` | Which occurrence of that day in the month, 1 through 5, where 5 is the last. | | `hour` | `uint16` | The hour of the change, in the local time before it. | | `minute` | `uint16` | The minute of the change. | | `second` | `uint16` | The second of the change. | | `milliseconds` | `uint16` | The millisecond of the change. | ## `TimeZoneInformation` ```rux pub struct TimeZoneInformation { pub bias: int32; pub standardName: uint16[N]; pub standardDate: TimeZoneRuleDate; pub standardBias: int32; pub daylightName: uint16[N]; pub daylightDate: TimeZoneRuleDate; pub daylightBias: int32; } ``` Win32's `TIME_ZONE_INFORMATION`: a zone's offsets and when its daylight time starts and ends. Each bias is minutes to add to local time to get UTC, so a zone east of Greenwich has a negative one. **See also**: <https://learn.microsoft.com/en-us/windows/win32/api/timezoneapi/ns-timezoneapi-time_zone_information>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/TimeZone.rux#L32){rel=""nofollow""} **Fields** | Name | Type | Description | | -------------- | ------------------ | ----------------------------------------------------------- | | `bias` | `int32` | The bias of standard time, in minutes. | | `standardName` | `uint16[N]` | The name of standard time, NUL-terminated UTF-16. | | `standardDate` | `TimeZoneRuleDate` | When standard time starts. | | `standardBias` | `int32` | What is added to `bias` during standard time, usually zero. | | `daylightName` | `uint16[N]` | The name of daylight time, NUL-terminated UTF-16. | | `daylightDate` | `TimeZoneRuleDate` | When daylight time starts. | | `daylightBias` | `int32` | What is added to `bias` during daylight time, usually -60. | ## `GetTimeZoneInformation` ```rux pub extern func GetTimeZoneInformation(information: *var TimeZoneInformation) -> uint32 ``` Reads the system's current time zone. **See also**: <https://learn.microsoft.com/en-us/windows/win32/api/timezoneapi/nf-timezoneapi-gettimezoneinformation>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/TimeZone.rux#L56){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------------- | -------------------------- | ----------------- | | `information` | `*var TimeZoneInformation` | receives the zone | **Returns**: which part of the year it is now, or `0xFFFFFFFF` on failure with the reason in [`GetLastError`](https://rux-lang.dev/docs/api/windows/errors#get-last-error) # Types The Win32 scalar and handle types. ## `Handle` ```rux pub type Handle = *var opaque ``` An opaque kernel object reference. Pointer-sized and owned by the kernel. A handle is valid until [`CloseHandle`](https://rux-lang.dev/docs/api/windows/files#close-handle) takes it, after which the number may be reused by the next object opened — so a stale handle does not fail, it addresses something else. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Types.rux#L13){rel=""nofollow""} ## `ModuleHandle` ```rux pub type ModuleHandle = *var opaque ``` A module reference, as `LoadLibraryW` returns one. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Types.rux#L17){rel=""nofollow""} ## `Bool` ```rux pub type Bool = int32 ``` Win32's `BOOL`: a 32-bit integer where zero is false and anything else is true. Not a one-byte boolean, and not `bool`. A call returning one reports failure as zero and success as anything else, which is why comparing against `1` is wrong. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Types.rux#L23){rel=""nofollow""} ## `Dword` ```rux pub type Dword = uint32 ``` Win32's `DWORD`: a 32-bit unsigned integer. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Types.rux#L27){rel=""nofollow""} ## `WideChar` ```rux pub type WideChar = char16 ``` A UTF-16 code unit, which is what every `*W` entry point takes. Not a character: a scalar outside the basic plane occupies two of these. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Types.rux#L32){rel=""nofollow""} ## `NtStatus` ```rux pub type NtStatus = int32 ``` An `NTSTATUS`: the status code the native and cryptographic interfaces report with. Zero and above is success; below zero is failure. This is a different scheme from [`GetLastError`](https://rux-lang.dev/docs/api/windows/errors#get-last-error), and a value of one must never be read as the other. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Types.rux#L38){rel=""nofollow""} ## `InvalidHandleValue` ```rux pub const InvalidHandleValue: uint64 = 0xFFFFFFFFFFFFFFFF; ``` The value a handle-returning call reports failure with. `-1` cast to a pointer, which is not null. [`CreateFileW`](https://rux-lang.dev/docs/api/windows/files#create-file-w) and [`FindFirstFileW`](https://rux-lang.dev/docs/api/windows/file-system#find-first-file-w) report failure this way; a memory-returning call such as [`VirtualAlloc`](https://rux-lang.dev/docs/api/windows/memory#virtual-alloc) reports null instead. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Types.rux#L44){rel=""nofollow""} # Win32FindDataA Win32's `WIN32_FIND_DATAA`: one directory entry, as [`FindFirstFileA`](https://rux-lang.dev/docs/api/windows/file-system#find-first-file-a) and [`FindNextFileA`](https://rux-lang.dev/docs/api/windows/file-system#find-next-file-a) fill it. ```rux pub struct Win32FindDataA { // private fields } ``` The narrow form, whose names come through the process code page and so cannot express every name a file system can hold. `Rux/FileSystem` enumerates through the wide entry points instead; this is here so a caller reaching for the `A` family directly can name the record they take. The fields are private: the layout is Microsoft's and reading it is the enumerating code's business. **See also**: <https://learn.microsoft.com/windows/win32/api/minwinbase/ns-minwinbase-win32_find_dataa>{rel=""nofollow""} # Clocks Performance counters, system time and tick counts. ## `QueryPerformanceCounter` ```rux pub extern func QueryPerformanceCounter(count: *var int64) -> int32 ``` Reads the monotonic performance counter. Writes the current count and returns nonzero. It cannot fail on any system this package supports, and the count is guaranteed not to go backwards — unlike the wall clock, which can. The unit is whatever QueryPerformanceFrequency reports and is not seconds. **See also**: <https://learn.microsoft.com/en-us/windows/win32/api/profileapi/nf-profileapi-queryperformancecounter>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Clock.rux#L34){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------- | ------------ | ------------------------------------ | | `count` | `*var int64` | receives the counter's current value | **Returns**: non-zero on success ## `QueryPerformanceFrequency` ```rux pub extern func QueryPerformanceFrequency(frequency: *var int64) -> int32 ``` Reads how many performance-counter ticks make one second. Fixed while the system runs, so a caller reads it once rather than per measurement. **See also**: <https://learn.microsoft.com/en-us/windows/win32/api/profileapi/nf-profileapi-queryperformancefrequency>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Clock.rux#L42){rel=""nofollow""} **Parameters** | Name | Type | Description | | ----------- | ------------ | ------------------------------------------------------------ | | `frequency` | `*var int64` | receives the counter's fixed frequency, in counts per second | **Returns**: non-zero on success ## `GetSystemTimePreciseAsFileTime` ```rux pub extern func GetSystemTimePreciseAsFileTime(time: *var FileTime) ``` Reads the current wall-clock time at the highest resolution the system offers. Writes 100-nanosecond intervals since January 1, 1601 UTC. The plain GetSystemTimeAsFileTime is cheaper and coarser, advancing only at the scheduler's tick. **See also**: <https://learn.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-getsystemtimepreciseasfiletime>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Clock.rux#L50){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------ | --------------- | -------------------- | | `time` | `*var FileTime` | receives the reading | ## `GetSystemTimeAsFileTime` ```rux pub extern func GetSystemTimeAsFileTime(time: *var FileTime) ``` Reads the current wall-clock time at the system tick's resolution. **See also**: <https://learn.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-getsystemtimeasfiletime>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Clock.rux#L56){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------ | --------------- | -------------------- | | `time` | `*var FileTime` | receives the reading | ## `GetLocalTime` ```rux pub extern func GetLocalTime(time: *SystemTime) ``` Retrieves the current local date and time. **See also**: <https://learn.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-getlocaltime>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Kernel.rux#L243){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------ | ------------- | -------------------- | | `time` | `*SystemTime` | receives the reading | ## `GetSystemTime` ```rux pub extern func GetSystemTime(time: *SystemTime) ``` Retrieves the current system date and time in Coordinated Universal Time (UTC) format. **See also**: <https://learn.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-getsystemtime>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Kernel.rux#L270){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------ | ------------- | -------------------- | | `time` | `*SystemTime` | receives the reading | ## `GetTickCount64` ```rux pub extern func GetTickCount64() -> uint64 ``` Retrieves the number of milliseconds that have elapsed since the system was started. **See also**: <https://learn.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-gettickcount64>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Kernel.rux#L276){rel=""nofollow""} **Returns**: milliseconds since the system started # Console Allocating, reading and writing the console. ## `WriteConsoleW` ```rux pub extern func WriteConsoleW( consoleOutput: *var opaque, buffer: *opaque, numberOfCharsToWrite: uint32, numberOfCharsWritten: *var uint32, reserved: *var opaque ) -> int32 pub extern func WriteConsoleW( consoleOutput: *opaque, buffer: *char16, numberOfCharsToWrite: uint32, numberOfCharsWritten: *uint32, reserved: *opaque ) -> bool32 ``` Writes a character string to a console screen buffer beginning at the current cursor location. | Overload | Summary | | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------- | | `pub extern func WriteConsoleW(consoleOutput: *var opaque, buffer: *opaque, numberOfCharsToWrite: uint32, numberOfCharsWritten: *var uint32, reserved: *var opaque) -> int32` | Writes UTF-16 to a console screen buffer. | | `pub extern func WriteConsoleW(consoleOutput: *opaque, buffer: *char16, numberOfCharsToWrite: uint32, numberOfCharsWritten: *uint32, reserved: *opaque) -> bool32` | Writes a character string to a console screen buffer beginning at the current cursor location. | **See also**: <https://learn.microsoft.com/en-us/windows/console/writeconsole>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/File.rux#L324){rel=""nofollow""} **Parameters** | Name | Type | Description | | ---------------------- | ------------------------- | ------------------------------ | | `consoleOutput` | `*var opaque` / `*opaque` | a console output handle | | `buffer` | `*opaque` / `*char16` | the bytes | | `numberOfCharsToWrite` | `uint32` | how many units to write | | `numberOfCharsWritten` | `*var uint32` / `*uint32` | receives how many were written | | `reserved` | `*var opaque` / `*opaque` | reserved; pass null | **Returns**: non-zero on success, and zero on failure with the reason in [`GetLastError`](https://rux-lang.dev/docs/api/windows/errors#get-last-error) ## `ReadConsoleW` ```rux pub extern func ReadConsoleW( consoleInput: *var opaque, buffer: *var opaque, numberOfCharsToRead: uint32, numberOfCharsRead: *var uint32, inputControl: *var opaque ) -> int32 ``` Reads UTF-16 from a console input buffer. **See also**: <https://learn.microsoft.com/en-us/windows/console/readconsole>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/File.rux#L336){rel=""nofollow""} **Parameters** | Name | Type | Description | | --------------------- | ------------- | -------------------------------- | | `consoleInput` | `*var opaque` | a console input handle | | `buffer` | `*var opaque` | the bytes | | `numberOfCharsToRead` | `uint32` | how many units to ask for | | `numberOfCharsRead` | `*var uint32` | receives how many were read | | `inputControl` | `*var opaque` | an input-control record, or null | **Returns**: non-zero on success ## `AllocConsole` ```rux pub extern func AllocConsole() -> bool32 ``` Allocates a new console for the calling process. **See also**: <https://learn.microsoft.com/en-us/windows/console/allocconsole>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Kernel.rux#L12){rel=""nofollow""} **Returns**: non-zero on success, and zero on failure with the reason in [`GetLastError`](https://rux-lang.dev/docs/api/windows/errors#get-last-error) ## `Beep` ```rux pub extern func Beep( freq: uint32, duration: uint32 ) -> bool32 ``` Generates simple tones on the speaker. **See also**: <https://learn.microsoft.com/en-us/windows/win32/api/utilapiset/nf-utilapiset-beep>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Kernel.rux#L20){rel=""nofollow""} **Parameters** | Name | Type | Description | | ---------- | -------- | ------------------------------------- | | `freq` | `uint32` | the tone's frequency in hertz | | `duration` | `uint32` | how long to sound it, in milliseconds | **Returns**: non-zero on success, and zero on failure with the reason in [`GetLastError`](https://rux-lang.dev/docs/api/windows/errors#get-last-error) ## `GetConsoleMode` ```rux pub extern func GetConsoleMode( consoleHandle: *opaque, mode: *uint32 ) -> bool32 ``` Retrieves the current input or output mode of a console screen buffer. **See also**: <https://learn.microsoft.com/en-us/windows/console/getconsolemode>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Kernel.rux#L153){rel=""nofollow""} **Parameters** | Name | Type | Description | | --------------- | --------- | ------------------------------ | | `consoleHandle` | `*opaque` | a console handle | | `mode` | `*uint32` | receives the console mode bits | **Returns**: non-zero on success, and zero on failure with the reason in [`GetLastError`](https://rux-lang.dev/docs/api/windows/errors#get-last-error) ## `GetStdHandle` ```rux pub extern func GetStdHandle(stdHandle: uint32) -> *opaque ``` Retrieves a handle to the specified standard device (standard input, standard output, or standard error). **See also**: <https://learn.microsoft.com/en-us/windows/console/getstdhandle>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Kernel.rux#L264){rel=""nofollow""} **Parameters** | Name | Type | Description | | ----------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `stdHandle` | `uint32` | one of [`StdInputHandle`](https://rux-lang.dev/docs/api/windows/console#std-input-handle), [`StdOutputHandle`](https://rux-lang.dev/docs/api/windows/console#std-output-handle) or [`StdErrorHandle`](https://rux-lang.dev/docs/api/windows/console#std-error-handle) | **Returns**: the standard handle, or [`InvalidHandleValue`](https://rux-lang.dev/docs/api/windows/types#invalid-handle-value) ## `ReadConsoleA` ```rux pub extern func ReadConsoleA( consoleInput: *opaque, buffer: *opaque, numberOfCharsToRead: uint32, numberOfCharsRead: *uint32, inputControl: *opaque ) -> bool32 ``` Reads characters from a console input buffer. **See also**: <https://learn.microsoft.com/en-us/windows/console/readconsole>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Kernel.rux#L368){rel=""nofollow""} **Parameters** | Name | Type | Description | | --------------------- | --------- | -------------------------------- | | `consoleInput` | `*opaque` | a console input handle | | `buffer` | `*opaque` | the bytes | | `numberOfCharsToRead` | `uint32` | how many units to ask for | | `numberOfCharsRead` | `*uint32` | receives how many were read | | `inputControl` | `*opaque` | an input-control record, or null | **Returns**: non-zero on success, and zero on failure with the reason in [`GetLastError`](https://rux-lang.dev/docs/api/windows/errors#get-last-error) ## `WriteConsoleA` ```rux pub extern func WriteConsoleA( consoleOutput: *opaque, buffer: *char8, numberOfCharsToWrite: uint32, numberOfCharsWritten: *uint32, reserved: *opaque ) -> bool32 ``` Writes a character string to a console screen buffer beginning at the current cursor location. **See also**: <https://learn.microsoft.com/en-us/windows/console/writeconsole>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Kernel.rux#L539){rel=""nofollow""} **Parameters** | Name | Type | Description | | ---------------------- | --------- | ------------------------------ | | `consoleOutput` | `*opaque` | a console output handle | | `buffer` | `*char8` | the bytes | | `numberOfCharsToWrite` | `uint32` | how many units to write | | `numberOfCharsWritten` | `*uint32` | receives how many were written | | `reserved` | `*opaque` | reserved; pass null | **Returns**: non-zero on success, and zero on failure with the reason in [`GetLastError`](https://rux-lang.dev/docs/api/windows/errors#get-last-error) ## `StdInputHandle` ```rux pub const StdInputHandle: uint32 = 0xFFFFFFF6; ``` The public `StdInputHandle` value. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Types.rux#L63){rel=""nofollow""} ## `StdOutputHandle` ```rux pub const StdOutputHandle: uint32 = 0xFFFFFFF5; ``` The public `StdOutputHandle` value. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Types.rux#L69){rel=""nofollow""} ## `StdErrorHandle` ```rux pub const StdErrorHandle: uint32 = 0xFFFFFFF4; ``` The public `StdErrorHandle` value. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Types.rux#L75){rel=""nofollow""} # File system Deleting, copying and moving files, directories, attributes, search and links. ## `FILE_ATTRIBUTE_READONLY` ```rux pub const FILE_ATTRIBUTE_READONLY: uint32 = 0x00000001; ``` `FILE_ATTRIBUTE_READONLY`: the file may not be opened for writing or deleted. The whole of Windows' permission model as this package uses it: there are ACLs underneath, but nothing in the portable surface can express them, and this bit is what `chmod` maps onto. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/File.rux#L55){rel=""nofollow""} ## `FILE_ATTRIBUTE_DIRECTORY` ```rux pub const FILE_ATTRIBUTE_DIRECTORY: uint32 = 0x00000010; ``` `FILE_ATTRIBUTE_DIRECTORY`: the name is a directory. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/File.rux#L60){rel=""nofollow""} ## `FILE_ATTRIBUTE_REPARSE_POINT` ```rux pub const FILE_ATTRIBUTE_REPARSE_POINT: uint32 = 0x00000400; ``` `FILE_ATTRIBUTE_REPARSE_POINT`: the name carries a reparse point, which is what a symbolic link is. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/File.rux#L65){rel=""nofollow""} ## `INVALID_FILE_ATTRIBUTES` ```rux pub const INVALID_FILE_ATTRIBUTES: uint32 = 0xFFFFFFFF; ``` `INVALID_FILE_ATTRIBUTES`: what [`GetFileAttributesW`](https://rux-lang.dev/docs/api/windows/file-system#get-file-attributes-w) returns when it could not answer. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/File.rux#L70){rel=""nofollow""} ## `SYMBOLIC_LINK_FLAG_DIRECTORY` ```rux pub const SYMBOLIC_LINK_FLAG_DIRECTORY: uint32 = 0x00000001; ``` `SYMBOLIC_LINK_FLAG_DIRECTORY`: the link's target is a directory. Windows types its symbolic links: a link made without this flag misbehaves when its target is a directory, which no Unix symlink ever asked anyone to know in advance. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/File.rux#L98){rel=""nofollow""} ## `SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE` ```rux pub const SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE: uint32 = 0x00000002; ``` `SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE`: let a Developer Mode machine create the link without the privilege older systems demand. Harmless where the privilege is held; without Developer Mode or the privilege the call still fails with [`ERROR_PRIVILEGE_NOT_HELD`](https://rux-lang.dev/docs/api/windows/errors#error-privilege-not-held). [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/File.rux#L106){rel=""nofollow""} ## `MOVEFILE_REPLACE_EXISTING` ```rux pub const MOVEFILE_REPLACE_EXISTING: uint32 = 0x00000001; ``` `MOVEFILE_REPLACE_EXISTING`: let the move overwrite an existing target. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/File.rux#L111){rel=""nofollow""} ## `MOVEFILE_WRITE_THROUGH` ```rux pub const MOVEFILE_WRITE_THROUGH: uint32 = 0x00000008; ``` `MOVEFILE_WRITE_THROUGH`: do not return until the move has reached the disk. With [`MOVEFILE_REPLACE_EXISTING`](https://rux-lang.dev/docs/api/windows/file-system#move-file-replace-existing), this is what makes publishing a file under its final name durable. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/File.rux#L117){rel=""nofollow""} ## `FindFirstFileW` ```rux pub extern func FindFirstFileW( fileName: *char16, findFileData: *var opaque ) -> *var opaque ``` Begins a directory enumeration matching a UTF-16 pattern. Returns InvalidHandleValue on failure. `findFileData` receives a WIN32\_FIND\_DATAW record: attributes at offset 0 (4 bytes), three FILETIMEs from 4, the size's halves at 28 and 32, and the entry's NUL-terminated UTF-16 name from offset 44. The record is 592 bytes. **See also**: <https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-findfirstfilew>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/File.rux#L146){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------------- | ------------- | ------------------------------------- | | `fileName` | `*char16` | the path, as a null-terminated string | | `findFileData` | `*var opaque` | receives the entry's record | **Returns**: a search handle, or [`InvalidHandleValue`](https://rux-lang.dev/docs/api/windows/types#invalid-handle-value) ## `FindNextFileW` ```rux pub extern func FindNextFileW( findFile: *var opaque, findFileData: *var opaque ) -> int32 ``` Continues a directory enumeration; fails with ERROR\_NO\_MORE\_FILES at its end. **See also**: <https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-findnextfilew>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/File.rux#L154){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------------- | ------------- | ------------------------------------------------- | | `findFile` | `*var opaque` | a search handle from the matching `FindFirstFile` | | `findFileData` | `*var opaque` | receives the entry's record | **Returns**: non-zero on success, and zero at the end of the enumeration ## `CreateHardLinkW` ```rux pub extern func CreateHardLinkW( fileName: *char16, existingFileName: *char16, securityAttributes: *var opaque ) -> int32 ``` Creates a hard link: a second name for an existing file's contents. **See also**: <https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-createhardlinkw>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/File.rux#L163){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------------------- | ------------- | ---------------------------------------------- | | `fileName` | `*char16` | the path, as a null-terminated string | | `existingFileName` | `*char16` | the path that exists now | | `securityAttributes` | `*var opaque` | a security descriptor, or null for the default | **Returns**: non-zero on success ## `CreateSymbolicLinkW` ```rux pub extern func CreateSymbolicLinkW( symlinkFileName: *char16, targetFileName: *char16, flags: uint32 ) -> uint8 ``` Creates a symbolic link; returns a BOOLEAN, so only the low byte is meaningful. Creation needs SeCreateSymbolicLinkPrivilege or a Developer Mode machine with the allow-unprivileged flag; without either it fails with ERROR\_PRIVILEGE\_NOT\_HELD. **See also**: <https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-createsymboliclinkw>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/File.rux#L174){rel=""nofollow""} **Parameters** | Name | Type | Description | | ----------------- | --------- | --------------------------------------- | | `symlinkFileName` | `*char16` | the link to create | | `targetFileName` | `*char16` | the path the link will point at | | `flags` | `uint32` | the call's flag bits, combined with `|` | **Returns**: non-zero on success; creating one needs a privilege or developer mode ## `GetTempPathW` ```rux pub extern func GetTempPathW( bufferLength: uint32, buffer: *var char16 ) -> uint32 ``` Writes the path of the directory designated for temporary files. Returns the length written without the terminator, or the required length when the buffer is too small, or zero on failure. The answer always ends in a backslash. Consults TMP, then TEMP, then USERPROFILE, then the Windows directory, so it answers even where none of those are set. **See also**: <https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-gettemppathw>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/File.rux#L222){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------------- | ------------- | ----------------------------- | | `bufferLength` | `uint32` | how many units `buffer` holds | | `buffer` | `*var char16` | the bytes | **Returns**: the length written including the separator, or zero on failure ## `DeleteFileW` ```rux pub extern func DeleteFileW(fileName: *char16) -> int32 ``` Deletes a file, taking a UTF-16 path. **See also**: <https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-deletefilew>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/File.rux#L229){rel=""nofollow""} **Parameters** | Name | Type | Description | | ---------- | --------- | ------------------------------------- | | `fileName` | `*char16` | the path, as a null-terminated string | **Returns**: non-zero on success ## `MoveFileExW` ```rux pub extern func MoveFileExW( existingFileName: *char16, newFileName: *char16, flags: uint32 ) -> int32 ``` Moves or renames a file or directory, taking UTF-16 paths. With MOVEFILE\_REPLACE\_EXISTING this replaces the target atomically within a volume, which is how a file is published under its final name. Across volumes it copies and deletes instead, which is not atomic. **See also**: <https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-movefileexw>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/File.rux#L240){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------------------ | --------- | --------------------------------------- | | `existingFileName` | `*char16` | the path that exists now | | `newFileName` | `*char16` | the path it should have afterwards | | `flags` | `uint32` | the call's flag bits, combined with `|` | **Returns**: non-zero on success ## `CopyFileW` ```rux pub extern func CopyFileW( existingFileName: *char16, newFileName: *char16, failIfExists: int32 ) -> int32 ``` Copies a file, taking UTF-16 paths. **See also**: <https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-copyfilew>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/File.rux#L249){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------------------ | --------- | ---------------------------------------- | | `existingFileName` | `*char16` | the path that exists now | | `newFileName` | `*char16` | the path it should have afterwards | | `failIfExists` | `int32` | non-zero to refuse rather than overwrite | **Returns**: non-zero on success ## `CreateDirectoryW` ```rux pub extern func CreateDirectoryW( pathName: *char16, securityAttributes: *var opaque ) -> int32 ``` Creates a directory, taking a UTF-16 path. **See also**: <https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createdirectoryw>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/File.rux#L257){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------------------- | ------------- | ----------------------------------------------- | | `pathName` | `*char16` | the directory path, as a null-terminated string | | `securityAttributes` | `*var opaque` | a security descriptor, or null for the default | **Returns**: non-zero on success ## `RemoveDirectoryW` ```rux pub extern func RemoveDirectoryW(pathName: *char16) -> int32 ``` Removes an empty directory, taking a UTF-16 path. **See also**: <https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-removedirectoryw>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/File.rux#L264){rel=""nofollow""} **Parameters** | Name | Type | Description | | ---------- | --------- | ----------------------------------------------- | | `pathName` | `*char16` | the directory path, as a null-terminated string | **Returns**: non-zero on success ## `GetFileAttributesW` ```rux pub extern func GetFileAttributesW(fileName: *char16) -> uint32 ``` Reads a file's attributes, taking a UTF-16 path. Returns 0xFFFFFFFF on failure, which is INVALID\_FILE\_ATTRIBUTES and not an attribute value. **See also**: <https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getfileattributesw>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/File.rux#L272){rel=""nofollow""} **Parameters** | Name | Type | Description | | ---------- | --------- | ------------------------------------- | | `fileName` | `*char16` | the path, as a null-terminated string | **Returns**: the attribute bits, or [`INVALID_FILE_ATTRIBUTES`](https://rux-lang.dev/docs/api/windows/file-system#invalid-file-attributes) ## `SetFileAttributesW` ```rux pub extern func SetFileAttributesW( fileName: *char16, fileAttributes: uint32 ) -> int32 ``` Sets a file's attributes, taking a UTF-16 path. **See also**: <https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-setfileattributesw>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/File.rux#L280){rel=""nofollow""} **Parameters** | Name | Type | Description | | ---------------- | --------- | ------------------------------------- | | `fileName` | `*char16` | the path, as a null-terminated string | | `fileAttributes` | `uint32` | the attribute bits to set | **Returns**: non-zero on success ## `GetCurrentDirectoryW` ```rux pub extern func GetCurrentDirectoryW( bufferLength: uint32, buffer: *var char16 ) -> uint32 ``` Reads the current directory into a UTF-16 buffer. Returns the length written, or the length required when the buffer is too small — a return larger than the buffer is not a failure but a request to call again. **See also**: <https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-getcurrentdirectory>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/File.rux#L290){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------------- | ------------- | ----------------------------- | | `bufferLength` | `uint32` | how many units `buffer` holds | | `buffer` | `*var char16` | the bytes | **Returns**: the length written, the length needed when the buffer is too small, or zero on failure ## `SetCurrentDirectoryW` ```rux pub extern func SetCurrentDirectoryW(pathName: *char16) -> int32 ``` Sets the current directory, taking a UTF-16 path. **See also**: <https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-setcurrentdirectory>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/File.rux#L297){rel=""nofollow""} **Parameters** | Name | Type | Description | | ---------- | --------- | ----------------------------------------------- | | `pathName` | `*char16` | the directory path, as a null-terminated string | **Returns**: non-zero on success ## `CopyFileA` ```rux pub extern func CopyFileA( existingFileName: *char8, newFileName: *char8, failIfExists: bool32 ) -> bool32 ``` Copies an existing file to a new file. **See also**: <https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-copyfilea>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Kernel.rux#L36){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------------------ | -------- | ---------------------------------------- | | `existingFileName` | `*char8` | the path that exists now | | `newFileName` | `*char8` | the path it should have afterwards | | `failIfExists` | `bool32` | non-zero to refuse rather than overwrite | **Returns**: non-zero on success, and zero on failure with the reason in [`GetLastError`](https://rux-lang.dev/docs/api/windows/errors#get-last-error) ## `CreateDirectoryA` ```rux pub extern func CreateDirectoryA( pathName: *char8, securityAttributes: *opaque ) -> bool32 ``` Creates a new directory. **See also**: <https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createdirectorya>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Kernel.rux#L48){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------------------- | --------- | ----------------------------------------------- | | `pathName` | `*char8` | the directory path, as a null-terminated string | | `securityAttributes` | `*opaque` | a security descriptor, or null for the default | **Returns**: non-zero on success, and zero on failure with the reason in [`GetLastError`](https://rux-lang.dev/docs/api/windows/errors#get-last-error) ## `DeleteFileA` ```rux pub extern func DeleteFileA(fileName: *char8) -> bool32 ``` Deletes an existing file. **See also**: <https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-deletefilea>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Kernel.rux#L97){rel=""nofollow""} **Parameters** | Name | Type | Description | | ---------- | -------- | ------------------------------------- | | `fileName` | `*char8` | the path, as a null-terminated string | **Returns**: non-zero on success, and zero on failure with the reason in [`GetLastError`](https://rux-lang.dev/docs/api/windows/errors#get-last-error) ## `FindClose` ```rux pub extern func FindClose(findFile: *opaque) -> bool32 ``` Closes a file search handle opened by the FindFirstFile, FindFirstFileEx, FindFirstFileNameW,. FindFirstFileNameTransactedW, FindFirstFileTransacted, FindFirstStreamTransactedW, or FindFirstStreamW functions. **See also**: <https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-findclose>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Kernel.rux#L112){rel=""nofollow""} **Parameters** | Name | Type | Description | | ---------- | --------- | ------------------------------------------------- | | `findFile` | `*opaque` | a search handle from the matching `FindFirstFile` | **Returns**: non-zero on success, and zero on failure with the reason in [`GetLastError`](https://rux-lang.dev/docs/api/windows/errors#get-last-error) ## `FindFirstFileA` ```rux pub extern func FindFirstFileA( fileName: *char8, findFileData: *Win32FindDataA ) -> *opaque ``` Searches a directory for a file or subdirectory with a name that matches a specific name (or partial name if wildcards are used). **See also**: <https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-findfirstfilea>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Kernel.rux#L121){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------------- | ----------------- | ------------------------------------- | | `fileName` | `*char8` | the path, as a null-terminated string | | `findFileData` | `*Win32FindDataA` | receives the entry's record | **Returns**: a search handle, or [`InvalidHandleValue`](https://rux-lang.dev/docs/api/windows/types#invalid-handle-value) ## `FindNextFileA` ```rux pub extern func FindNextFileA( findFile: *opaque, findFileData: *Win32FindDataA ) -> bool32 ``` Continues a file search from a previous call to the FindFirstFile, FindFirstFileEx, or FindFirstFileTransacted functions. **See also**: <https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-findnextfilea>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Kernel.rux#L133){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------------- | ----------------- | ------------------------------------------------- | | `findFile` | `*opaque` | a search handle from the matching `FindFirstFile` | | `findFileData` | `*Win32FindDataA` | receives the entry's record | **Returns**: non-zero on success, and zero on failure with the reason in [`GetLastError`](https://rux-lang.dev/docs/api/windows/errors#get-last-error) ## `GetCurrentDirectoryA` ```rux pub extern func GetCurrentDirectoryA( bufferLength: uint32, buffer: *char8 ) -> uint32 ``` Retrieves the current directory. **See also**: <https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-getcurrentdirectory>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Kernel.rux#L181){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------------- | -------- | ----------------------------- | | `bufferLength` | `uint32` | how many units `buffer` holds | | `buffer` | `*char8` | the bytes | **Returns**: the length written, the length needed when the buffer is too small, or zero on failure ## `GetFileAttributesA` ```rux pub extern func GetFileAttributesA(fileName: *char8) -> uint32 ``` Retrieves file attributes. **See also**: <https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getfileattributesa>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Kernel.rux#L216){rel=""nofollow""} **Parameters** | Name | Type | Description | | ---------- | -------- | ------------------------------------- | | `fileName` | `*char8` | the path, as a null-terminated string | **Returns**: the attribute bits, or [`INVALID_FILE_ATTRIBUTES`](https://rux-lang.dev/docs/api/windows/file-system#invalid-file-attributes) ## `MoveFileA` ```rux pub extern func MoveFileA( existingFileName: *char8, newFileName: *char8 ) -> bool32 ``` Moves an existing file or directory. **See also**: <https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-movefilea>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Kernel.rux#L319){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------------------ | -------- | ---------------------------------- | | `existingFileName` | `*char8` | the path that exists now | | `newFileName` | `*char8` | the path it should have afterwards | **Returns**: non-zero on success, and zero on failure with the reason in [`GetLastError`](https://rux-lang.dev/docs/api/windows/errors#get-last-error) ## `RemoveDirectoryA` ```rux pub extern func RemoveDirectoryA(pathName: *char8) -> bool32 ``` Deletes an existing empty directory. **See also**: <https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-removedirectorya>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Kernel.rux#L398){rel=""nofollow""} **Parameters** | Name | Type | Description | | ---------- | -------- | ----------------------------------------------- | | `pathName` | `*char8` | the directory path, as a null-terminated string | **Returns**: non-zero on success, and zero on failure with the reason in [`GetLastError`](https://rux-lang.dev/docs/api/windows/errors#get-last-error) ## `SetCurrentDirectoryA` ```rux pub extern func SetCurrentDirectoryA(pathName: *char8) -> bool32 ``` Changes the current directory. **See also**: <https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-setcurrentdirectory>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Kernel.rux#L437){rel=""nofollow""} **Parameters** | Name | Type | Description | | ---------- | -------- | ----------------------------------------------- | | `pathName` | `*char8` | the directory path, as a null-terminated string | **Returns**: non-zero on success, and zero on failure with the reason in [`GetLastError`](https://rux-lang.dev/docs/api/windows/errors#get-last-error) ## `SetFileAttributesA` ```rux pub extern func SetFileAttributesA( fileName: *char8, fileAttributes: uint32 ) -> bool32 ``` Sets file attributes. **See also**: <https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-setfileattributesa>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Kernel.rux#L445){rel=""nofollow""} **Parameters** | Name | Type | Description | | ---------------- | -------- | ------------------------------------- | | `fileName` | `*char8` | the path, as a null-terminated string | | `fileAttributes` | `uint32` | the attribute bits to set | **Returns**: non-zero on success, and zero on failure with the reason in [`GetLastError`](https://rux-lang.dev/docs/api/windows/errors#get-last-error) # Files Opening, reading, writing and flushing files through handles. ## `GENERIC_READ` ```rux pub const GENERIC_READ: uint32 = 0x80000000; ``` `GENERIC_READ`: the handle may read. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/File.rux#L14){rel=""nofollow""} ## `GENERIC_WRITE` ```rux pub const GENERIC_WRITE: uint32 = 0x40000000; ``` `GENERIC_WRITE`: the handle may write. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/File.rux#L19){rel=""nofollow""} ## `FILE_APPEND_DATA` ```rux pub const FILE_APPEND_DATA: uint32 = 0x00000004; ``` `FILE_APPEND_DATA`: the handle may append, and only append. The access right that makes an append-only handle: every write lands at the end whatever the file pointer says, which [`GENERIC_WRITE`](https://rux-lang.dev/docs/api/windows/files#generic-write) does not promise. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/File.rux#L26){rel=""nofollow""} ## `FILE_SHARE_READ` ```rux pub const FILE_SHARE_READ: uint32 = 0x00000001; ``` `FILE_SHARE_READ`: other openers may read while this handle is open. Windows denies sharing by default, which is the opposite of every Unix. A file opened without this cannot be opened for reading by anything else, including the same process. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/File.rux#L33){rel=""nofollow""} ## `FILE_SHARE_WRITE` ```rux pub const FILE_SHARE_WRITE: uint32 = 0x00000002; ``` `FILE_SHARE_WRITE`: other openers may write while this handle is open. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/File.rux#L38){rel=""nofollow""} ## `FILE_SHARE_DELETE` ```rux pub const FILE_SHARE_DELETE: uint32 = 0x00000004; ``` `FILE_SHARE_DELETE`: the file may be renamed or deleted while this handle is open. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/File.rux#L43){rel=""nofollow""} ## `FILE_ATTRIBUTE_NORMAL` ```rux pub const FILE_ATTRIBUTE_NORMAL: uint32 = 0x00000080; ``` `FILE_ATTRIBUTE_NORMAL`: no attributes beyond being an ordinary file. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/File.rux#L48){rel=""nofollow""} ## `FILE_FLAG_BACKUP_SEMANTICS` ```rux pub const FILE_FLAG_BACKUP_SEMANTICS: uint32 = 0x02000000; ``` `FILE_FLAG_BACKUP_SEMANTICS`: let [`CreateFileW`](https://rux-lang.dev/docs/api/windows/files#create-file-w) open a directory. Without it a directory cannot be opened at all, which makes this the flag every metadata query needs. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/File.rux#L76){rel=""nofollow""} ## `FILE_FLAG_OPEN_REPARSE_POINT` ```rux pub const FILE_FLAG_OPEN_REPARSE_POINT: uint32 = 0x00200000; ``` `FILE_FLAG_OPEN_REPARSE_POINT`: open the symbolic link itself rather than what it points at. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/File.rux#L81){rel=""nofollow""} ## `FILE_FLAG_DELETE_ON_CLOSE` ```rux pub const FILE_FLAG_DELETE_ON_CLOSE: uint32 = 0x04000000; ``` `FILE_FLAG_DELETE_ON_CLOSE`: remove the file when its last handle closes. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/File.rux#L86){rel=""nofollow""} ## `FILE_FLAG_WRITE_THROUGH` ```rux pub const FILE_FLAG_WRITE_THROUGH: uint32 = 0x80000000; ``` `FILE_FLAG_WRITE_THROUGH`: writes reach the device before the call returns. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/File.rux#L91){rel=""nofollow""} ## `CreateFileW` ```rux pub extern func CreateFileW( fileName: *char16, desiredAccess: uint32, shareMode: uint32, securityAttributes: *var opaque, creationDisposition: uint32, flagsAndAttributes: uint32, templateFile: *var opaque ) -> *var opaque pub extern func CreateFileW( fileName: *char16, desiredAccess: uint32, shareMode: uint32, securityAttributes: *opaque, creationDisposition: uint32, flagsAndAttributes: uint32, templateFile: *opaque ) -> *opaque ``` Creates or opens a file or device, taking a UTF-16 path. Returns InvalidHandleValue on failure, not null. The share mode is not a default: passing zero denies every other opener, which is Windows' behaviour and not most callers' intent. | Overload | Summary | | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -------------------------------------------------------- | | `pub extern func CreateFileW(fileName: *char16, desiredAccess: uint32, shareMode: uint32, securityAttributes: *var opaque, creationDisposition: uint32, flagsAndAttributes: uint32, templateFile: *var opaque) -> *var opaque` | Creates or opens a file or device, taking a UTF-16 path. | | `pub extern func CreateFileW(fileName: *char16, desiredAccess: uint32, shareMode: uint32, securityAttributes: *opaque, creationDisposition: uint32, flagsAndAttributes: uint32, templateFile: *opaque) -> *opaque` | Creates or opens a file or I/O device. | **See also**: <https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilew>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/File.rux#L134){rel=""nofollow""} **Parameters** | Name | Type | Description | | --------------------- | ------------------------- | ------------------------------------------------------------------------------------------------------------ | | `fileName` | `*char16` | the path, as a null-terminated string | | `desiredAccess` | `uint32` | the access rights wanted, such as [`GENERIC_READ`](https://rux-lang.dev/docs/api/windows/files#generic-read) | | `shareMode` | `uint32` | what other openers may do meanwhile; zero denies them everything | | `securityAttributes` | `*var opaque` / `*opaque` | a security descriptor, or null for the default | | `creationDisposition` | `uint32` | one of the [`CreationDisposition`](https://rux-lang.dev/docs/api/windows/creation-disposition) values | | `flagsAndAttributes` | `uint32` | the file attributes and flags | | `templateFile` | `*var opaque` / `*opaque` | a template whose attributes to copy, or null | **Returns**: the new handle, or [`InvalidHandleValue`](https://rux-lang.dev/docs/api/windows/types#invalid-handle-value) — which is not null ## `GetFileInformationByHandle` ```rux pub extern func GetFileInformationByHandle( file: *var opaque, fileInformation: *var opaque ) -> int32 ``` Fills a BY\_HANDLE\_FILE\_INFORMATION record for an open handle. The record is 52 bytes: attributes at offset 0 (4 bytes), the creation, last-access and last-write FILETIMEs at 4, 12 and 20 (8 bytes each), the volume serial number at 28, the size's high and low halves at 32 and 36, the link count at 40, and the file index's halves at 44 and 48. **See also**: <https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getfileinformationbyhandle>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/File.rux#L185){rel=""nofollow""} **Parameters** | Name | Type | Description | | ----------------- | ------------- | -------------------------------------- | | `file` | `*var opaque` | an open file handle | | `fileInformation` | `*var opaque` | receives the file's information record | **Returns**: non-zero on success ## `SetFileTime` ```rux pub extern func SetFileTime( file: *var opaque, creationTime: *FileTime, lastAccessTime: *FileTime, lastWriteTime: *FileTime ) -> int32 ``` Sets the creation, last-access and last-write times of an open handle. Each pointer may be null to leave that time alone. **See also**: <https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-setfiletime>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/File.rux#L196){rel=""nofollow""} **Parameters** | Name | Type | Description | | ---------------- | ------------- | --------------------------------------------- | | `file` | `*var opaque` | an open file handle | | `creationTime` | `*FileTime` | the creation time to set, or null to leave it | | `lastAccessTime` | `*FileTime` | the access time to set, or null to leave it | | `lastWriteTime` | `*FileTime` | the write time to set, or null to leave it | **Returns**: non-zero on success ## `GetFinalPathNameByHandleW` ```rux pub extern func GetFinalPathNameByHandleW( file: *var opaque, filePath: *var char16, filePathLength: uint32, flags: uint32 ) -> uint32 ``` Writes the final, resolved path of an open handle: symbolic links followed, short names expanded, case as the filesystem stores it. Returns the length written, without the terminator, or the required length when the buffer is too small, or zero on failure. VOLUME\_NAME\_DOS (0) spells the answer with a drive letter where the file has one. **See also**: <https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getfinalpathnamebyhandlew>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/File.rux#L210){rel=""nofollow""} **Parameters** | Name | Type | Description | | ---------------- | ------------- | --------------------------------------- | | `file` | `*var opaque` | an open file handle | | `filePath` | `*var char16` | receives the resolved path | | `filePathLength` | `uint32` | how many units `filePath` holds | | `flags` | `uint32` | the call's flag bits, combined with `|` | **Returns**: the length written, or zero on failure ## `FlushFileBuffers` ```rux pub extern func FlushFileBuffers(file: *var opaque) -> int32 ``` Flushes a file handle's writes to the device. Returns zero on failure. This is what makes a write durable; FILE\_FLAG\_WRITE\_THROUGH is the alternative that does it on every write instead. **See also**: <https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-flushfilebuffers>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/File.rux#L306){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------ | ------------- | ------------------- | | `file` | `*var opaque` | an open file handle | **Returns**: non-zero on success ## `SetEndOfFile` ```rux pub extern func SetEndOfFile(file: *var opaque) -> int32 ``` Sets the size of a file to the handle's current position. **See also**: <https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-setendoffile>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/File.rux#L313){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------ | ------------- | ------------------- | | `file` | `*var opaque` | an open file handle | **Returns**: non-zero on success ## `CloseHandle` ```rux pub extern func CloseHandle(handle: *opaque) -> bool32 ``` Closes an open object handle. **See also**: <https://learn.microsoft.com/en-us/windows/win32/api/handleapi/nf-handleapi-closehandle>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Kernel.rux#L27){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | --------- | -------------------- | | `handle` | `*opaque` | the handle to act on | **Returns**: non-zero on success, and zero on failure with the reason in [`GetLastError`](https://rux-lang.dev/docs/api/windows/errors#get-last-error) ## `CreateFileA` ```rux pub extern func CreateFileA( fileName: *char8, desiredAccess: uint32, shareMode: uint32, securityAttributes: *opaque, creationDisposition: uint32, flagsAndAttributes: uint32, templateFile: *opaque ) -> *opaque ``` Creates or opens a file or I/O device. **See also**: <https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilea>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Kernel.rux#L61){rel=""nofollow""} **Parameters** | Name | Type | Description | | --------------------- | --------- | ------------------------------------------------------------------------------------------------------------ | | `fileName` | `*char8` | the path, as a null-terminated string | | `desiredAccess` | `uint32` | the access rights wanted, such as [`GENERIC_READ`](https://rux-lang.dev/docs/api/windows/files#generic-read) | | `shareMode` | `uint32` | what other openers may do meanwhile; zero denies them everything | | `securityAttributes` | `*opaque` | a security descriptor, or null for the default | | `creationDisposition` | `uint32` | one of the [`CreationDisposition`](https://rux-lang.dev/docs/api/windows/creation-disposition) values | | `flagsAndAttributes` | `uint32` | the file attributes and flags | | `templateFile` | `*opaque` | a template whose attributes to copy, or null | **Returns**: the new handle, or [`InvalidHandleValue`](https://rux-lang.dev/docs/api/windows/types#invalid-handle-value) — which is not null ## `GetFileSizeEx` ```rux pub extern func GetFileSizeEx( file: *opaque, size: *int64 ) -> bool32 ``` Retrieves the size of the specified file. **See also**: <https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getfilesizeex>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Kernel.rux#L224){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------ | --------- | ------------------- | | `file` | `*opaque` | an open file handle | | `size` | `*int64` | a size in bytes | **Returns**: non-zero on success, and zero on failure with the reason in [`GetLastError`](https://rux-lang.dev/docs/api/windows/errors#get-last-error) ## `ReadFile` ```rux pub extern func ReadFile( file: *opaque, buffer: *opaque, numberOfBytesToRead: uint32, numberOfBytesRead: *uint32, overlapped: *opaque ) -> bool32 ``` Reads data from the specified file or input/output (I/O) device. **See also**: <https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-readfile>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Kernel.rux#L385){rel=""nofollow""} **Parameters** | Name | Type | Description | | --------------------- | --------- | ---------------------------------------------------- | | `file` | `*opaque` | an open file handle | | `buffer` | `*opaque` | the bytes | | `numberOfBytesToRead` | `uint32` | how many bytes to ask for | | `numberOfBytesRead` | `*uint32` | receives how many were read | | `overlapped` | `*opaque` | an overlapped record, or null for a synchronous call | **Returns**: non-zero on success, and zero on failure with the reason in [`GetLastError`](https://rux-lang.dev/docs/api/windows/errors#get-last-error) ## `SetFilePointerEx` ```rux pub extern func SetFilePointerEx( file: *opaque, distanceToMov: int64, newFilePointer: *int64, moveMethod: uint32 ) -> bool32 ``` Moves the file pointer of the specified file. **See also**: <https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-setfilepointerex>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Kernel.rux#L455){rel=""nofollow""} **Parameters** | Name | Type | Description | | ---------------- | --------- | -------------------------------------------- | | `file` | `*opaque` | an open file handle | | `distanceToMov` | `int64` | how far to move, interpreted by `moveMethod` | | `newFilePointer` | `*int64` | receives the resulting offset, or null | | `moveMethod` | `uint32` | where the move is measured from | **Returns**: non-zero on success, and zero on failure with the reason in [`GetLastError`](https://rux-lang.dev/docs/api/windows/errors#get-last-error) ## `WriteFile` ```rux pub extern func WriteFile( file: *opaque, buffer: *opaque, bytesToWrite: uint32, bytesWritten: *uint32, overlapped: *opaque ) -> bool32 ``` Writes data to the specified file or input/output (I/O) device. **See also**: <https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-writefile>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Kernel.rux#L573){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------------- | --------- | ---------------------------------------------------- | | `file` | `*opaque` | an open file handle | | `buffer` | `*opaque` | the bytes | | `bytesToWrite` | `uint32` | how many bytes to offer | | `bytesWritten` | `*uint32` | receives how many were written | | `overlapped` | `*opaque` | an overlapped record, or null for a synchronous call | **Returns**: non-zero on success, and zero on failure with the reason in [`GetLastError`](https://rux-lang.dev/docs/api/windows/errors#get-last-error) # GetRandom Fills `length` bytes of `buffer` with unpredictable bytes. ```rux pub func GetRandom( buffer: *var opaque, length: uint ) -> bool ``` `buffer` is borrowed and written; `length` is read by value. Returns true when the whole buffer was filled, and false when the provider refused — there is no partial success to handle, unlike every Unix source. Runs in time proportional to `length` and allocates nothing. `buffer` must be writable for `length` bytes. `length` is passed as a 32-bit count, so a request above four gigabytes is refused rather than truncated. ## Parameters | Name | Type | Description | | -------- | ------------- | ---------------------- | | `buffer` | `*var opaque` | receives the bytes | | `length` | `uint` | how many bytes to fill | **Returns**: whether the whole buffer was filled; there is no partial success ## Related ### `BCRYPT_USE_SYSTEM_PREFERRED_RNG` ```rux pub const BCRYPT_USE_SYSTEM_PREFERRED_RNG: uint32 = 0x00000002; ``` `BCRYPT_USE_SYSTEM_PREFERRED_RNG`: draw from the system's preferred generator rather than a named algorithm. Passed with a null algorithm handle, which is what makes this a one-call interface: nothing has to be opened, configured, or closed. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Entropy.rux#L16){rel=""nofollow""} ### `STATUS_SUCCESS` ```rux pub const STATUS_SUCCESS: int32 = 0; ``` `STATUS_SUCCESS`: the status an [`NtStatus`](https://rux-lang.dev/docs/api/windows/types#nt-status)-reporting call gives when it worked. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Entropy.rux#L21){rel=""nofollow""} # Memory Heap allocation, virtual memory and raw memory operations. ## `GetProcessHeap` ```rux pub extern func GetProcessHeap() -> *opaque ``` Retrieves a handle to the default heap of the calling process. **See also**: <https://learn.microsoft.com/en-us/windows/win32/api/heapapi/nf-heapapi-getprocessheap>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Kernel.rux#L257){rel=""nofollow""} **Returns**: the process heap's handle, which is never released ## `HeapAlloc` ```rux pub extern func HeapAlloc( heap: *opaque, flags: uint32, bytes: uint ) -> *var opaque ``` Allocates a block of memory from a heap. The allocated memory is not movable. **See also**: <https://learn.microsoft.com/en-us/windows/win32/api/heapapi/nf-heapapi-heapalloc>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Kernel.rux#L285){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------- | --------- | -------------------------------------------------------------------------------------------------------------------------- | | `heap` | `*opaque` | a heap handle, from [`GetProcessHeap`](https://rux-lang.dev/docs/api/windows/memory#get-process-heap) for the process heap | | `flags` | `uint32` | the call's flag bits, combined with `|` | | `bytes` | `uint` | how many bytes to take | **Returns**: the block's address, or null ## `HeapFree` ```rux pub extern func HeapFree( heap: *opaque, flags: uint32, mem: *opaque ) -> bool32 ``` Frees a memory block allocated from a heap by the HeapAlloc or HeapReAlloc function. **See also**: <https://learn.microsoft.com/en-us/windows/win32/api/heapapi/nf-heapapi-heapfree>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Kernel.rux#L294){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------- | --------- | -------------------------------------------------------------------------------------------------------------------------- | | `heap` | `*opaque` | a heap handle, from [`GetProcessHeap`](https://rux-lang.dev/docs/api/windows/memory#get-process-heap) for the process heap | | `flags` | `uint32` | the call's flag bits, combined with `|` | | `mem` | `*opaque` | the block to act on | **Returns**: non-zero on success, and zero on failure with the reason in [`GetLastError`](https://rux-lang.dev/docs/api/windows/errors#get-last-error) ## `HeapReAlloc` ```rux pub extern func HeapReAlloc( heap: *opaque, flags: uint32, mem: *opaque, bytes: uint ) -> *var opaque ``` Reallocates a block of memory from a heap. **See also**: <https://learn.microsoft.com/en-us/windows/win32/api/heapapi/nf-heapapi-heaprealloc>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Kernel.rux#L304){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------- | --------- | -------------------------------------------------------------------------------------------------------------------------- | | `heap` | `*opaque` | a heap handle, from [`GetProcessHeap`](https://rux-lang.dev/docs/api/windows/memory#get-process-heap) for the process heap | | `flags` | `uint32` | the call's flag bits, combined with `|` | | `mem` | `*opaque` | the block to act on | | `bytes` | `uint` | how many bytes to take | **Returns**: the resized block's address, or null with the original still valid ## `RtlCompareMemory` ```rux pub extern func RtlCompareMemory( source1: *opaque, source2: *opaque, length: uint ) -> uint ``` Compares two blocks of memory and returns the number of bytes that match until the first difference. **See also**: <https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/nf-wdm-rtlcomparememory>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Kernel.rux#L407){rel=""nofollow""} **Parameters** | Name | Type | Description | | --------- | --------- | --------------------- | | `source1` | `*opaque` | one of the two blocks | | `source2` | `*opaque` | the other | | `length` | `uint` | how many bytes | **Returns**: how many leading bytes match ## `RtlCopyMemory` ```rux pub extern func RtlCopyMemory( destination: *var opaque, source: *opaque, length: uint ) ``` Copies a block of memory from one location to another. **See also**: <https://learn.microsoft.com/en-us/previous-versions/windows/desktop/legacy/aa366535(v=vs.85)>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Kernel.rux#L415){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------------- | ------------- | ------------------ | | `destination` | `*var opaque` | the bytes to write | | `source` | `*opaque` | the bytes to read | | `length` | `uint` | how many bytes | ## `RtlFillMemory` ```rux pub extern func RtlFillMemory( destination: *opaque, length: uint, fill: int32 ) ``` Fills a block of memory with the specified fill value. **See also**: <https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/nf-wdm-rtlfillmemory>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Kernel.rux#L423){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------------- | --------- | ------------------------- | | `destination` | `*opaque` | the bytes to write | | `length` | `uint` | how many bytes | | `fill` | `int32` | the byte to write to each | ## `RtlZeroMemory` ```rux pub extern func RtlZeroMemory( destination: *opaque, length: uint ) ``` Fills a block of memory with zeros, given a pointer to the block and the length in bytes. **See also**: <https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/nf-wdm-rtlzeromemory>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Kernel.rux#L430){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------------- | --------- | ------------------ | | `destination` | `*opaque` | the bytes to write | | `length` | `uint` | how many bytes | ## `MEM_COMMIT` ```rux pub const MEM_COMMIT: uint32 = 0x00001000; ``` `MEM_COMMIT`: back the range with storage. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Memory.rux#L13){rel=""nofollow""} ## `MEM_RESERVE` ```rux pub const MEM_RESERVE: uint32 = 0x00002000; ``` `MEM_RESERVE`: take the address space without backing it. A reserved page cannot be touched. Touching one faults exactly as an unmapped page does, which is what makes reservation a cheap way to hold a range for later. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Memory.rux#L20){rel=""nofollow""} ## `MEM_RESET` ```rux pub const MEM_RESET: uint32 = 0x00080000; ``` `MEM_RESET`: the contents are no longer of interest and need not be written to the page file. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Memory.rux#L25){rel=""nofollow""} ## `MEM_RELEASE` ```rux pub const MEM_RELEASE: uint32 = 0x00008000; ``` `MEM_RELEASE`: give back the whole reservation, which [`VirtualFree`](https://rux-lang.dev/docs/api/windows/memory#virtual-free) requires a size of zero for. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Memory.rux#L30){rel=""nofollow""} ## `MEM_DECOMMIT` ```rux pub const MEM_DECOMMIT: uint32 = 0x00004000; ``` `MEM_DECOMMIT`: take back the storage but keep the reservation. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Memory.rux#L35){rel=""nofollow""} ## `PAGE_NOACCESS` ```rux pub const PAGE_NOACCESS: uint32 = 0x01; ``` `PAGE_NOACCESS`: the pages may not be touched at all. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Memory.rux#L40){rel=""nofollow""} ## `PAGE_READONLY` ```rux pub const PAGE_READONLY: uint32 = 0x02; ``` `PAGE_READONLY`: the pages may be read. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Memory.rux#L45){rel=""nofollow""} ## `PAGE_READWRITE` ```rux pub const PAGE_READWRITE: uint32 = 0x04; ``` `PAGE_READWRITE`: the pages may be read and written. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Memory.rux#L50){rel=""nofollow""} ## `PAGE_EXECUTE` ```rux pub const PAGE_EXECUTE: uint32 = 0x10; ``` `PAGE_EXECUTE`: the pages may be executed. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Memory.rux#L55){rel=""nofollow""} ## `PAGE_EXECUTE_READ` ```rux pub const PAGE_EXECUTE_READ: uint32 = 0x20; ``` `PAGE_EXECUTE_READ`: the pages may be executed and read. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Memory.rux#L60){rel=""nofollow""} ## `PAGE_EXECUTE_READWRITE` ```rux pub const PAGE_EXECUTE_READWRITE: uint32 = 0x40; ``` `PAGE_EXECUTE_READWRITE`: the pages may be executed, read and written. What a hardened process refuses, and what an exploit needs. Prefer writing through one protection and executing through another. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Memory.rux#L67){rel=""nofollow""} ## `PAGE_GUARD` ```rux pub const PAGE_GUARD: uint32 = 0x100; ``` `PAGE_GUARD`: the next touch raises a one-shot guard exception and then clears the flag. Combined with another protection. This is how a stack grows on Windows. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Memory.rux#L73){rel=""nofollow""} ## `VirtualAlloc` ```rux pub extern func VirtualAlloc( address: *var opaque, size: uint, allocationType: uint32, protect: uint32 ) -> *var opaque ``` Reserves, commits, or changes the state of a region of pages. Returns the base address of the region, or null on failure. A null address argument lets the system choose, which it does at 64 KiB granularity rather than page granularity. **See also**: <https://learn.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-virtualalloc>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Memory.rux#L87){rel=""nofollow""} **Parameters** | Name | Type | Description | | ---------------- | ------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- | | `address` | `*var opaque` | an address in this process | | `size` | `uint` | a size in bytes | | `allocationType` | `uint32` | [`MEM_RESERVE`](https://rux-lang.dev/docs/api/windows/memory#mem-reserve), [`MEM_COMMIT`](https://rux-lang.dev/docs/api/windows/memory#mem-commit), or both | | `protect` | `uint32` | the page protection, as a `PAGE_*` value | **Returns**: the region's base address, or null — not [`InvalidHandleValue`](https://rux-lang.dev/docs/api/windows/types#invalid-handle-value) ## `VirtualFree` ```rux pub extern func VirtualFree( address: *var opaque, size: uint, freeType: uint32 ) -> int32 ``` Releases, decommits, or both, a region of pages. Returns zero on failure. MEM\_RELEASE requires a size of zero and the exact base address VirtualAlloc returned; giving it anything else fails rather than releasing part of the region. **See also**: <https://learn.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-virtualfree>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Memory.rux#L98){rel=""nofollow""} **Parameters** | Name | Type | Description | | ---------- | ------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- | | `address` | `*var opaque` | an address in this process | | `size` | `uint` | a size in bytes | | `freeType` | `uint32` | [`MEM_RELEASE`](https://rux-lang.dev/docs/api/windows/memory#mem-release) or [`MEM_DECOMMIT`](https://rux-lang.dev/docs/api/windows/memory#mem-decommit) | **Returns**: non-zero on success ## `VirtualProtect` ```rux pub extern func VirtualProtect( address: *var opaque, size: uint, newProtect: uint32, oldProtect: *var uint32 ) -> int32 ``` Changes the protection on a region of committed pages. Writes the previous protection through oldProtect, which must not be null. Returns zero on failure. **See also**: <https://learn.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-virtualprotect>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Memory.rux#L109){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------------ | ------------- | ----------------------------------------- | | `address` | `*var opaque` | an address in this process | | `size` | `uint` | a size in bytes | | `newProtect` | `uint32` | the protection to apply | | `oldProtect` | `*var uint32` | receives the protection that was in force | **Returns**: non-zero on success ## `VirtualLock` ```rux pub extern func VirtualLock( address: *var opaque, size: uint ) -> int32 ``` Locks a region into physical memory so it is never written to the page file. The way to keep a secret off the disk. The process working-set limit bounds how much may be locked, so this fails for a large region rather than succeeding slowly. **See also**: <https://learn.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-virtuallock>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Memory.rux#L120){rel=""nofollow""} **Parameters** | Name | Type | Description | | --------- | ------------- | -------------------------- | | `address` | `*var opaque` | an address in this process | | `size` | `uint` | a size in bytes | **Returns**: non-zero on success ## `VirtualUnlock` ```rux pub extern func VirtualUnlock( address: *var opaque, size: uint ) -> int32 ``` Unlocks a region previously locked into physical memory. **See also**: <https://learn.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-virtualunlock>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Memory.rux#L128){rel=""nofollow""} **Parameters** | Name | Type | Description | | --------- | ------------- | -------------------------- | | `address` | `*var opaque` | an address in this process | | `size` | `uint` | a size in bytes | **Returns**: non-zero on success # Processes and threads Exiting, threads, waiting and loading libraries. ## `ALL_PROCESSOR_GROUPS` ```rux pub const ALL_PROCESSOR_GROUPS: uint16 = 0xFFFF; ``` `ALL_PROCESSOR_GROUPS`: asks [`GetActiveProcessorCount`](https://rux-lang.dev/docs/api/windows/process#get-active-processor-count) about every processor group at once. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Constants.rux#L314){rel=""nofollow""} ## `STACK_SIZE_PARAM_IS_A_RESERVATION` ```rux pub const STACK_SIZE_PARAM_IS_A_RESERVATION: uint32 = 0x00010000; ``` `STACK_SIZE_PARAM_IS_A_RESERVATION`: [`CreateThread`](https://rux-lang.dev/docs/api/windows/process#create-thread) takes its stack size as the space to reserve rather than to commit, which is what a stack size usually means. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Constants.rux#L320){rel=""nofollow""} ## `INFINITE` ```rux pub const INFINITE: uint32 = 0xFFFFFFFF; ``` `INFINITE`: a wait with no time-out. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Constants.rux#L325){rel=""nofollow""} ## `ExitProcess` ```rux pub extern func ExitProcess(exitCode: uint32) ``` Ends the calling process and all its threads. **See also**: <https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-exitprocess>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Kernel.rux#L103){rel=""nofollow""} **Parameters** | Name | Type | Description | | ---------- | -------- | -------------------- | | `exitCode` | `uint32` | the status to report | ## `FreeLibrary` ```rux pub extern func FreeLibrary(libModule: *opaque) -> bool32 ``` Frees the loaded dynamic-link library (DLL) module and, if necessary, decrements its reference count. When the reference count reaches zero, the module is unloaded from the address space of the calling process and the handle is no longer valid **See also**: <https://learn.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-freelibrary>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Kernel.rux#L145){rel=""nofollow""} **Parameters** | Name | Type | Description | | ----------- | --------- | --------------------------------------------------------------------------------------------------- | | `libModule` | `*opaque` | a module handle from [`LoadLibraryA`](https://rux-lang.dev/docs/api/windows/process#load-library-a) | **Returns**: non-zero on success, and zero on failure with the reason in [`GetLastError`](https://rux-lang.dev/docs/api/windows/errors#get-last-error) ## `GetCommandLineW` ```rux pub extern func GetCommandLineW() -> *uint16 ``` Retrieves the command line the process was started with, as one string. The string belongs to the process for its whole life and must not be written or freed. It is the command line exactly as the parent passed it, quotes and all; [`CommandLineToArgvW`](https://rux-lang.dev/docs/api/windows/process#command-line-to-argv-w) splits it into arguments. **See also**: <https://learn.microsoft.com/windows/win32/api/processenv/nf-processenv-getcommandlinew>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Kernel.rux#L161){rel=""nofollow""} **Returns**: the NUL-terminated UTF-16 command line, which is never null ## `GetModuleFileNameW` ```rux pub extern func GetModuleFileNameW( moduleHandle: *opaque, buffer: *var uint16, size: uint32 ) -> uint32 ``` Retrieves the full path of the file a module was loaded from; a null module is the process's executable. The path is NUL-terminated when it fits. When it does not, it is cut to `size` units, the last of them the terminator, and the call returns `size`. **See also**: <https://learn.microsoft.com/windows/win32/api/libloaderapi/nf-libloaderapi-getmodulefilenamew>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Kernel.rux#L173){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------------- | ------------- | -------------------------------------- | | `moduleHandle` | `*opaque` | the module, or null for the executable | | `buffer` | `*var uint16` | receives the path | | `size` | `uint32` | how many units `buffer` holds | **Returns**: the path's length without its terminator, `size` when it was cut, or zero on failure with the reason in [`GetLastError`](https://rux-lang.dev/docs/api/windows/errors#get-last-error) ## `GetEnvironmentStringsW` ```rux pub extern func GetEnvironmentStringsW() -> *uint16 ``` Copies the calling process's environment block. The block is a sequence of NUL-terminated `name=value` UTF-16 strings ended by an empty one. It is a copy owned by the caller, released with `FreeEnvironmentStringsW`; changes made to the environment after the call do not appear in it. **See also**: <https://learn.microsoft.com/windows/win32/api/processenv/nf-processenv-getenvironmentstringsw>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Kernel.rux#L190){rel=""nofollow""} **Returns**: the environment block, or null on failure with the reason in [`GetLastError`](https://rux-lang.dev/docs/api/windows/errors#get-last-error) ## `GetCurrentProcessId` ```rux pub extern func GetCurrentProcessId() -> uint32 ``` Retrieves the process identifier of the calling process. **See also**: <https://learn.microsoft.com/windows/win32/api/processthreadsapi/nf-processthreadsapi-getcurrentprocessid>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Kernel.rux#L196){rel=""nofollow""} **Returns**: the calling process's identifier ## `GetActiveProcessorCount` ```rux pub extern func GetActiveProcessorCount(groupNumber: uint16) -> uint32 ``` Retrieves the number of active processors in a processor group, or in all of them. **See also**: <https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-getactiveprocessorcount>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Kernel.rux#L203){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------------- | | `groupNumber` | `uint16` | the processor group, or [`ALL_PROCESSOR_GROUPS`](https://rux-lang.dev/docs/api/windows/process#all-processor-groups) for the whole system | **Returns**: the number of active processors, or zero on failure ## `GetCurrentThreadId` ```rux pub extern func GetCurrentThreadId() -> uint32 pub extern func GetCurrentThreadId() -> uint32 ``` Retrieves the thread identifier of the calling thread. **See also**: <https://learn.microsoft.com/windows/win32/api/processthreadsapi/nf-processthreadsapi-getcurrentthreadid>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Kernel.rux#L209){rel=""nofollow""} **Returns**: the calling thread's identifier ## `GetProcAddress` ```rux pub extern func GetProcAddress( libModule: *opaque, procName: *char8 ) -> *opaque ``` Retrieves the address of an exported symbol. **See also**: <https://learn.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-getprocaddress>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Kernel.rux#L251){rel=""nofollow""} **Parameters** | Name | Type | Description | | ----------- | --------- | --------------------------------------------------------------------------------------------------- | | `libModule` | `*opaque` | a module handle from [`LoadLibraryA`](https://rux-lang.dev/docs/api/windows/process#load-library-a) | | `procName` | `*char8` | the exported symbol's name | **Returns**: the symbol's address, or null ## `LoadLibraryA` ```rux pub extern func LoadLibraryA(libFileName: *char8) -> *opaque ``` Loads a DLL into the calling process. **See also**: <https://learn.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibrarya>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Kernel.rux#L311){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------------- | -------- | -------------------------- | | `libFileName` | `*char8` | the library's name or path | **Returns**: the module's handle, or null ## `CreateThread` ```rux pub extern func CreateThread( securityAttributes: *opaque, stackSize: uint64, startAddress: *opaque, parameter: *opaque, creationFlags: uint32, threadId: *uint32 ) -> *opaque ``` Creates a thread to execute within the virtual address space of the calling process. **See also**: <https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-createthread>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Kernel.rux#L472){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------------------- | --------- | ----------------------------------------------- | | `securityAttributes` | `*opaque` | a security descriptor, or null for the default | | `stackSize` | `uint64` | the initial stack size, or zero for the default | | `startAddress` | `*opaque` | the thread's entry point | | `parameter` | `*opaque` | the value handed to the entry point | | `creationFlags` | `uint32` | the thread creation flags | | `threadId` | `*uint32` | receives the new thread's identifier, or null | **Returns**: the new thread's handle, or null ## `Sleep` ```rux pub extern func Sleep(milliseconds: uint32) ``` Suspends the execution of the current thread until the time-out interval elapses. **See also**: <https://learn.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-sleep>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Kernel.rux#L491){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------------- | -------- | -------------------------- | | `milliseconds` | `uint32` | a duration in milliseconds | ## `SwitchToThread` ```rux pub extern func SwitchToThread() -> bool32 ``` Causes the calling thread to yield execution to another thread that is ready to run. **See also**: <https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-switchtothread>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Kernel.rux#L497){rel=""nofollow""} **Returns**: non-zero on success, and zero on failure with the reason in [`GetLastError`](https://rux-lang.dev/docs/api/windows/errors#get-last-error) ## `WaitForSingleObject` ```rux pub extern func WaitForSingleObject( handle: *opaque, milliseconds: uint32 ) -> uint32 ``` Waits until the specified object is in the signaled state or the time-out interval elapses. **See also**: <https://learn.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-waitforsingleobject>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Kernel.rux#L505){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------------- | --------- | -------------------------- | | `handle` | `*opaque` | the handle to act on | | `milliseconds` | `uint32` | a duration in milliseconds | **Returns**: why the wait ended ## `CommandLineToArgvW` ```rux pub extern func CommandLineToArgvW( commandLine: *uint16, count: *var int32 ) -> **uint16 ``` Splits a command line into arguments the way the C runtime does. Backslashes, quotes and spaces follow the C runtime's rules, and the first argument, the program, is read up to the first space outside quotes. The result is one allocation holding the pointer array and every argument; it stays valid until passed to `LocalFree`. **See also**: <https://learn.microsoft.com/windows/win32/api/shellapi/nf-shellapi-commandlinetoargvw>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Shell.rux#L17){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------------- | ------------ | ------------------------------------------------------------------------------------------------------------------------------------------ | | `commandLine` | `*uint16` | the NUL-terminated UTF-16 command line, usually from [`GetCommandLineW`](https://rux-lang.dev/docs/api/windows/process#get-command-line-w) | | `count` | `*var int32` | receives how many arguments the array holds | **Returns**: the array of NUL-terminated UTF-16 arguments, or null on failure with the reason in [`GetLastError`](https://rux-lang.dev/docs/api/windows/errors#get-last-error) # Process control Starting processes with [`CreateProcessW`](https://rux-lang.dev/docs/api/windows/process-control#create-process-w), their startup information, inherited handles and waits. ## `SecurityAttributes` ```rux pub struct SecurityAttributes { pub length: uint32; pub securityDescriptor: *opaque; pub inheritHandle: bool32; } ``` The `SECURITY_ATTRIBUTES` a pipe or file is created with: here only whether its handle is inheritable. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/ProcessControl.rux#L7){rel=""nofollow""} **Fields** | Name | Type | Description | | -------------------- | --------- | ----------------------------------------------------- | | `length` | `uint32` | The structure's size in bytes. | | `securityDescriptor` | `*opaque` | A security descriptor, or null for the default. | | `inheritHandle` | `bool32` | Non-zero when a child process may inherit the handle. | ## `StartupInfo` ```rux pub struct StartupInfo { pub size: uint32; pub reserved: *opaque; pub desktop: *uint16; pub title: *uint16; pub x: uint32; pub y: uint32; pub xSize: uint32; pub ySize: uint32; pub xCountChars: uint32; pub yCountChars: uint32; pub fillAttribute: uint32; pub flags: uint32; pub showWindow: uint16; pub reserved2Size: uint16; pub reserved2: *opaque; pub standardInput: *opaque; pub standardOutput: *opaque; pub standardError: *opaque; } ``` The `STARTUPINFOW` a new process is started with; this package fills in its standard handles. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/ProcessControl.rux#L18){rel=""nofollow""} **Fields** | Name | Type | Description | | ---------------- | --------- | -------------------------------------------------------------------------------------------------------------------------------------------- | | `size` | `uint32` | The structure's size in bytes. | | `reserved` | `*opaque` | Reserved; null. | | `desktop` | `*uint16` | The desktop, or null. | | `title` | `*uint16` | The console title, or null. | | `x` | `uint32` | The window's left edge, when `flags` says so. | | `y` | `uint32` | The window's top edge, when `flags` says so. | | `xSize` | `uint32` | The window's width, when `flags` says so. | | `ySize` | `uint32` | The window's height, when `flags` says so. | | `xCountChars` | `uint32` | The console buffer's width in characters, when `flags` says so. | | `yCountChars` | `uint32` | The console buffer's height in characters, when `flags` says so. | | `fillAttribute` | `uint32` | The console's text and background colors, when `flags` says so. | | `flags` | `uint32` | Which fields the system reads, such as [`STARTF_USESTDHANDLES`](https://rux-lang.dev/docs/api/windows/process-control#startf-usestdhandles). | | `showWindow` | `uint16` | How the window is shown, when `flags` says so. | | `reserved2Size` | `uint16` | Reserved; zero. | | `reserved2` | `*opaque` | Reserved; null. | | `standardInput` | `*opaque` | The child's standard input. | | `standardOutput` | `*opaque` | The child's standard output. | | `standardError` | `*opaque` | The child's standard error. | ## `ProcessInformation` ```rux pub struct ProcessInformation { pub process: *opaque; pub thread: *opaque; pub processId: uint32; pub threadId: uint32; } ``` The `PROCESS_INFORMATION` [`CreateProcessW`](https://rux-lang.dev/docs/api/windows/process-control#create-process-w) fills in: the new process and its first thread. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/ProcessControl.rux#L59){rel=""nofollow""} **Fields** | Name | Type | Description | | ----------- | --------- | ----------------------------------------------- | | `process` | `*opaque` | The new process's handle, to wait on and close. | | `thread` | `*opaque` | Its first thread's handle, to close. | | `processId` | `uint32` | The process identifier. | | `threadId` | `uint32` | The first thread's identifier. | ## `STARTF_USESTDHANDLES` ```rux pub const STARTF_USESTDHANDLES: uint32 = 0x00000100; ``` `STARTF_USESTDHANDLES`: the standard handles in [`StartupInfo`](https://rux-lang.dev/docs/api/windows/process-control#startup-info) are the child's. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/ProcessControl.rux#L73){rel=""nofollow""} ## `CREATE_UNICODE_ENVIRONMENT` ```rux pub const CREATE_UNICODE_ENVIRONMENT: uint32 = 0x00000400; ``` `CREATE_UNICODE_ENVIRONMENT`: the environment block is UTF-16. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/ProcessControl.rux#L78){rel=""nofollow""} ## `HANDLE_FLAG_INHERIT` ```rux pub const HANDLE_FLAG_INHERIT: uint32 = 0x00000001; ``` `HANDLE_FLAG_INHERIT`: the handle is inherited by child processes. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/ProcessControl.rux#L83){rel=""nofollow""} ## `DUPLICATE_SAME_ACCESS` ```rux pub const DUPLICATE_SAME_ACCESS: uint32 = 0x00000002; ``` `DUPLICATE_SAME_ACCESS`: a duplicated handle has the access of the original. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/ProcessControl.rux#L88){rel=""nofollow""} ## `WAIT_TIMEOUT` ```rux pub const WAIT_TIMEOUT: uint32 = 0x00000102; ``` `WAIT_TIMEOUT`: a wait ended because its time ran out. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/ProcessControl.rux#L93){rel=""nofollow""} ## `ERROR_BROKEN_PIPE` ```rux pub const ERROR_BROKEN_PIPE: uint32 = 109; ``` `ERROR_BROKEN_PIPE`: the other end of the pipe was closed. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/ProcessControl.rux#L98){rel=""nofollow""} ## `CreateProcessW` ```rux pub extern func CreateProcessW( applicationName: *uint16, commandLine: *var uint16, processAttributes: *SecurityAttributes, threadAttributes: *SecurityAttributes, inheritHandles: bool32, creationFlags: uint32, environment: *opaque, currentDirectory: *uint16, startupInfo: *StartupInfo, processInformation: *var ProcessInformation ) -> bool32 ``` Starts a program as a new process. **See also**: <https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-createprocessw>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/ProcessControl.rux#L116){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------------------- | ------------------------- | ------------------------------------------------------------------------------------------------------------------------------ | | `applicationName` | `*uint16` | the program's path, or null to take it from the command line | | `commandLine` | `*var uint16` | the command line, which the call may modify | | `processAttributes` | `*SecurityAttributes` | the process handle's security, or null | | `threadAttributes` | `*SecurityAttributes` | the thread handle's security, or null | | `inheritHandles` | `bool32` | non-zero to let the child inherit the parent's inheritable handles | | `creationFlags` | `uint32` | flags such as [`CREATE_UNICODE_ENVIRONMENT`](https://rux-lang.dev/docs/api/windows/process-control#create-unicode-environment) | | `environment` | `*opaque` | the environment block, or null to inherit the parent's | | `currentDirectory` | `*uint16` | the child's working directory, or null for the parent's | | `startupInfo` | `*StartupInfo` | how the child starts, including its standard handles | | `processInformation` | `*var ProcessInformation` | receives the new process and thread | **Returns**: non-zero on success, and zero on failure with the reason in [`GetLastError`](https://rux-lang.dev/docs/api/windows/errors#get-last-error) ## `GetExitCodeProcess` ```rux pub extern func GetExitCodeProcess( process: *opaque, exitCode: *var uint32 ) -> bool32 ``` Reads a process's exit code, or `STILL_ACTIVE` while it runs. **See also**: <https://learn.microsoft.com/windows/win32/api/processthreadsapi/nf-processthreadsapi-getexitcodeprocess>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/ProcessControl.rux#L127){rel=""nofollow""} **Parameters** | Name | Type | Description | | ---------- | ------------- | ------------------ | | `process` | `*opaque` | the process handle | | `exitCode` | `*var uint32` | receives the code | **Returns**: non-zero on success, and zero on failure with the reason in [`GetLastError`](https://rux-lang.dev/docs/api/windows/errors#get-last-error) ## `TerminateProcess` ```rux pub extern func TerminateProcess( process: *opaque, exitCode: uint32 ) -> bool32 ``` Ends a process and all its threads. **See also**: <https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-terminateprocess>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/ProcessControl.rux#L135){rel=""nofollow""} **Parameters** | Name | Type | Description | | ---------- | --------- | ------------------------------ | | `process` | `*opaque` | the process handle | | `exitCode` | `uint32` | the code the process ends with | **Returns**: non-zero on success, and zero on failure with the reason in [`GetLastError`](https://rux-lang.dev/docs/api/windows/errors#get-last-error) ## `CreatePipe` ```rux pub extern func CreatePipe( readPipe: *var *opaque, writePipe: *var *opaque, attributes: *SecurityAttributes, size: uint32 ) -> bool32 ``` Creates an anonymous pipe. **See also**: <https://learn.microsoft.com/en-us/windows/win32/api/namedpipeapi/nf-namedpipeapi-createpipe>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/ProcessControl.rux#L145){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------------ | --------------------- | --------------------------------------------------- | | `readPipe` | `*var *opaque` | receives the read end | | `writePipe` | `*var *opaque` | receives the write end | | `attributes` | `*SecurityAttributes` | whether the ends are inheritable, or null | | `size` | `uint32` | the buffer size suggestion, or zero for the default | **Returns**: non-zero on success, and zero on failure with the reason in [`GetLastError`](https://rux-lang.dev/docs/api/windows/errors#get-last-error) ## `SetHandleInformation` ```rux pub extern func SetHandleInformation( handle: *opaque, mask: uint32, flags: uint32 ) -> bool32 ``` Changes a handle's flags, such as whether it is inherited. **See also**: <https://learn.microsoft.com/en-us/windows/win32/api/handleapi/nf-handleapi-sethandleinformation>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/ProcessControl.rux#L155){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | --------- | ------------------- | | `handle` | `*opaque` | the handle | | `mask` | `uint32` | the flags to change | | `flags` | `uint32` | their new values | **Returns**: non-zero on success, and zero on failure with the reason in [`GetLastError`](https://rux-lang.dev/docs/api/windows/errors#get-last-error) ## `DuplicateHandle` ```rux pub extern func DuplicateHandle( sourceProcess: *opaque, sourceHandle: *opaque, targetProcess: *opaque, targetHandle: *var *opaque, desiredAccess: uint32, inheritHandle: bool32, options: uint32 ) -> bool32 ``` Duplicates a handle, here into the same process with different inheritance. **See also**: <https://learn.microsoft.com/en-us/windows/win32/api/handleapi/nf-handleapi-duplicatehandle>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/ProcessControl.rux#L168){rel=""nofollow""} **Parameters** | Name | Type | Description | | --------------- | -------------- | ---------------------------------------------------------------------------------------------------------------------------------------- | | `sourceProcess` | `*opaque` | the process that owns the handle | | `sourceHandle` | `*opaque` | the handle | | `targetProcess` | `*opaque` | the process to duplicate it into | | `targetHandle` | `*var *opaque` | receives the duplicate | | `desiredAccess` | `uint32` | the access to grant, ignored with [`DUPLICATE_SAME_ACCESS`](https://rux-lang.dev/docs/api/windows/process-control#duplicate-same-access) | | `inheritHandle` | `bool32` | non-zero to make the duplicate inheritable | | `options` | `uint32` | flags such as [`DUPLICATE_SAME_ACCESS`](https://rux-lang.dev/docs/api/windows/process-control#duplicate-same-access) | **Returns**: non-zero on success, and zero on failure with the reason in [`GetLastError`](https://rux-lang.dev/docs/api/windows/errors#get-last-error) ## `GetCurrentProcess` ```rux pub extern func GetCurrentProcess() -> *opaque ``` Returns a pseudo-handle for the calling process, which needs no closing. **See also**: <https://learn.microsoft.com/windows/win32/api/processthreadsapi/nf-processthreadsapi-getcurrentprocess>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/ProcessControl.rux#L176){rel=""nofollow""} **Returns**: the pseudo-handle ## `SetEnvironmentVariableW` ```rux pub extern func SetEnvironmentVariableW( name: *uint16, value: *uint16 ) -> bool32 ``` Sets or removes an environment variable of the calling process. **See also**: <https://learn.microsoft.com/en-us/windows/win32/api/processenv/nf-processenv-setenvironmentvariablew>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/ProcessControl.rux#L184){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------- | --------- | --------------------------------------------------- | | `name` | `*uint16` | the variable's name, NUL-terminated | | `value` | `*uint16` | its new value, NUL-terminated, or null to remove it | **Returns**: non-zero on success, and zero on failure with the reason in [`GetLastError`](https://rux-lang.dev/docs/api/windows/errors#get-last-error) # Address waits [`WaitOnAddress`](https://rux-lang.dev/docs/api/windows/synch#wait-on-address) and the calls that wake its waiters. ## `WaitOnAddress` ```rux pub extern func WaitOnAddress( address: *opaque, compareAddress: *opaque, addressSize: uint64, milliseconds: uint32 ) -> bool32 ``` Waits for the value at an address to change. **See also**: <https://learn.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-waitonaddress>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Synch.rux#L16){rel=""nofollow""} **Parameters** | Name | Type | Description | | ---------------- | --------- | ------------------------------------------------------------------------------------------------- | | `address` | `*opaque` | the value to wait on | | `compareAddress` | `*opaque` | a copy of the value the caller last saw; the wait ends at once when they differ | | `addressSize` | `uint64` | the value's size in bytes: 1, 2, 4 or 8 | | `milliseconds` | `uint32` | how long to wait at most, or [`INFINITE`](https://rux-lang.dev/docs/api/windows/process#infinite) | **Returns**: non-zero after a wake, and zero on time-out or failure with the reason in [`GetLastError`](https://rux-lang.dev/docs/api/windows/errors#get-last-error) ## `WakeByAddressSingle` ```rux pub extern func WakeByAddressSingle(address: *opaque) ``` Wakes one thread waiting on an address. **See also**: <https://learn.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-wakebyaddresssingle>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Synch.rux#L22){rel=""nofollow""} **Parameters** | Name | Type | Description | | --------- | --------- | --------------------- | | `address` | `*opaque` | the value it waits on | ## `WakeByAddressAll` ```rux pub extern func WakeByAddressAll(address: *opaque) ``` Wakes every thread waiting on an address. **See also**: <https://learn.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-wakebyaddressall>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Synch.rux#L28){rel=""nofollow""} **Parameters** | Name | Type | Description | | --------- | --------- | ---------------------- | | `address` | `*opaque` | the value they wait on | # Text conversion Converting between code pages and UTF-16. ## `MultiByteToWideChar` ```rux pub extern func MultiByteToWideChar( codePage: CodePage, flags: uint32, multiByteStr: *char8, multiByte: int32, wideCharStr: *char16, wideChar: int32 ) -> int32 pub extern func MultiByteToWideChar( codePage: uint32, flags: uint32, multiByteStr: *char8, multiByte: int32, wideCharStr: *char16, wideChar: int32 ) -> int32 ``` Maps a character string to a UTF-16 wide character string. **See also**: <https://learn.microsoft.com/en-us/windows/win32/api/stringapiset/nf-stringapiset-multibytetowidechar>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Kernel.rux#L331){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------------- | --------------------- | ---------------------------------------------------------------------------------------------------------- | | `codePage` | `CodePage` / `uint32` | the code page to convert through, as a [`CodePage`](https://rux-lang.dev/docs/api/windows/code-page) value | | `flags` | `uint32` | the call's flag bits, combined with `|` | | `multiByteStr` | `*char8` | the bytes to convert | | `multiByte` | `int32` | how many bytes, or -1 to stop at the terminator | | `wideCharStr` | `*char16` | receives the UTF-16 units, or null to ask how many are needed | | `wideChar` | `int32` | how many units the output holds, or zero to ask | **Returns**: the units written, the units needed when asked, or zero on failure ## `WideCharToMultiByte` ```rux pub extern func WideCharToMultiByte( codePage: uint32, flags: uint32, wideCharStr: *char16, wideChar: int32, multiByteStr: *char8, multiByte: int32, defaultChar: *char8, usedDefaultChar: *bool32 ) -> int32 ``` Converts UTF-16 text to another code page. **See also**: <https://learn.microsoft.com/en-us/windows/win32/api/stringapiset/nf-stringapiset-widechartomultibyte>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Kernel.rux#L519){rel=""nofollow""} **Parameters** | Name | Type | Description | | ----------------- | --------- | ---------------------------------------------------------------------------------------------------------- | | `codePage` | `uint32` | the code page to convert through, as a [`CodePage`](https://rux-lang.dev/docs/api/windows/code-page) value | | `flags` | `uint32` | the call's flag bits, combined with `|` | | `wideCharStr` | `*char16` | receives the UTF-16 units, or null to ask how many are needed | | `wideChar` | `int32` | how many units the output holds, or zero to ask | | `multiByteStr` | `*char8` | the bytes to convert | | `multiByte` | `int32` | how many bytes, or -1 to stop at the terminator | | `defaultChar` | `*char8` | the byte to substitute for an unconvertible unit, or null | | `usedDefaultChar` | `*bool32` | receives whether any substitution happened, or null | **Returns**: the bytes written, the bytes needed when asked, or zero on failure # Errors The last Win32 error and the codes it reports. ## `ERROR_SUCCESS` ```rux pub const ERROR_SUCCESS: uint32 = 0; ``` `ERROR_SUCCESS`: the operation succeeded, which is the value [`GetLastError`](https://rux-lang.dev/docs/api/windows/errors#get-last-error) reports when nothing has failed. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Errors.rux#L14){rel=""nofollow""} ## `ERROR_FILE_NOT_FOUND` ```rux pub const ERROR_FILE_NOT_FOUND: uint32 = 2; ``` `ERROR_FILE_NOT_FOUND`: the named file does not exist. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Errors.rux#L19){rel=""nofollow""} ## `ERROR_PATH_NOT_FOUND` ```rux pub const ERROR_PATH_NOT_FOUND: uint32 = 3; ``` `ERROR_PATH_NOT_FOUND`: a directory along the path does not exist. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Errors.rux#L24){rel=""nofollow""} ## `ERROR_ACCESS_DENIED` ```rux pub const ERROR_ACCESS_DENIED: uint32 = 5; ``` `ERROR_ACCESS_DENIED`: the caller does not have the rights the operation needs. Also what a sharing violation looks like when the file is already open without the matching share mode. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Errors.rux#L30){rel=""nofollow""} ## `ERROR_INVALID_HANDLE` ```rux pub const ERROR_INVALID_HANDLE: uint32 = 6; ``` `ERROR_INVALID_HANDLE`: the handle is not one this operation can use. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Errors.rux#L35){rel=""nofollow""} ## `ERROR_NOT_ENOUGH_MEMORY` ```rux pub const ERROR_NOT_ENOUGH_MEMORY: uint32 = 8; ``` `ERROR_NOT_ENOUGH_MEMORY`: not enough storage to complete the operation. Distinct from [`ERROR_OUTOFMEMORY`](https://rux-lang.dev/docs/api/windows/errors#error-out-of-memory), and which of the two a call reports is the call's own business, so a caller checking for exhaustion has to accept either. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Errors.rux#L42){rel=""nofollow""} ## `ERROR_OUTOFMEMORY` ```rux pub const ERROR_OUTOFMEMORY: uint32 = 14; ``` `ERROR_OUTOFMEMORY`: not enough storage to complete the operation. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Errors.rux#L47){rel=""nofollow""} ## `ERROR_NOT_SUPPORTED` ```rux pub const ERROR_NOT_SUPPORTED: uint32 = 50; ``` `ERROR_NOT_SUPPORTED`: the operation is not supported on this object or this system. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Errors.rux#L52){rel=""nofollow""} ## `ERROR_FILE_EXISTS` ```rux pub const ERROR_FILE_EXISTS: uint32 = 80; ``` `ERROR_FILE_EXISTS`: the file already exists, and the call was told not to replace it. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Errors.rux#L57){rel=""nofollow""} ## `ERROR_INVALID_PARAMETER` ```rux pub const ERROR_INVALID_PARAMETER: uint32 = 87; ``` `ERROR_INVALID_PARAMETER`: an argument is not valid. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Errors.rux#L62){rel=""nofollow""} ## `ERROR_DISK_FULL` ```rux pub const ERROR_DISK_FULL: uint32 = 112; ``` `ERROR_DISK_FULL`: the volume has no room left. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Errors.rux#L67){rel=""nofollow""} ## `ERROR_PRIVILEGE_NOT_HELD` ```rux pub const ERROR_PRIVILEGE_NOT_HELD: uint32 = 1314; ``` `ERROR_PRIVILEGE_NOT_HELD`: the account lacks a privilege the operation requires. What refuses [`CreateSymbolicLinkW`](https://rux-lang.dev/docs/api/windows/file-system#create-symbolic-link-w) on a machine without Developer Mode, where creating a symbolic link needs `SeCreateSymbolicLinkPrivilege` — a restriction no other supported system places on the same operation. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Errors.rux#L74){rel=""nofollow""} ## `ERROR_NO_MORE_FILES` ```rux pub const ERROR_NO_MORE_FILES: uint32 = 18; ``` `ERROR_NO_MORE_FILES`: a directory enumeration has handed over its last entry. Reported by [`FindNextFileW`](https://rux-lang.dev/docs/api/windows/file-system#find-next-file-w) at the end of an enumeration, where nothing has gone wrong at all — the caller distinguishes it from a real failure by this code. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Errors.rux#L81){rel=""nofollow""} ## `ERROR_ALREADY_EXISTS` ```rux pub const ERROR_ALREADY_EXISTS: uint32 = 183; ``` `ERROR_ALREADY_EXISTS`: the object already exists. Reported by [`CreateDirectoryW`](https://rux-lang.dev/docs/api/windows/file-system#create-directory-w) where [`ERROR_FILE_EXISTS`](https://rux-lang.dev/docs/api/windows/errors#error-file-exists) is reported by the file calls, which is why a caller asking "was it already there" has to accept both. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Errors.rux#L88){rel=""nofollow""} ## `ERROR_INVALID_ADDRESS` ```rux pub const ERROR_INVALID_ADDRESS: uint32 = 487; ``` `ERROR_INVALID_ADDRESS`: the address is not one the operation can use. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Errors.rux#L93){rel=""nofollow""} ## `ERROR_COMMITMENT_LIMIT` ```rux pub const ERROR_COMMITMENT_LIMIT: uint32 = 1455; ``` `ERROR_COMMITMENT_LIMIT`: the system's commit limit is reached, so nothing more can be backed. What a large commit fails with when the page file cannot grow, as distinct from running out of address space. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Errors.rux#L99){rel=""nofollow""} ## `GetLastError` ```rux pub extern func GetLastError() -> uint32 ``` Retrieves the calling thread's last-error code value. **See also**: <https://learn.microsoft.com/en-us/windows/win32/api/errhandlingapi/nf-errhandlingapi-getlasterror>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Kernel.rux#L237){rel=""nofollow""} **Returns**: the calling thread's last error code, which only a documented failure sets # Winsock Starting Winsock, address families, sockets and their options, and name resolution. ## `WsaData` ```rux pub struct WsaData { // private fields } ``` Room for a `WSADATA`, which [`WSAStartup`](https://rux-lang.dev/docs/api/windows/winsock#wsa-startup) fills and nothing here reads. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Winsock.rux#L7){rel=""nofollow""} **Constructors** ### `WsaData` ```rux pub func WsaData() -> WsaData ``` Zeroed storage for [`WSAStartup`](https://rux-lang.dev/docs/api/windows/winsock#wsa-startup) to fill. **Returns**: the storage [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Winsock.rux#L15){rel=""nofollow""} ## `AddressInfo` ```rux pub struct AddressInfo { pub flags: int32; pub family: int32; pub socketType: int32; pub protocol: int32; pub addressLength: uint64; pub canonicalName: *char8; pub address: *opaque; pub next: *var AddressInfo; } ``` Winsock's `addrinfo`: one result of [`getaddrinfo`](https://rux-lang.dev/docs/api/windows/winsock#getaddrinfo), linked to the next. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Winsock.rux#L22){rel=""nofollow""} **Fields** | Name | Type | Description | | --------------- | ------------------ | ---------------------------------------- | | `flags` | `int32` | Flags such as `AI_PASSIVE`. | | `family` | `int32` | The address family, or zero for any. | | `socketType` | `int32` | The socket type, or zero for any. | | `protocol` | `int32` | The protocol, or zero for any. | | `addressLength` | `uint64` | The size of `address` in bytes. | | `canonicalName` | `*char8` | The host's canonical name, or null. | | `address` | `*opaque` | The address, a `sockaddr`. | | `next` | `*var AddressInfo` | The next result, or null after the last. | ## `AF_INET` ```rux pub const AF_INET: int32 = 2; ``` `AF_INET`: the IPv4 address family. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Winsock.rux#L44){rel=""nofollow""} ## `AF_INET6` ```rux pub const AF_INET6: int32 = 23; ``` `AF_INET6`: the IPv6 address family. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Winsock.rux#L49){rel=""nofollow""} ## `SOCK_STREAM` ```rux pub const SOCK_STREAM: int32 = 1; ``` `SOCK_STREAM`: a connected byte stream. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Winsock.rux#L54){rel=""nofollow""} ## `SOCK_DGRAM` ```rux pub const SOCK_DGRAM: int32 = 2; ``` `SOCK_DGRAM`: individual datagrams. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Winsock.rux#L59){rel=""nofollow""} ## `SOL_SOCKET` ```rux pub const SOL_SOCKET: int32 = 0xFFFF; ``` `SOL_SOCKET`: the level of the options every socket has. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Winsock.rux#L64){rel=""nofollow""} ## `SO_RCVTIMEO` ```rux pub const SO_RCVTIMEO: int32 = 0x1006; ``` `SO_RCVTIMEO`: how long a receive waits, in milliseconds. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Winsock.rux#L69){rel=""nofollow""} ## `SO_SNDTIMEO` ```rux pub const SO_SNDTIMEO: int32 = 0x1005; ``` `SO_SNDTIMEO`: how long a send waits, in milliseconds. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Winsock.rux#L74){rel=""nofollow""} ## `IPPROTO_TCP` ```rux pub const IPPROTO_TCP: int32 = 6; ``` `IPPROTO_TCP`: the level of TCP's options. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Winsock.rux#L79){rel=""nofollow""} ## `TCP_NODELAY` ```rux pub const TCP_NODELAY: int32 = 1; ``` `TCP_NODELAY`: send small writes at once rather than gathering them. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Winsock.rux#L84){rel=""nofollow""} ## `IPPROTO_IPV6` ```rux pub const IPPROTO_IPV6: int32 = 41; ``` `IPPROTO_IPV6`: the level of IPv6's options. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Winsock.rux#L89){rel=""nofollow""} ## `IPV6_V6ONLY` ```rux pub const IPV6_V6ONLY: int32 = 27; ``` `IPV6_V6ONLY`: accept only IPv6 on an IPv6 socket. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Winsock.rux#L94){rel=""nofollow""} ## `INVALID_SOCKET` ```rux pub const INVALID_SOCKET: uint64 = 0xFFFFFFFFFFFFFFFF; ``` `INVALID_SOCKET`: what a call that makes a socket returns on failure. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Winsock.rux#L99){rel=""nofollow""} ## `FIONBIO` ```rux pub const FIONBIO: int32 = -2147195266; ``` `FIONBIO`: the [`ioctlsocket`](https://rux-lang.dev/docs/api/windows/winsock#ioctlsocket) command that turns a socket's non-blocking mode on or off. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Winsock.rux#L104){rel=""nofollow""} ## `POLLRDNORM` ```rux pub const POLLRDNORM: int16 = 0x100; ``` `POLLRDNORM`: [`WSAPoll`](https://rux-lang.dev/docs/api/windows/winsock#wsa-poll) reports a socket with data to read, or a connection to accept. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Winsock.rux#L109){rel=""nofollow""} ## `POLLWRNORM` ```rux pub const POLLWRNORM: int16 = 0x10; ``` `POLLWRNORM`: [`WSAPoll`](https://rux-lang.dev/docs/api/windows/winsock#wsa-poll) reports a socket a write would not wait on. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Winsock.rux#L114){rel=""nofollow""} ## `POLLERR` ```rux pub const POLLERR: int16 = 0x1; ``` `POLLERR`: the socket has an error pending; always reported. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Winsock.rux#L119){rel=""nofollow""} ## `POLLHUP` ```rux pub const POLLHUP: int16 = 0x2; ``` `POLLHUP`: the connection was closed; always reported. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Winsock.rux#L124){rel=""nofollow""} ## `POLLNVAL` ```rux pub const POLLNVAL: int16 = 0x4; ``` `POLLNVAL`: the socket is not valid; always reported. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Winsock.rux#L129){rel=""nofollow""} ## `WsaPollFd` ```rux pub struct WsaPollFd { pub socket: uint64; pub events: int16; pub returned: int16; } ``` `WSAPOLLFD`: one socket [`WSAPoll`](https://rux-lang.dev/docs/api/windows/winsock#wsa-poll) watches, the events wanted, and the events it reports. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Winsock.rux#L133){rel=""nofollow""} **Fields** | Name | Type | Description | | ---------- | -------- | -------------------------------------------------------------------------------------------------------- | | `socket` | `uint64` | The socket. | | `events` | `int16` | The events wanted, such as [`POLLRDNORM`](https://rux-lang.dev/docs/api/windows/winsock#pollrdnorm). | | `returned` | `int16` | The events that happened, filled by [`WSAPoll`](https://rux-lang.dev/docs/api/windows/winsock#wsa-poll). | ## `WSAStartup` ```rux pub extern func WSAStartup( version: uint16, data: *var WsaData ) -> int32 ``` Starts Winsock for this process. **See also**: <https://learn.microsoft.com/en-us/windows/win32/api/winsock/nf-winsock-wsastartup>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Winsock.rux#L150){rel=""nofollow""} **Parameters** | Name | Type | Description | | --------- | -------------- | -------------------------------------- | | `version` | `uint16` | the version wanted, `0x0202` for 2.2 | | `data` | `*var WsaData` | receives details of the implementation | **Returns**: zero, or an error code ## `WSAGetLastError` ```rux pub extern func WSAGetLastError() -> int32 ``` The calling thread's last Winsock error. **See also**: <https://learn.microsoft.com/en-us/windows/win32/api/winsock/nf-winsock-wsagetlasterror>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Winsock.rux#L156){rel=""nofollow""} **Returns**: the error code ## `socket` ```rux pub extern func socket( family: int32, kind: int32, protocol: int32 ) -> uint64 ``` Opens a socket. **See also**: <https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-socket>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Winsock.rux#L165){rel=""nofollow""} **Parameters** | Name | Type | Description | | ---------- | ------- | --------------------- | | `family` | `int32` | the address family | | `kind` | `int32` | the socket type | | `protocol` | `int32` | the protocol, or zero | **Returns**: the socket, or [`INVALID_SOCKET`](https://rux-lang.dev/docs/api/windows/winsock#invalid-socket) ## `connect` ```rux pub extern func connect( socket: uint64, address: *opaque, length: int32 ) -> int32 ``` Connects a socket to `address`. **See also**: <https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-connect>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Winsock.rux#L174){rel=""nofollow""} **Parameters** | Name | Type | Description | | --------- | --------- | ------------------------- | | `socket` | `uint64` | the socket | | `address` | `*opaque` | the address, a `sockaddr` | | `length` | `int32` | the address's size | **Returns**: zero, or -1 with the reason in [`WSAGetLastError`](https://rux-lang.dev/docs/api/windows/winsock#wsa-get-last-error) ## `bind` ```rux pub extern func bind( socket: uint64, address: *opaque, length: int32 ) -> int32 ``` Gives a socket its local address. **See also**: <https://learn.microsoft.com/en-us/windows/win32/api/winsock/nf-winsock-bind>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Winsock.rux#L183){rel=""nofollow""} **Parameters** | Name | Type | Description | | --------- | --------- | ------------------------- | | `socket` | `uint64` | the socket | | `address` | `*opaque` | the address, a `sockaddr` | | `length` | `int32` | the address's size | **Returns**: zero, or -1 with the reason in [`WSAGetLastError`](https://rux-lang.dev/docs/api/windows/winsock#wsa-get-last-error) ## `listen` ```rux pub extern func listen( socket: uint64, backlog: int32 ) -> int32 ``` Makes a bound stream socket accept connections. **See also**: <https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-listen>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Winsock.rux#L191){rel=""nofollow""} **Parameters** | Name | Type | Description | | --------- | -------- | ----------------------------- | | `socket` | `uint64` | the socket | | `backlog` | `int32` | how many connections may wait | **Returns**: zero, or -1 with the reason in [`WSAGetLastError`](https://rux-lang.dev/docs/api/windows/winsock#wsa-get-last-error) ## `accept` ```rux pub extern func accept( socket: uint64, address: *var opaque, length: *var int32 ) -> uint64 ``` Accepts a waiting connection. **See also**: <https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-accept>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Winsock.rux#L200){rel=""nofollow""} **Parameters** | Name | Type | Description | | --------- | ------------- | ---------------------------------------------- | | `socket` | `uint64` | the listening socket | | `address` | `*var opaque` | receives the peer's address, or null | | `length` | `*var int32` | the buffer's size, then the address's, or null | **Returns**: the new socket, or [`INVALID_SOCKET`](https://rux-lang.dev/docs/api/windows/winsock#invalid-socket) ## `sendto` ```rux pub extern func sendto( socket: uint64, buffer: *opaque, count: int32, flags: int32, address: *opaque, length: int32 ) -> int32 ``` Sends bytes on a socket, to `address` when it is not connected. **See also**: <https://learn.microsoft.com/en-us/windows/win32/api/winsock/nf-winsock-sendto>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Winsock.rux#L212){rel=""nofollow""} **Parameters** | Name | Type | Description | | --------- | --------- | ------------------------ | | `socket` | `uint64` | the socket | | `buffer` | `*opaque` | the bytes | | `count` | `int32` | how many | | `flags` | `int32` | flags, or zero | | `address` | `*opaque` | the destination, or null | | `length` | `int32` | the destination's size | **Returns**: the bytes sent, or -1 with the reason in [`WSAGetLastError`](https://rux-lang.dev/docs/api/windows/winsock#wsa-get-last-error) ## `recvfrom` ```rux pub extern func recvfrom( socket: uint64, buffer: *var opaque, count: int32, flags: int32, address: *var opaque, length: *var int32 ) -> int32 ``` Receives bytes from a socket, and where they came from. **See also**: <https://learn.microsoft.com/en-us/windows/win32/api/winsock/nf-winsock-recvfrom>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Winsock.rux#L224){rel=""nofollow""} **Parameters** | Name | Type | Description | | --------- | ------------- | ---------------------------------------------- | | `socket` | `uint64` | the socket | | `buffer` | `*var opaque` | receives the bytes | | `count` | `int32` | how many fit | | `flags` | `int32` | flags, or zero | | `address` | `*var opaque` | receives the sender's address, or null | | `length` | `*var int32` | the buffer's size, then the address's, or null | **Returns**: the bytes received, zero once a stream's peer closed it, or -1 with the reason in [`WSAGetLastError`](https://rux-lang.dev/docs/api/windows/winsock#wsa-get-last-error) ## `closesocket` ```rux pub extern func closesocket(socket: uint64) -> int32 ``` Closes a socket. **See also**: <https://learn.microsoft.com/en-us/windows/win32/api/winsock/nf-winsock-closesocket>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Winsock.rux#L232){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | -------- | ----------- | | `socket` | `uint64` | the socket | **Returns**: zero, or -1 with the reason in [`WSAGetLastError`](https://rux-lang.dev/docs/api/windows/winsock#wsa-get-last-error) ## `shutdown` ```rux pub extern func shutdown( socket: uint64, how: int32 ) -> int32 ``` Ends one or both directions of a connection. **See also**: <https://learn.microsoft.com/en-us/windows/win32/api/winsock/nf-winsock-shutdown>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Winsock.rux#L240){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | -------- | -------------------------------------------------- | | `socket` | `uint64` | the socket | | `how` | `int32` | 0 to stop receiving, 1 to stop sending, 2 for both | **Returns**: zero, or -1 with the reason in [`WSAGetLastError`](https://rux-lang.dev/docs/api/windows/winsock#wsa-get-last-error) ## `setsockopt` ```rux pub extern func setsockopt( socket: uint64, level: int32, name: int32, value: *opaque, length: int32 ) -> int32 ``` Sets a socket option. **See also**: <https://learn.microsoft.com/en-us/windows/win32/api/winsock/nf-winsock-setsockopt>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Winsock.rux#L251){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | --------- | ------------------ | | `socket` | `uint64` | the socket | | `level` | `int32` | the option's level | | `name` | `int32` | the option | | `value` | `*opaque` | the option's value | | `length` | `int32` | the value's size | **Returns**: zero, or -1 with the reason in [`WSAGetLastError`](https://rux-lang.dev/docs/api/windows/winsock#wsa-get-last-error) ## `getsockname` ```rux pub extern func getsockname( socket: uint64, address: *var opaque, length: *var int32 ) -> int32 ``` Reads a socket's local address. **See also**: <https://learn.microsoft.com/en-us/windows/win32/api/winsock/nf-winsock-getsockname>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Winsock.rux#L260){rel=""nofollow""} **Parameters** | Name | Type | Description | | --------- | ------------- | ------------------------------------- | | `socket` | `uint64` | the socket | | `address` | `*var opaque` | receives the address | | `length` | `*var int32` | the buffer's size, then the address's | **Returns**: zero, or -1 with the reason in [`WSAGetLastError`](https://rux-lang.dev/docs/api/windows/winsock#wsa-get-last-error) ## `getpeername` ```rux pub extern func getpeername( socket: uint64, address: *var opaque, length: *var int32 ) -> int32 ``` Reads the address of a connected socket's peer. **See also**: <https://learn.microsoft.com/en-us/windows/win32/api/winsock/nf-winsock-getpeername>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Winsock.rux#L269){rel=""nofollow""} **Parameters** | Name | Type | Description | | --------- | ------------- | ------------------------------------- | | `socket` | `uint64` | the socket | | `address` | `*var opaque` | receives the address | | `length` | `*var int32` | the buffer's size, then the address's | **Returns**: zero, or -1 with the reason in [`WSAGetLastError`](https://rux-lang.dev/docs/api/windows/winsock#wsa-get-last-error) ## `getaddrinfo` ```rux pub extern func getaddrinfo( node: *char8, service: *char8, hints: *AddressInfo, result: *var *var AddressInfo ) -> int32 ``` Looks up the addresses of a host and service. **See also**: <https://learn.microsoft.com/en-us/windows/win32/api/ws2tcpip/nf-ws2tcpip-getaddrinfo>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Winsock.rux#L279){rel=""nofollow""} **Parameters** | Name | Type | Description | | --------- | ----------------------- | ------------------------------------------------------------------------------------------------------------------ | | `node` | `*char8` | the host name or numeric address, NUL-terminated, or null | | `service` | `*char8` | the service name or port number, NUL-terminated, or null | | `hints` | `*AddressInfo` | what kind of results are wanted, or null | | `result` | `*var *var AddressInfo` | receives the first result, freed with [`freeaddrinfo`](https://rux-lang.dev/docs/api/windows/winsock#freeaddrinfo) | **Returns**: zero, or a Winsock error code ## `freeaddrinfo` ```rux pub extern func freeaddrinfo(info: *var AddressInfo) ``` Frees the results of [`getaddrinfo`](https://rux-lang.dev/docs/api/windows/winsock#getaddrinfo). **See also**: <https://learn.microsoft.com/en-us/windows/win32/api/ws2tcpip/nf-ws2tcpip-freeaddrinfo>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Winsock.rux#L285){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------ | ------------------ | ---------------- | | `info` | `*var AddressInfo` | the first result | ## `ioctlsocket` ```rux pub extern func ioctlsocket( socket: uint64, command: int32, argument: *var uint32 ) -> int32 ``` Sets a socket's mode, such as non-blocking with [`FIONBIO`](https://rux-lang.dev/docs/api/windows/winsock#fionbio). **See also**: <https://learn.microsoft.com/en-us/windows/win32/api/winsock/nf-winsock-ioctlsocket>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Winsock.rux#L294){rel=""nofollow""} **Parameters** | Name | Type | Description | | ---------- | ------------- | ------------------------------------------------------------------------------------------------------------------ | | `socket` | `uint64` | the socket | | `command` | `int32` | the mode to set, such as [`FIONBIO`](https://rux-lang.dev/docs/api/windows/winsock#fionbio) | | `argument` | `*var uint32` | the mode's value: for [`FIONBIO`](https://rux-lang.dev/docs/api/windows/winsock#fionbio), nonzero for non-blocking | **Returns**: zero, or -1 with the reason in [`WSAGetLastError`](https://rux-lang.dev/docs/api/windows/winsock#wsa-get-last-error) ## `WSAPoll` ```rux pub extern func WSAPoll( sockets: *var WsaPollFd, count: uint32, timeout: int32 ) -> int32 ``` Waits until one of `count` sockets is ready or `timeout` milliseconds pass, filling each one's `returned`. **See also**: <https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-wsapoll>{rel=""nofollow""} [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Windows/Src/Winsock.rux#L303){rel=""nofollow""} **Parameters** | Name | Type | Description | | --------- | ---------------- | ------------------------------------------------------------------ | | `sockets` | `*var WsaPollFd` | the sockets and the events wanted of each | | `count` | `uint32` | how many there are | | `timeout` | `int32` | milliseconds to wait, zero to only look, or -1 to wait without end | **Returns**: how many sockets have events, zero after the timeout, or -1 with the reason in [`WSAGetLastError`](https://rux-lang.dev/docs/api/windows/winsock#wsa-get-last-error) # Regex Regular expressions matched in linear time, with Unicode classes, captures, splitting and replacement. ## Installation Add `Regex` to the `[Dependencies]` table of your package's `Rux.toml`: ```toml [Dependencies] Regex = { Namespace = "Rux", Version = "0.1.0" } ``` Standard packages are declared by hand: the registry does not serve them, so `rux add Rux/Regex` cannot add them. ## Dependencies - [`Allocator`](https://rux-lang.dev/docs/api/allocator) 0.1.0 - [`Collections`](https://rux-lang.dev/docs/api/collections) 0.1.0 - [`Core`](https://rux-lang.dev/docs/api/core) 0.1.0 - [`Text`](https://rux-lang.dev/docs/api/text) 0.1.0 - [`Unicode`](https://rux-lang.dev/docs/api/unicode) 0.1.0 ## Guide Regular expressions matched in linear time: Unicode classes and case folding, numbered and named groups, every match in turn, splitting and replacement. ### What it provides | Module | Covers | | ---------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | [`Regex`](https://rux-lang.dev/docs/api/regex/regex#regex) | [`Regex`](https://rux-lang.dev/docs/api/regex/regex#regex) with [`New`](https://rux-lang.dev/docs/api/regex/regex#new), [`IsMatch`](https://rux-lang.dev/docs/api/regex/regex#is-match), [`Find`](https://rux-lang.dev/docs/api/regex/regex#find), [`FindAt`](https://rux-lang.dev/docs/api/regex/regex#find-at), [`Capture`](https://rux-lang.dev/docs/api/regex/regex#capture), [`CaptureAt`](https://rux-lang.dev/docs/api/regex/regex#capture-at), [`FindAll`](https://rux-lang.dev/docs/api/regex/regex#find-all), [`Split`](https://rux-lang.dev/docs/api/regex/regex#split), [`Replace`](https://rux-lang.dev/docs/api/regex/regex#replace) and [`ReplaceFirst`](https://rux-lang.dev/docs/api/regex/regex#replace-first); [`Match`](https://rux-lang.dev/docs/api/regex/regex#match), [`Captures`](https://rux-lang.dev/docs/api/regex/regex#captures), [`MatchIterator`](https://rux-lang.dev/docs/api/regex/regex#match-iterator), [`SplitIterator`](https://rux-lang.dev/docs/api/regex/regex#split-iterator) and [`Escape`](https://rux-lang.dev/docs/api/regex/regex#escape) | | `Error` | [`RegexError`](https://rux-lang.dev/docs/api/regex/error#regex-error) and [`RegexErrorKind`](https://rux-lang.dev/docs/api/regex/error#regex-error-kind), with the offset in the pattern where it went wrong | The module names describe where each declaration comes from; they are not part of an import path. ### Example ```rux import Allocator::SystemAllocator; import Regex::{ Regex, RegexError }; func Year(text: char8[..]) -> uint ! RegexError { let date = Regex::New(SystemAllocator(), "(?<year>\\d{4})-(?<month>\\d{2})-(?<day>\\d{2})")?; match date.Capture(text)? { .Some(groups) => return (groups.Named("year") ?? return 0).start, none => return 0 } } ``` ### Design The syntax is RE2's. A pattern holds literals, `.`, classes such as `[a-z]`, `[^0-9]` and `[[:alpha:]]`, the class escapes `\d`, `\w` and `\s`, Unicode general categories and properties such as `\p{L}`, `\p{Lu}`, `\p{Alphabetic}` and `\P{White_Space}`, and scripts such as `\p{Greek}`, `\p{sc=Han}` or `\p{Script=Cyrillic}`, which, as in RE2, test the Script property rather than Script\_Extensions. It also holds the anchors `^`, `$`, `\A`, `\z`, `\b` and `\B`, the groups `(...)`, `(?:...)`, `(?<name>...)` and `(?P<name>...)`, alternation, and the repetitions `*`, `+`, `?` and `{n,m}` with lazy forms. The flags are `i` for case-insensitive, `m` for `^` and `$` at line ends, `s` for `.` matching `\n` and `x` for spaces and `#` comments, set as `(?i)` or for a group as `(?i:...)`. `\d`, `\w` and `\s` are Unicode-aware. Case-insensitive matching compares simple case foldings, so `k` matches the Kelvin sign but `ß` does not match `ss`, and a class matches every value its members fold with: `(?i)[\u{212A}]` matches `k`, and `(?i)[ς]` matches `Σ`. `$` without `m` matches only at the very end of the text. Backreferences and lookaround are refused, because without them a search never needs to backtrack. The pattern compiles to a Thompson automaton that Pike's matcher runs over the text once, moving every thread of the match a character at a time. A search therefore takes time proportional to the length of the text times the size of the pattern, whatever either holds: `(a*)*b` over a long run of `a`s finishes as quickly as anything else. Threads are kept in order of preference, so a match is the leftmost one and, among those starting there, the one a backtracking matcher would choose: `foo|foobar` matches `foo`. When every match must start with the same text, or with one of a few bytes, a search skips straight to the places it can. A text of 64 bytes or more is searched by two lazy DFAs instead. Each set of threads the matcher can be in becomes one state the first time a search meets it, and the state each character leads to is remembered, so a character costs one table lookup once a text's states are built. The forward DFA finds where the leftmost-first match ends, or that there is none; a second DFA, over the pattern reversed, reads backwards from there to where the match starts; and the Pike matcher runs over just that match when its groups are wanted. A pattern heavy with classes, such as `\w+\d\w+`, is searched about ten times as fast this way. The states are kept per search, or per iterator across its matches, and are dropped and rebuilt if a pattern makes too many, so memory stays bounded. A pattern too large to compile twice is searched by the Pike matcher alone. Positions are byte offsets into the UTF-8 text searched, always at character boundaries. Each search allocates its working storage from the regex's allocator, which is why searches can fail with [`OutOfMemory`](https://rux-lang.dev/docs/api/regex/error#out-of-memory). A compiled [`Regex`](https://rux-lang.dev/docs/api/regex/regex#regex) never changes, so one can be searched from several threads at once. A counted repetition is written out in full when compiled, so a pattern whose compiled form would exceed 100,000 instructions is refused as `TooLarge`. ## Index ### Types | Name | Summary | | ------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------- | | [`RegexErrorKind`](https://rux-lang.dev/docs/api/regex/error#regex-error-kind) | What went wrong. | | [`RegexError`](https://rux-lang.dev/docs/api/regex/error#regex-error) | Why a pattern could not be compiled, and where. | | [`Match`](https://rux-lang.dev/docs/api/regex/regex#match) | Where a match is in the text searched: from byte `start` up to byte `end`. | | [`Regex`](https://rux-lang.dev/docs/api/regex/regex#regex) | A compiled pattern. | | [`MatchIterator`](https://rux-lang.dev/docs/api/regex/regex#match-iterator) | The matches of a pattern in a text, one after another, leftmost first and never overlapping. | | [`SplitIterator`](https://rux-lang.dev/docs/api/regex/regex#split-iterator) | The parts of a text between the matches of a pattern. | | [`Captures`](https://rux-lang.dev/docs/api/regex/regex#captures) | The groups of one match: where each matched, or that it did not. | ### Functions | Name | Summary | | ------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------ | | [`Escape`](https://rux-lang.dev/docs/api/regex/regex#escape) | `text` with every character a pattern gives a meaning to escaped, so that the result, as a pattern, matches `text` and nothing else. | # Errors Why a pattern was refused, and where in it. ## `RegexErrorKind` ```rux pub enum RegexErrorKind: uint8 { UnclosedGroup = 1, UnopenedGroup = 2, UnclosedClass = 3, InvalidEscape = 4, NothingToRepeat = 5, InvalidRange = 6, InvalidCount = 7, UnknownProperty = 8, UnknownFlag = 9, InvalidGroupName = 10, DuplicateGroupName = 11, Unsupported = 12, InvalidText = 13, TooLarge = 14, OutOfMemory = 15 } ``` What went wrong. `Copy`. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Regex/Src/Error.rux#L5){rel=""nofollow""} **Cases** | Name | Value | Description | | -------------------- | ----- | --------------------------------------------------------------------------------------------------------------------------------- | | `UnclosedGroup` | `1` | A `(` has no `)`. | | `UnopenedGroup` | `2` | A `)` has no `(`. | | `UnclosedClass` | `3` | A `[` has no `]`. | | `InvalidEscape` | `4` | A `\` is followed by something that is not an escape, or ends the pattern. | | `NothingToRepeat` | `5` | A `*`, `+`, `?` or `{n,m}` has nothing before it to repeat. | | `InvalidRange` | `6` | A class range ends before it starts, as `z-a` does, or one end of it is a class such as `\d`. | | `InvalidCount` | `7` | A repetition count is over 1000, or its maximum is below its minimum. | | `UnknownProperty` | `8` | A `\p{...}` names a property or category this package does not know. | | `UnknownFlag` | `9` | A `(?...)` holds a flag other than `i`, `m`, `s` and `x`. | | `InvalidGroupName` | `10` | A group name is empty, or holds something other than letters, digits and `_`, or starts with a digit. | | `DuplicateGroupName` | `11` | Two groups have the same name. | | `Unsupported` | `12` | The pattern uses lookaround, a backreference or something else that cannot be matched in linear time. | | `InvalidText` | `13` | The pattern is not UTF-8 text. | | `TooLarge` | `14` | The compiled pattern would be too large, usually from counted repetitions inside each other, or its groups are nested too deeply. | | `OutOfMemory` | `15` | The allocator could not supply the storage. | ## `RegexError` ```rux pub struct RegexError { pub kind: RegexErrorKind; pub offset: uint; } ``` Why a pattern could not be compiled, and where. `Copy`. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Regex/Src/Error.rux#L41){rel=""nofollow""} **Fields** | Name | Type | Description | | -------- | ---------------- | ------------------------------------------------------------------------------------------------------------------------ | | `kind` | `RegexErrorKind` | What went wrong. | | `offset` | `uint` | The byte offset in the pattern where it went wrong; zero for failures that have no place, such as running out of memory. | **Associated functions** ### `At` ```rux pub func At( kind: RegexErrorKind, offset: uint ) -> RegexError ``` An error of `kind` at `offset`. | Name | Type | Description | | -------- | ---------------- | -------------------- | | `kind` | `RegexErrorKind` | what went wrong | | `offset` | `uint` | where in the pattern | **Returns**: the error [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Regex/Src/Error.rux#L55){rel=""nofollow""} ### `OutOfMemory` ```rux pub func OutOfMemory() -> RegexError ``` The error for storage the allocator could not supply. **Returns**: the error [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Regex/Src/Error.rux#L62){rel=""nofollow""} # Regex A compiled regular expression: matching, finding, capturing, splitting and replacing, and escaping text to match it literally. ## `Match` ```rux pub struct Match { pub start: uint; pub end: uint; } ``` Where a match is in the text searched: from byte `start` up to byte `end`. `Copy`. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Regex/Src/Regex.rux#L37){rel=""nofollow""} **Fields** | Name | Type | Description | | ------- | ------ | ----------------------------------------------- | | `start` | `uint` | The byte offset of the start of the match. | | `end` | `uint` | The byte offset just past the end of the match. | **Methods** ### `Length` ```rux pub func Length(self: &Match) -> uint ``` How many bytes the match spans. **Returns**: the length in bytes [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Regex/Src/Regex.rux#L48){rel=""nofollow""} ### `Slice` ```rux pub func Slice(self: &Match, text: char8[..]) -> char8[..] ``` The matched part of `text`, which must be the text that was searched. | Name | Type | Description | | ------ | ----------- | -------------------------- | | `text` | `char8[..]` | the text that was searched | **Returns**: the bytes of the match [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Regex/Src/Regex.rux#L56){rel=""nofollow""} ## `Regex` ```rux pub struct Regex { // private fields } ``` A compiled pattern. Not copied. The syntax is RE2's: literals, `.`, classes such as `[a-z]`, `[^0-9]`, `[[:alpha:]]`, `\d`, `\w` and `\s`, Unicode general categories and properties such as `\p{L}`, `\p{Lu}` and `\p{White_Space}`, the anchors `^`, `$`, `\A`, `\z`, `\b` and `\B`, groups `(...)`, `(?:...)` and `(?<name>...)`, alternation `|`, the repetitions `*`, `+`, `?` and `{n,m}` with a lazy `?` form of each, and the flags `i`, `m`, `s` and `x` as `(?i)` or `(?i:...)`. Backreferences and lookaround are refused: without them every search takes time linear in the text. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Regex/Src/Regex.rux#L68){rel=""nofollow""} **Associated functions** ### `New` ```rux pub func New( allocator: Allocator, pattern: char8[..] ) -> Regex ! RegexError ``` Compiles `pattern`. | Name | Type | Description | | ----------- | ----------- | ----------------------------------------------------------------------------------------------- | | `allocator` | `Allocator` | what the compiled pattern, and every search of it, takes storage from | | `pattern` | `char8[..]` | the pattern, in the syntax [`Regex`](https://rux-lang.dev/docs/api/regex/regex#regex) describes | **Returns**: the compiled pattern, or why it could not be compiled and where [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Regex/Src/Regex.rux#L252){rel=""nofollow""} **Methods** ### `GroupCount` ```rux pub func GroupCount(self: &Regex) -> uint ``` How many capturing groups the pattern has, not counting the whole match. **Returns**: the count [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Regex/Src/Regex.rux#L324){rel=""nofollow""} ### `GroupIndex` ```rux pub func GroupIndex(self: &Regex, name: char8[..]) -> uint? ``` The number of the group called `name`. | Name | Type | Description | | ------ | ----------- | ---------------- | | `name` | `char8[..]` | the group's name | **Returns**: its number, or `none` when no group has that name [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Regex/Src/Regex.rux#L332){rel=""nofollow""} ### `IsMatch` ```rux pub func IsMatch( self: &Regex, text: char8[..] ) -> bool ! RegexError ``` Whether the pattern matches anywhere in `text`. Stops at the first match it sees. | Name | Type | Description | | ------ | ----------- | ------------------ | | `text` | `char8[..]` | the text to search | **Returns**: whether there is a match, or fails when the search's storage could not be allocated [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Regex/Src/Regex.rux#L341){rel=""nofollow""} ### `Find` ```rux pub func Find( self: &Regex, text: char8[..] ) -> Match? ! RegexError ``` The leftmost match in `text`; among matches starting there, the one a backtracking matcher would choose. | Name | Type | Description | | ------ | ----------- | ------------------ | | `text` | `char8[..]` | the text to search | **Returns**: the match, or `none` [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Regex/Src/Regex.rux#L356){rel=""nofollow""} ### `FindAt` ```rux pub func FindAt( self: &Regex, text: char8[..], start: uint ) -> Match? ! RegexError ``` The leftmost match in `text` at or after byte `start`. Anchors and word boundaries still see the text before `start`, so `^` does not match there unless `start` is where a line starts. | Name | Type | Description | | ------- | ----------- | ------------------------------------------------------- | | `text` | `char8[..]` | the text to search | | `start` | `uint` | the byte offset to search from, at a character boundary | **Returns**: the match, or `none` [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Regex/Src/Regex.rux#L366){rel=""nofollow""} ### `Capture` ```rux pub func Capture( self: &Regex, text: char8[..] ) -> Captures? ! RegexError ``` The leftmost match in `text`, with where each group matched. | Name | Type | Description | | ------ | ----------- | ------------------ | | `text` | `char8[..]` | the text to search | **Returns**: the groups, or `none` when there is no match [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Regex/Src/Regex.rux#L378){rel=""nofollow""} ### `CaptureAt` ```rux pub func CaptureAt( self: &Regex, text: char8[..], start: uint ) -> Captures? ! RegexError ``` The leftmost match in `text` at or after byte `start`, with where each group matched. | Name | Type | Description | | ------- | ----------- | ------------------------------------------------------- | | `text` | `char8[..]` | the text to search | | `start` | `uint` | the byte offset to search from, at a character boundary | **Returns**: the groups, or `none` when there is no match [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Regex/Src/Regex.rux#L387){rel=""nofollow""} ### `FindAll` ```rux pub func FindAll( self: &Regex, text: char8[..] ) -> MatchIterator ! RegexError ``` Every match in `text`, leftmost first and never overlapping. An empty match right after another match is skipped, so `a*` finds three matches in `baab`: before the `b`, `aa`, and at the end. | Name | Type | Description | | ------ | ----------- | --------------------------------------------------- | | `text` | `char8[..]` | the text to search, which must outlive the iterator | **Returns**: the matches in turn [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Regex/Src/Regex.rux#L410){rel=""nofollow""} ### `Split` ```rux pub func Split( self: &Regex, text: char8[..] ) -> SplitIterator ! RegexError ``` The parts of `text` between the matches. | Name | Type | Description | | ------ | ----------- | -------------------------------------------------- | | `text` | `char8[..]` | the text to split, which must outlive the iterator | **Returns**: the parts in turn [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Regex/Src/Regex.rux#L418){rel=""nofollow""} ### `Replace` ```rux pub func Replace( self: &Regex, allocator: Allocator, text: char8[..], replacement: char8[..] ) -> String ! RegexError ``` `text` with every match replaced by `replacement`, in which `$1` or `${1}` stands for what group 1 matched, `$name` or `${name}` for what the group called `name` matched, `$0` for the whole match, and `$$` for `$`. A group that did not match, or does not exist, stands for nothing. | Name | Type | Description | | ------------- | ----------- | -------------------------- | | `allocator` | `Allocator` | what the result is kept in | | `text` | `char8[..]` | the text to search | | `replacement` | `char8[..]` | what each match becomes | **Returns**: the new text [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Regex/Src/Regex.rux#L430){rel=""nofollow""} ### `ReplaceFirst` ```rux pub func ReplaceFirst( self: &Regex, allocator: Allocator, text: char8[..], replacement: char8[..] ) -> String ! RegexError ``` `text` with its first match replaced by `replacement`, which is read as [`Replace`](https://rux-lang.dev/docs/api/regex/regex#replace) reads it. | Name | Type | Description | | ------------- | ----------- | -------------------------- | | `allocator` | `Allocator` | what the result is kept in | | `text` | `char8[..]` | the text to search | | `replacement` | `char8[..]` | what the match becomes | **Returns**: the new text [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Regex/Src/Regex.rux#L441){rel=""nofollow""} ## `MatchIterator` ```rux pub struct MatchIterator { // private fields } ``` The matches of a pattern in a text, one after another, leftmost first and never overlapping. Not copied. Borrows the regex and the text, which must outlive it. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Regex/Src/Regex.rux#L159){rel=""nofollow""} **Implements Iterator** `MatchIterator` conforms to `Iterator`. ### `Next` ```rux pub func Next(self: &var MatchIterator) -> Match? ``` The next match, or `none` after the last. **Returns**: the match [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Regex/Src/Regex.rux#L167){rel=""nofollow""} ## `SplitIterator` ```rux pub struct SplitIterator { // private fields } ``` The parts of a text between the matches of a pattern. Not copied. Borrows the regex and the text, which must outlive it. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Regex/Src/Regex.rux#L177){rel=""nofollow""} **Implements Iterator** `SplitIterator` conforms to `Iterator`. ### `Next` ```rux pub func Next(self: &var SplitIterator) -> char8[..]? ``` The next part, or `none` after the last. There is always one more part than there are matches, so a match at either end gives an empty part there. **Returns**: the part [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Regex/Src/Regex.rux#L188){rel=""nofollow""} ## `Captures` ```rux pub struct Captures { // private fields } ``` The groups of one match: where each matched, or that it did not. Not copied. Borrows the regex it came from for the group names, so it must not outlive the regex. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Regex/Src/Regex.rux#L205){rel=""nofollow""} **Methods** ### `Count` ```rux pub func Count(self: &Captures) -> uint ``` How many groups there are, counting the whole match as group 0. **Returns**: the count [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Regex/Src/Regex.rux#L217){rel=""nofollow""} ### `Group` ```rux pub func Group(self: &Captures, index: uint) -> Match? ``` Where group `index` matched: 0 is the whole match, and the groups count from 1 in the order their `(` appear. | Name | Type | Description | | ------- | ------ | ------------------ | | `index` | `uint` | the group's number | **Returns**: where it matched, or `none` when it did not take part in the match or there is no such group [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Regex/Src/Regex.rux#L225){rel=""nofollow""} ### `Named` ```rux pub func Named(self: &Captures, name: char8[..]) -> Match? ``` Where the group called `name` matched. | Name | Type | Description | | ------ | ----------- | ---------------- | | `name` | `char8[..]` | the group's name | **Returns**: where it matched, or `none` when it did not take part in the match or there is no such group [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Regex/Src/Regex.rux#L238){rel=""nofollow""} ## `Escape` ```rux pub func Escape( allocator: Allocator, text: char8[..] ) -> String ! RegexError ``` `text` with every character a pattern gives a meaning to escaped, so that the result, as a pattern, matches `text` and nothing else. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Regex/Src/Regex.rux#L546){rel=""nofollow""} **Parameters** | Name | Type | Description | | ----------- | ----------- | -------------------------- | | `allocator` | `Allocator` | what the result is kept in | | `text` | `char8[..]` | the text to escape | **Returns**: the pattern # Process The running process: its command-line arguments, environment, identifier and exit. ## Installation Add `Process` to the `[Dependencies]` table of your package's `Rux.toml`: ```toml [Dependencies] Process = { Namespace = "Rux", Version = "0.1.0" } ``` Standard packages are declared by hand: the registry does not serve them, so `rux add Rux/Process` cannot add them. ## Dependencies - [`Allocator`](https://rux-lang.dev/docs/api/allocator) 0.1.0 - [`Core`](https://rux-lang.dev/docs/api/core) 0.1.0 - [`FreeBSD`](https://rux-lang.dev/docs/api/freebsd) 0.1.0 (FreeBSD only) - [`Io`](https://rux-lang.dev/docs/api/io) 0.1.0 - [`Linux`](https://rux-lang.dev/docs/api/linux) 0.1.0 (Linux only) - [`macOS`](https://rux-lang.dev/docs/api/macos) 0.1.0 (macOS only) - [`Memory`](https://rux-lang.dev/docs/api/memory) 0.1.0 - [`Path`](https://rux-lang.dev/docs/api/path) 0.1.0 - [`Thread`](https://rux-lang.dev/docs/api/thread) 0.1.0 - [`Windows`](https://rux-lang.dev/docs/api/windows) 0.1.0 (Windows only) ## Guide The running process — its command-line arguments, environment, identifier and exit — and the child processes it starts. ### What it provides | Module | Covers | | ------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | [`Arguments`](https://rux-lang.dev/docs/api/process/arguments#arguments) | [`ArgumentCount`](https://rux-lang.dev/docs/api/process/arguments#argument-count), `Argument`, and [`Arguments`](https://rux-lang.dev/docs/api/process/arguments#arguments) for walking them in order | | [`Environment`](https://rux-lang.dev/docs/api/process/environment#environment) | [`Variable`](https://rux-lang.dev/docs/api/process/environment#variable) for one value by name, [`Environment`](https://rux-lang.dev/docs/api/process/environment#environment) for walking every [`EnvironmentVariable`](https://rux-lang.dev/docs/api/process/environment#environment-variable), and `SetVariable` and `RemoveVariable` | | [`Exit`](https://rux-lang.dev/docs/api/process/exit#exit) | [`Exit`](https://rux-lang.dev/docs/api/process/exit#exit), which ends the process with a status, and [`CurrentId`](https://rux-lang.dev/docs/api/process/exit#current-id) | | `Executable` | [`CurrentExecutable`](https://rux-lang.dev/docs/api/process/executable#current-executable), the path of the file the process is running, as the system loaded it | | [`Command`](https://rux-lang.dev/docs/api/process/command#command) | [`Command`](https://rux-lang.dev/docs/api/process/command#command), which describes a program to start, and [`Stdio`](https://rux-lang.dev/docs/api/process/command#stdio) for its standard streams | | [`Child`](https://rux-lang.dev/docs/api/process/child#child) | [`Child`](https://rux-lang.dev/docs/api/process/child#child) with [`Wait`](https://rux-lang.dev/docs/api/process/child#wait), [`TryWait`](https://rux-lang.dev/docs/api/process/child#try-wait) and [`Kill`](https://rux-lang.dev/docs/api/process/child#kill), its [`ExitStatus`](https://rux-lang.dev/docs/api/process/child#exit-status), and the [`PipeReader`](https://rux-lang.dev/docs/api/process/child#pipe-reader) and [`PipeWriter`](https://rux-lang.dev/docs/api/process/child#pipe-writer) streams | | [`Capture`](https://rux-lang.dev/docs/api/process/command#capture) | [`Command::Capture`](https://rux-lang.dev/docs/api/process/command#capture), which runs a program and keeps its output, error and status | The module names describe where each declaration comes from; they are not part of an import path. ### Example ```rux import Path::OsStringView; import Process::{ ArgumentCount, Arguments, Variable }; func CountFlags() -> uint { var flags: uint = 0; var walk = Arguments(); for argument in walk.Skip(1) { let units = argument.Units(); if units.length > 0 && units[0] as uint32 == 0x2D { flags = flags + 1; } } return flags; } func HasHome() -> bool { let home = Variable("HOME") ?? OsStringView(); return !home.IsEmpty() && ArgumentCount() > 0; } ``` ```rux import Allocator::SystemAllocator; import Io::IoError; import Process::Command; func Version() -> bool ! IoError { var command = Command(SystemAllocator(), "git"); command.Argument("--version"); let captured = command.Capture(SystemAllocator())?; return captured.Status().Success() && captured.Output().length > 0; } ``` ### Design Arguments and environment values are native text, `Path::OsStringView`: bytes on the Unix systems and UTF-16 code units on Windows, exactly as the system handed them over. Nothing obliges either to be valid UTF-8 or UTF-16, so a program that needs text converts with `ToText` and decides what an unconvertible argument means. The first argument is the program as it was invoked, a name or a path the parent chose. Every view of an argument or variable borrows storage the process owns for its whole life, so reading them allocates nothing and a view can be kept anywhere. Linux and FreeBSD keep the vectors on the stack the kernel built, which the entry stub records for `Core::ProcessStartFrame`; macOS has dyld record them in libSystem; Windows hands over one command line, which is split once with `CommandLineToArgvW` so that the arguments are the ones the C runtime would give, and one environment block, which is read once. The first read happens on first use and is kept, so a program that starts threads should read what it needs before it does. Names are matched the way each system matches them: exactly on the Unix systems and without regard to ASCII case on Windows. `SetVariable` and `RemoveVariable` keep their changes in a table beside the environment the process started with, which [`Variable`](https://rux-lang.dev/docs/api/process/environment#variable), [`Environment`](https://rux-lang.dev/docs/api/process/environment#environment) and every child this package starts consult first. Their text is never freed, so every view handed out stays valid. Windows is told of each change as well; the C library's own environment on the Unix systems is not, so code outside Rux that reads it there does not see the change. A [`Command`](https://rux-lang.dev/docs/api/process/command#command) collects a program, its arguments, a working directory, environment changes for the child, and what each standard stream is connected to: this process's own, nothing, or a new pipe. A part the system cannot take, such as text with a NUL in it, is remembered and reported when the command is started, so the parts can be given without checking each. On Linux, FreeBSD and macOS the child is started with the C library's `posix_spawnp`, which finds the program through `PATH` and reports a program that could not be started as `NotFound` or the system's reason rather than as a child that exits; a program that starts children is therefore linked against the C library. On Windows it is started with `CreateProcessW`, from a command line quoted the way the C runtime splits one, so each argument arrives exactly as it was given. On the Unix systems a relative program path is looked up after the child has changed to its working directory; on Windows, before. A [`Child`](https://rux-lang.dev/docs/api/process/child#child)'s pipes are `Io` streams the caller takes and owns; closing the writer ends the child's input. [`Wait`](https://rux-lang.dev/docs/api/process/child#wait) closes that writer first, so a child that reads to the end is not left waiting. [`Capture`](https://rux-lang.dev/docs/api/process/command#capture) reads standard error on a second thread while it reads standard output, so a child that fills one pipe while the other is being read never deadlocks. A child that is dropped without waiting keeps running; on the Unix systems its status then stays with the system until this process ends. [`Exit`](https://rux-lang.dev/docs/api/process/exit#exit) ends every thread at once and reports its status to the parent, which sees the low eight bits on the Unix systems and all thirty-two on Windows. Nothing is flushed or destroyed on the way out, so returning from `Main` remains the ordinary way to finish. ## Index ### Types | Name | Summary | | ----------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------- | | [`ArgumentIterator`](https://rux-lang.dev/docs/api/process/arguments#argument-iterator) | A walk over the process's arguments in order, the program first. | | [`CapturedOutput`](https://rux-lang.dev/docs/api/process/capture#captured-output) | What a program wrote to its standard output and error, and how it finished. | | [`ExitStatus`](https://rux-lang.dev/docs/api/process/child#exit-status) | How a child process finished. | | [`PipeWriter`](https://rux-lang.dev/docs/api/process/child#pipe-writer) | The writing end of a pipe into a child's standard input. | | [`PipeReader`](https://rux-lang.dev/docs/api/process/child#pipe-reader) | The reading end of a pipe from a child's standard output or error. | | [`Child`](https://rux-lang.dev/docs/api/process/child#child) | A child process this one started. | | [`Stdio`](https://rux-lang.dev/docs/api/process/command#stdio) | What a child's standard stream is connected to. | | [`Command`](https://rux-lang.dev/docs/api/process/command#command) | A program to start, with its arguments, working directory, environment changes and standard streams. | | [`EnvironmentVariable`](https://rux-lang.dev/docs/api/process/environment#environment-variable) | One environment variable: its name and its value. | | [`EnvironmentIterator`](https://rux-lang.dev/docs/api/process/environment#environment-iterator) | A walk over the environment variables: those the process started with, in the order the system holds them, then those set since. | ### Functions | Name | Summary | | ------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------- | | [`ArgumentCount`](https://rux-lang.dev/docs/api/process/arguments#argument-count) | How many arguments the process was started with, the program itself included. | | [`Argument`](https://rux-lang.dev/docs/api/process/arguments#argument) | The argument at `index`, counting the program as argument zero, or none past the last one. | | [`Arguments`](https://rux-lang.dev/docs/api/process/arguments#arguments) | Every argument the process was started with, the program first. | | [`Environment`](https://rux-lang.dev/docs/api/process/environment#environment) | Every environment variable of the process. | | [`Variable`](https://rux-lang.dev/docs/api/process/environment#variable) | The value of the environment variable `name`, or none when it is not set. | | [`SetVariable`](https://rux-lang.dev/docs/api/process/environment#set-variable) | Sets the environment variable `name` to `value`, for this process and every process it starts from now on. | | [`RemoveVariable`](https://rux-lang.dev/docs/api/process/environment#remove-variable) | Removes the environment variable `name`, for this process and every process it starts from now on. | | [`CurrentExecutable`](https://rux-lang.dev/docs/api/process/executable#current-executable) | The path of the executable file the process is running, as the system loaded it. | | [`Exit`](https://rux-lang.dev/docs/api/process/exit#exit) | Ends the whole process at once, reporting `code` to its parent. | | [`CurrentId`](https://rux-lang.dev/docs/api/process/exit#current-id) | The identifier the system gave this process. | # Captured output What a program wrote and how it ended, kept by [`Command::Capture`](https://rux-lang.dev/docs/api/process/command#capture). ## `CapturedOutput` ```rux pub struct CapturedOutput { // private fields } ``` What a program wrote to its standard output and error, and how it finished. The bytes are kept as the program wrote them, which is usually but not always UTF-8. Not copied. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Process/Src/Capture.rux#L14){rel=""nofollow""} **Methods** ### `Status` ```rux pub func Status(self: &CapturedOutput) -> ExitStatus ``` How the program finished. **Returns**: its exit status [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Process/Src/Capture.rux#L26){rel=""nofollow""} ### `Output` ```rux pub func Output(self: &CapturedOutput) -> char8[..] ``` Everything the program wrote to its standard output. **Returns**: the bytes, valid while the captured output lives [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Process/Src/Capture.rux#L33){rel=""nofollow""} ### `Error` ```rux pub func Error(self: &CapturedOutput) -> char8[..] ``` Everything the program wrote to its standard error. **Returns**: the bytes, valid while the captured output lives [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Process/Src/Capture.rux#L40){rel=""nofollow""} # Child processes A started program: waiting for it, killing it, and its standard streams. ## `ExitStatus` ```rux pub struct ExitStatus { // private fields } ``` How a child process finished. `Copy`. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Process/Src/Child.rux#L54){rel=""nofollow""} **Methods** ### `Success` ```rux pub func Success(self: &ExitStatus) -> bool ``` Whether the child exited with code zero. **Returns**: true for a clean exit [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Process/Src/Child.rux#L63){rel=""nofollow""} ### `Code` ```rux pub func Code(self: &ExitStatus) -> int32? ``` The code the child exited with, or none when a signal ended it. **Returns**: the exit code [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Process/Src/Child.rux#L70){rel=""nofollow""} ### `Signal` ```rux pub func Signal(self: &ExitStatus) -> int32? ``` The signal that ended the child on a Unix system, or none when it exited. Never present on Windows. **Returns**: the signal number [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Process/Src/Child.rux#L78){rel=""nofollow""} ## `PipeWriter` ```rux pub struct PipeWriter { // private fields } ``` The writing end of a pipe into a child's standard input. Closing it, by dropping it, ends the child's input. A pipe end is not copied. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Process/Src/Child.rux#L94){rel=""nofollow""} **Methods** ### `Close` ```rux pub func Close(self: &var PipeWriter) ``` Closes the pipe now rather than when the writer is dropped. Closing it twice does nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Process/Src/Child.rux#L110){rel=""nofollow""} **Implements Writer** `PipeWriter` conforms to `Writer`. ### `Write` ```rux pub func Write( self: &var PipeWriter, bytes: char8[..] ) -> uint ! IoError ``` Writes some of `bytes` into the pipe, waiting while it is full. | Name | Type | Description | | ------- | ----------- | ------------------ | | `bytes` | `char8[..]` | the bytes to write | **Returns**: how many were written, or fails, with a broken pipe once the child closed its end [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Process/Src/Child.rux#L125){rel=""nofollow""} ### `Flush` ```rux pub func Flush(self: &var PipeWriter) -> ! IoError ``` Does nothing: a pipe keeps no buffer of its own. **Returns**: nothing [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Process/Src/Child.rux#L146){rel=""nofollow""} **Destructor** ### `~PipeWriter` ```rux func ~PipeWriter(self: &var PipeWriter) ``` [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Process/Src/Child.rux#L115){rel=""nofollow""} ## `PipeReader` ```rux pub struct PipeReader { // private fields } ``` The reading end of a pipe from a child's standard output or error. A read past what the child wrote, once it has closed its end, fails with `EndOfStream`. A pipe end is not copied. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Process/Src/Child.rux#L101){rel=""nofollow""} **Methods** ### `Close` ```rux pub func Close(self: &var PipeReader) ``` Closes the pipe now rather than when the reader is dropped. Closing it twice does nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Process/Src/Child.rux#L156){rel=""nofollow""} **Implements Reader** `PipeReader` conforms to `Reader`. ### `Read` ```rux pub func Read( self: &var PipeReader, into: var char8[..] ) -> uint ! IoError ``` Reads what the child has written so far into `into`, waiting while it has written nothing. | Name | Type | Description | | ------ | --------------- | ---------------------- | | `into` | `var char8[..]` | where to put the bytes | **Returns**: how many were read, or fails with `EndOfStream` once the child closed its end and all was read [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Process/Src/Child.rux#L171){rel=""nofollow""} **Destructor** ### `~PipeReader` ```rux func ~PipeReader(self: &var PipeReader) ``` [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Process/Src/Child.rux#L161){rel=""nofollow""} ## `Child` ```rux pub struct Child { // private fields } ``` A child process this one started. Wait for it to learn how it finished. Dropping a child that was not waited for neither waits for nor stops it; on the Unix systems its exit status then stays with the system until this process ends. A child is not copied. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Process/Src/Child.rux#L198){rel=""nofollow""} **Methods** ### `Id` ```rux pub func Id(self: &Child) -> uint32 ``` The child's process identifier. **Returns**: the identifier [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Process/Src/Child.rux#L215){rel=""nofollow""} ### `TakeInput` ```rux pub func TakeInput(self: &var Child) -> PipeWriter? ``` The pipe into the child's standard input, when it was started with `Stdio::Pipe` there and the pipe was not taken before. **Returns**: the writer, which the caller now owns [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Process/Src/Child.rux#L223){rel=""nofollow""} ### `TakeOutput` ```rux pub func TakeOutput(self: &var Child) -> PipeReader? ``` The pipe from the child's standard output, when it was started with `Stdio::Pipe` there and the pipe was not taken before. **Returns**: the reader, which the caller now owns [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Process/Src/Child.rux#L234){rel=""nofollow""} ### `TakeError` ```rux pub func TakeError(self: &var Child) -> PipeReader? ``` The pipe from the child's standard error, when it was started with `Stdio::Pipe` there and the pipe was not taken before. **Returns**: the reader, which the caller now owns [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Process/Src/Child.rux#L245){rel=""nofollow""} ### `Wait` ```rux pub func Wait(self: &var Child) -> ExitStatus ! IoError ``` Waits for the child to finish and returns how it did. The pipe into its input, if still held, is closed first, so a child reading its input to the end is not left waiting for more. Waiting again returns the same status. **Returns**: how the child finished [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Process/Src/Child.rux#L256){rel=""nofollow""} ### `TryWait` ```rux pub func TryWait(self: &var Child) -> ExitStatus? ! IoError ``` How the child finished, or none while it still runs, without waiting. **Returns**: the status once the child has finished [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Process/Src/Child.rux#L279){rel=""nofollow""} ### `Kill` ```rux pub func Kill(self: &var Child) -> ! IoError ``` Ends the child at once: with `SIGKILL` on the Unix systems, and with exit code 1 on Windows. Killing a child that has already finished does nothing. Wait for it afterwards to learn its status. **Returns**: nothing, or fails when the system refused [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Process/Src/Child.rux#L300){rel=""nofollow""} **Destructor** ### `~Child` ```rux func ~Child(self: &var Child) ``` [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Process/Src/Child.rux#L327){rel=""nofollow""} # Commands Describing a program to start: its arguments, environment, working directory and standard streams. ## `Stdio` ```rux pub enum Stdio: uint8 { Inherit = 0, Null = 1, Pipe = 2 } ``` What a child's standard stream is connected to. `Copy`. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Process/Src/Command.rux#L46){rel=""nofollow""} **Cases** | Name | Value | Description | | --------- | ----- | ------------------------------------------------------------------------------------------------------------------- | | `Inherit` | `0` | The stream this process has, which the child shares. | | `Null` | `1` | Nothing: reads find the end at once and writes are discarded. | | `Pipe` | `2` | A new pipe, whose other end the parent takes from the [`Child`](https://rux-lang.dev/docs/api/process/child#child). | ## `Command` ```rux pub struct Command { // private fields } ``` A program to start, with its arguments, working directory, environment changes and standard streams. Build it up and then [`Spawn`](https://rux-lang.dev/docs/api/process/command#spawn) it, or [`Run`](https://rux-lang.dev/docs/api/process/command#run) it to completion, or [`Capture`](https://rux-lang.dev/docs/api/process/command#capture) what it writes. A command can be started more than once. A command is not copied. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Process/Src/Command.rux#L59){rel=""nofollow""} **Constructors** ### `Command` ```rux pub func Command( allocator: Allocator, program: char8[..] ) -> Command ``` A command to start `program`, found through `PATH` when it names no directory. The program is also the child's first argument, as every system expects. Its streams start as `Stdio::Inherit`. | Name | Type | Description | | ----------- | ----------- | ----------------------------------------- | | `allocator` | `Allocator` | what the command's parts are kept in | | `program` | `char8[..]` | the program's name or path, as UTF-8 text | **Returns**: the command [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Process/Src/Command.rux#L84){rel=""nofollow""} **Associated functions** ### `FromNative` ```rux pub func FromNative( allocator: Allocator, program: OsStringView ) -> Command ``` A command to start `program` given in native form, such as this process's own first argument. | Name | Type | Description | | ----------- | -------------- | ------------------------------------ | | `allocator` | `Allocator` | what the command's parts are kept in | | `program` | `OsStringView` | the program's name or path | **Returns**: the command [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Process/Src/Command.rux#L100){rel=""nofollow""} **Methods** ### `Capture` ```rux pub func Capture( self: &Command, allocator: Allocator ) -> CapturedOutput ! IoError ``` Starts the program with its output and error piped, keeps everything it writes, and waits for it to finish. Its input is what the command says, which is this process's own unless changed. | Name | Type | Description | | ----------- | ----------- | ----------------------------------- | | `allocator` | `Allocator` | what the captured bytes are kept in | **Returns**: the output, the error and how the program finished [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Process/Src/Command.rux#L83){rel=""nofollow""} ### `Argument` ```rux pub func Argument(self: &var Command, value: char8[..]) ``` Adds an argument, as UTF-8 text. | Name | Type | Description | | ------- | ----------- | ------------ | | `value` | `char8[..]` | the argument | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Process/Src/Command.rux#L112){rel=""nofollow""} ### `NativeArgument` ```rux pub func NativeArgument( self: &var Command, value: OsStringView ) ``` Adds an argument already in native form, such as one of this process's own arguments. | Name | Type | Description | | ------- | -------------- | ------------ | | `value` | `OsStringView` | the argument | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Process/Src/Command.rux#L121){rel=""nofollow""} ### `Directory` ```rux pub func Directory(self: &var Command, path: char8[..]) ``` Starts the child in `path` rather than in this process's working directory. | Name | Type | Description | | ------ | ----------- | ---------------------------- | | `path` | `char8[..]` | the directory, as UTF-8 text | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Process/Src/Command.rux#L130){rel=""nofollow""} ### `SetVariable` ```rux pub func SetVariable( self: &var Command, name: char8[..], value: char8[..] ) ``` Gives the child the variable `name` set to `value`, whatever this process's environment holds. | Name | Type | Description | | ------- | ----------- | ---------------------------------------------------------- | | `name` | `char8[..]` | the variable's name, which may not be empty or contain `=` | | `value` | `char8[..]` | its value | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Process/Src/Command.rux#L140){rel=""nofollow""} ### `RemoveVariable` ```rux pub func RemoveVariable(self: &var Command, name: char8[..]) ``` Leaves the variable `name` out of the child's environment. | Name | Type | Description | | ------ | ----------- | ------------------- | | `name` | `char8[..]` | the variable's name | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Process/Src/Command.rux#L152){rel=""nofollow""} ### `ClearEnvironment` ```rux pub func ClearEnvironment(self: &var Command) ``` Starts the child with no variables but those set on the command. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Process/Src/Command.rux#L161){rel=""nofollow""} ### `StandardInput` ```rux pub func StandardInput(self: &var Command, stdio: Stdio) ``` Connects the child's standard input. | Name | Type | Description | | ------- | ------- | ------------------ | | `stdio` | `Stdio` | what it reads from | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Process/Src/Command.rux#L169){rel=""nofollow""} ### `StandardOutput` ```rux pub func StandardOutput(self: &var Command, stdio: Stdio) ``` Connects the child's standard output. | Name | Type | Description | | ------- | ------- | ----------------- | | `stdio` | `Stdio` | what it writes to | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Process/Src/Command.rux#L176){rel=""nofollow""} ### `StandardError` ```rux pub func StandardError(self: &var Command, stdio: Stdio) ``` Connects the child's standard error. | Name | Type | Description | | ------- | ------- | ----------------- | | `stdio` | `Stdio` | what it writes to | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Process/Src/Command.rux#L183){rel=""nofollow""} ### `Spawn` ```rux pub func Spawn(self: &Command) -> Child ! IoError ``` Starts the program as a child process. **Returns**: the child, or fails: with a part of the command the system could not take, with `NotFound` for a program that is not there, or with the system's reason [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Process/Src/Command.rux#L191){rel=""nofollow""} ### `Run` ```rux pub func Run(self: &Command) -> ExitStatus ! IoError ``` Starts the program and waits for it to finish. **Returns**: how it finished [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Process/Src/Command.rux#L199){rel=""nofollow""} # Arguments The command-line arguments the process was started with. ## `ArgumentCount` ```rux pub func ArgumentCount() -> uint ``` How many arguments the process was started with, the program itself included. Usually at least one, since the program is passed as the first argument; a parent may pass none at all, and then this is zero. Cannot fail and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Process/Src/Arguments.rux#L17){rel=""nofollow""} **Returns**: the argument count ## `Argument` ```rux pub func Argument(index: uint) -> OsStringView? ``` The argument at `index`, counting the program as argument zero, or none past the last one. The view borrows storage the process owns for its whole life. Cannot fail and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Process/Src/Arguments.rux#L26){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------- | ------ | --------------------------------------- | | `index` | `uint` | the zero-based position of the argument | **Returns**: the argument's native units, or none when `index` is not below [`ArgumentCount`](https://rux-lang.dev/docs/api/process/arguments#argument-count) ## `ArgumentIterator` ```rux pub struct ArgumentIterator { // private fields } ``` A walk over the process's arguments in order, the program first. `Copy`; each copy walks on its own from where it was copied. Holds only a position, so it allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Process/Src/Arguments.rux#L34){rel=""nofollow""} **Methods** ### `Iterate` ```rux pub func Iterate(self: &ArgumentIterator) -> ArgumentIterator ``` The walk itself, so that `for argument in Arguments()` reads every argument. **Returns**: a copy of this walk from its current position [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Process/Src/Arguments.rux#L51){rel=""nofollow""} ### `Skip` ```rux pub func Skip( self: &var ArgumentIterator, count: uint ) -> ArgumentIterator ``` Leaves out the next `count` arguments, as `Skip(1)` leaves out the program. Advances the walk and returns it, so the call can be chained in a `for` header. Cannot fail. | Name | Type | Description | | ------- | ------ | ------------------------------- | | `count` | `uint` | how many arguments to pass over | **Returns**: this walk, advanced [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Process/Src/Arguments.rux#L60){rel=""nofollow""} **Implements Iterator** `ArgumentIterator` conforms to `Iterator`. ### `Next` ```rux pub func Next(self: &var ArgumentIterator) -> OsStringView? ``` The next argument, or none after the last. **Returns**: the argument's native units, borrowing storage the process owns for its whole life [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Process/Src/Arguments.rux#L70){rel=""nofollow""} ## `Arguments` ```rux pub func Arguments() -> ArgumentIterator ``` Every argument the process was started with, the program first. Cannot fail and allocates nothing. Use `Skip(1)` on the result, or start a loop at index one, to leave out the program's own name. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Process/Src/Arguments.rux#L43){rel=""nofollow""} **Returns**: a walk over the arguments # Environment Reading, setting and removing environment variables. ## `EnvironmentVariable` ```rux pub struct EnvironmentVariable { pub name: OsStringView; pub value: OsStringView; } ``` One environment variable: its name and its value. `Copy`. Both views borrow storage the process owns for its whole life. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Process/Src/Environment.rux#L23){rel=""nofollow""} **Fields** | Name | Type | Description | | ------- | -------------- | ----------------------------------------------------------------------------------------- | | `name` | `OsStringView` | The name, the units before the first `=`. | | `value` | `OsStringView` | The value, every unit after the first `=`, which may itself contain `=` and may be empty. | ## `EnvironmentIterator` ```rux pub struct EnvironmentIterator { // private fields } ``` A walk over the environment variables: those the process started with, in the order the system holds them, then those set since. `Copy`, holding only a position, so it allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Process/Src/Environment.rux#L97){rel=""nofollow""} **Methods** ### `Iterate` ```rux pub func Iterate(self: &EnvironmentIterator) -> EnvironmentIterator ``` The walk itself, so that `for variable in Environment()` reads every variable. **Returns**: a copy of this walk from its current position [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Process/Src/Environment.rux#L115){rel=""nofollow""} **Implements Iterator** `EnvironmentIterator` conforms to `Iterator`. ### `Next` ```rux pub func Next(self: &var EnvironmentIterator) -> EnvironmentVariable? ``` The next variable, or none after the last. **Returns**: the variable's name and value [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Process/Src/Environment.rux#L124){rel=""nofollow""} ## `Environment` ```rux pub func Environment() -> EnvironmentIterator ``` Every environment variable of the process. Cannot fail and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Process/Src/Environment.rux#L107){rel=""nofollow""} **Returns**: a walk over the environment ## `Variable` ```rux pub func Variable(name: char8[..]) -> OsStringView? ``` The value of the environment variable `name`, or none when it is not set. `name` is UTF-8 text. It is matched exactly on the Unix systems and without regard to ASCII case on Windows, which is how each system matches names. A variable set or removed with `SetVariable` or `RemoveVariable` reads as it was last changed. When the starting environment names a variable twice, the first is the one returned, as the C library's `getenv` returns it. A variable set to the empty string is present, with an empty value. The view borrows storage the process owns for its whole life. Runs in time linear in the size of the environment and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Process/Src/Environment.rux#L238){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------ | ----------- | ------------------- | | `name` | `char8[..]` | the variable's name | **Returns**: the variable's value, or none when no variable has that name ## `SetVariable` ```rux pub func SetVariable( name: char8[..], value: char8[..] ) -> ! IoError ``` Sets the environment variable `name` to `value`, for this process and every process it starts from now on. Both are UTF-8 text. The change is seen by [`Variable`](https://rux-lang.dev/docs/api/process/environment#variable) and [`Environment`](https://rux-lang.dev/docs/api/process/environment#environment), by [`Command`](https://rux-lang.dev/docs/api/process/command#command), and on Windows by the system; the C library's own environment on the Unix systems is not changed. Views handed out before stay valid. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Process/Src/Environment.rux#L349){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------- | ----------- | ----------------------------------------------------------------- | | `name` | `char8[..]` | the variable's name, which may not be empty or contain `=` or NUL | | `value` | `char8[..]` | its new value, which may not contain NUL | **Returns**: nothing, or fails with `InvalidInput` for a name or value the environment cannot hold ## `RemoveVariable` ```rux pub func RemoveVariable(name: char8[..]) -> ! IoError ``` Removes the environment variable `name`, for this process and every process it starts from now on. Removing a variable that is not set does nothing. Views of its value handed out before stay valid. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Process/Src/Environment.rux#L364){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------ | ----------- | ----------------------------------------------------------------- | | `name` | `char8[..]` | the variable's name, which may not be empty or contain `=` or NUL | **Returns**: nothing, or fails with `InvalidInput` for a name the environment cannot hold # Executable The path of the file the process is running. ## `CurrentExecutable` ```rux pub func CurrentExecutable(allocator: Allocator) -> PathBuffer ! IoError ``` The path of the executable file the process is running, as the system loaded it. Unlike `Argument(0)`, which is whatever the parent chose to pass, this is the file itself, so a program that runs itself again or finds files installed beside it can rely on it. Windows, Linux and FreeBSD give an absolute path with symbolic links resolved; macOS gives the path the executable was loaded by, which may be relative to the directory the process started in or pass through links. Fails with `NotFound` when the system cannot say, as when Linux has no `/proc` mounted, and with `LimitExceeded` when the path cannot be stored. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Process/Src/Executable.rux#L34){rel=""nofollow""} **Parameters** | Name | Type | Description | | ----------- | ----------- | ------------------------ | | `allocator` | `Allocator` | what the path is kept in | **Returns**: the executable's path # Exit Ending the process, and its identifier. ## `Exit` ```rux pub func Exit(code: int32) ``` Ends the whole process at once, reporting `code` to its parent. Every thread stops. Nothing is flushed, unwound or destroyed: the system reclaims memory and descriptors, and data still buffered in the process is lost, so flush what must be written first. On the Unix systems the parent sees only the low eight bits of `code`; on Windows it sees all thirty-two. Does not return. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Process/Src/Exit.rux#L44){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------ | ------- | ---------------------------------------------------- | | `code` | `int32` | the status to report, zero for success by convention | ## `CurrentId` ```rux pub func CurrentId() -> uint32 ``` The identifier the system gave this process. Stable for the life of the process and unique among running processes, but reused once the process has exited. Cannot fail and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Process/Src/Exit.rux#L58){rel=""nofollow""} **Returns**: the process identifier # CommandLine Declarative command-line parsing: options, positional arguments, subcommands and generated help. ## Installation Add `CommandLine` to the `[Dependencies]` table of your package's `Rux.toml`: ```toml [Dependencies] CommandLine = { Namespace = "Rux", Version = "0.1.0" } ``` Standard packages are declared by hand: the registry does not serve them, so `rux add Rux/CommandLine` cannot add them. ## Dependencies - [`Core`](https://rux-lang.dev/docs/api/core) 0.1.0 - [`Path`](https://rux-lang.dev/docs/api/path) 0.1.0 - [`Process`](https://rux-lang.dev/docs/api/process) 0.1.0 - [`Text`](https://rux-lang.dev/docs/api/text) 0.1.0 ## Guide ### What it provides | Module | Covers | | ------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `Spec` | [`CommandSpec`](https://rux-lang.dev/docs/api/commandline/spec#command-spec), [`OptionSpec`](https://rux-lang.dev/docs/api/commandline/spec#option-spec), [`PositionalSpec`](https://rux-lang.dev/docs/api/commandline/spec#positional-spec), and the [`Command`](https://rux-lang.dev/docs/api/commandline/spec#command), [`Flag`](https://rux-lang.dev/docs/api/commandline/spec#flag), [`ValueOption`](https://rux-lang.dev/docs/api/commandline/spec#value-option), [`Required`](https://rux-lang.dev/docs/api/commandline/spec#required), [`Optional`](https://rux-lang.dev/docs/api/commandline/spec#optional) and [`Remaining`](https://rux-lang.dev/docs/api/commandline/spec#remaining) builders | | [`Parsed`](https://rux-lang.dev/docs/api/commandline/parsed) | [`Parse`](https://rux-lang.dev/docs/api/commandline/parsed#parse) and [`ParseProcess`](https://rux-lang.dev/docs/api/commandline/parsed#parse-process), and the [`Parsed`](https://rux-lang.dev/docs/api/commandline/parsed) queries: [`Has`](https://rux-lang.dev/docs/api/commandline/parsed#has), `Count`, [`Value`](https://rux-lang.dev/docs/api/commandline/parsed#value), [`Values`](https://rux-lang.dev/docs/api/commandline/parsed#values), [`Positional`](https://rux-lang.dev/docs/api/commandline/parsed#positional), [`Positionals`](https://rux-lang.dev/docs/api/commandline/parsed#positionals), [`Integer`](https://rux-lang.dev/docs/api/commandline/parsed#integer), [`Subcommand`](https://rux-lang.dev/docs/api/commandline/parsed#subcommand) | | `Help` | `WriteHelp`, [`WriteUsage`](https://rux-lang.dev/docs/api/commandline/help#write-usage) and [`WriteVersion`](https://rux-lang.dev/docs/api/commandline/help#write-version) | | `Error` | [`CommandLineError`](https://rux-lang.dev/docs/api/commandline/command-line-error), which describes itself through `Display` | | `Scan` | [`ArgumentSource`](https://rux-lang.dev/docs/api/commandline/parsed#argument-source), the arguments a parse reads | The module names describe where each declaration comes from; they are not part of an import path. ### Example ```rux import CommandLine::{ Command, Flag, OptionSpec, ParseProcess, PositionalSpec, Required, ValueOption }; func Run() -> int { let options: OptionSpec[2] = [Flag("verbose", 'v', "Say more"), ValueOption("output", 'o', "FILE", "Where to write")]; let positionals: PositionalSpec[1] = [Required("input", "What to read")]; let spec = Command("tool", "Converts files").WithVersion("1.0.0").WithOptions(options[..]).WithPositionals(positionals[..]); let parsed = ParseProcess(@spec) catch { else => return 2 }; if parsed.HelpRequested() || parsed.VersionRequested() { return 0; } return parsed.Count("verbose") as int; } ``` ### Design A command is described as values: its name, summary and version, its options, its positional arguments and its subcommands. The description is what the arguments are checked against and what the help text is written from, so the two cannot disagree. Every part borrows its text and slices, so a whole command line can be described in locals and nothing is allocated. The grammar is the conventional one. `--name` and `--name=value` are long options, and a value may also be the next argument. `-abc` is three short flags, and a short option that takes a value takes the rest of the cluster or the next argument, so `-o out`, `-oout`, `--output out` and `--output=out` mean the same. `--` ends options, `-` alone is an argument, and a repeated option keeps every value, with [`Value`](https://rux-lang.dev/docs/api/commandline/parsed#value) answering the last so that a later argument overrides an earlier one. A command with subcommands takes its first positional argument as the subcommand's name, and everything after it belongs to the subcommand. Every command understands `--help` and `-h`, and `--version` and `-V` when it has a version, unless it declares its own options of those names. A parse checks the arguments once and keeps nothing but where they are. Each question walks them again with the same scanner, so an answer can never come from a reading different from the one that was validated, and parsing needs no storage. Values are `Path::OsStringView`s borrowing the arguments, lossless on every system; [`Integer`](https://rux-lang.dev/docs/api/commandline/parsed#integer) reads a value as a decimal `int64`. A mismatch is a [`CommandLineError`](https://rux-lang.dev/docs/api/commandline/command-line-error) that names the argument as it was typed, or the option or positional by its specification's name, and describes itself through `Display`, such as `option '--output' needs a value`. Asking for help or the version succeeds whatever else is missing. ## Index ### Types | Name | Summary | | ------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------- | | [`CommandLineError`](https://rux-lang.dev/docs/api/commandline/command-line-error) | Why the arguments did not match the command. | | [`Parsed`](https://rux-lang.dev/docs/api/commandline/parsed) | Arguments that matched a command. | | [`ValueIterator`](https://rux-lang.dev/docs/api/commandline/parsed#value-iterator) | A walk over the values one option or positional was given, in the order they were given. | | [`ArgumentSource`](https://rux-lang.dev/docs/api/commandline/parsed#argument-source) | Where the arguments being parsed come from. | | [`OptionSpec`](https://rux-lang.dev/docs/api/commandline/spec#option-spec) | One option a command accepts, such as `--output FILE` or `-v`. | | [`PositionalKind`](https://rux-lang.dev/docs/api/commandline/spec#positional-kind) | How a positional argument may be given. | | [`PositionalSpec`](https://rux-lang.dev/docs/api/commandline/spec#positional-spec) | One positional argument a command accepts, such as `<input>`. | | [`CommandSpec`](https://rux-lang.dev/docs/api/commandline/spec#command-spec) | A command: what it is called, what it accepts, and the subcommands under it. | ### Functions | Name | Summary | | -------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------- | | [`WriteUsage`](https://rux-lang.dev/docs/api/commandline/help#write-usage) | Writes the usage line, such as `Usage: tool [options] <input> [output]`. | | [`WriteHelp`](https://rux-lang.dev/docs/api/commandline/help#write-help) | Writes the full help text: the summary, the usage line, and the arguments, options and subcommands with their descriptions aligned. | | [`WriteVersion`](https://rux-lang.dev/docs/api/commandline/help#write-version) | Writes the version line, such as `tool 1.4.2`. | | [`Parse`](https://rux-lang.dev/docs/api/commandline/parsed#parse) | Checks `arguments` against `spec`. | | [`ParseProcess`](https://rux-lang.dev/docs/api/commandline/parsed#parse-process) | Checks the process's own arguments against `spec`. | | [`Flag`](https://rux-lang.dev/docs/api/commandline/spec#flag) | An option that is present or absent and takes no value, such as `--verbose`. | | [`ValueOption`](https://rux-lang.dev/docs/api/commandline/spec#value-option) | An option that takes a value, such as `--output FILE`. | | [`Required`](https://rux-lang.dev/docs/api/commandline/spec#required) | A positional argument that must be given. | | [`Optional`](https://rux-lang.dev/docs/api/commandline/spec#optional) | A positional argument that may be left out. | | [`Remaining`](https://rux-lang.dev/docs/api/commandline/spec#remaining) | A positional argument that takes every positional argument left, which may be none. | | [`Command`](https://rux-lang.dev/docs/api/commandline/spec#command) | A command with a name and a summary, and as yet no version, options, positionals or subcommands. | # CommandLineError Why the arguments did not match the command. ```rux pub variant CommandLineError { UnknownOption(OsStringView), MissingValue(char8[..]), UnexpectedValue(char8[..]), UnknownCommand(OsStringView), MissingCommand, MissingPositional(char8[..]), UnexpectedArgument(OsStringView), InvalidValue(char8[..], OsStringView) } ``` Failure-only: a parse is the success channel of `Parsed ! CommandLineError`. Copy; every view and name it carries borrows the arguments or the specification, which must outlive it. ## Cases | Name | Description | | --------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- | | `UnknownOption(OsStringView)` | An argument that looks like an option names none the command has. Carries the argument as typed. | | `MissingValue(char8[..])` | An option that takes a value was the last argument, or ended a cluster of short options. Carries the option's long name. | | `UnexpectedValue(char8[..])` | A flag was given a value with `=`. Carries the option's long name. | | `UnknownCommand(OsStringView)` | The command has subcommands and the word naming one is not among them. Carries the word as typed. | | `MissingCommand` | The command has subcommands and none was named. | | `MissingPositional(char8[..])` | A required positional argument was not given. Carries its name. | | `UnexpectedArgument(OsStringView)` | A positional argument beyond every one the command accepts. Carries the argument as typed. | | `InvalidValue(char8[..], OsStringView)` | A value that could not be read as what was asked of it, such as a number. Carries the option or positional's name, then the value as typed. | ## Implements Display `CommandLineError` conforms to `Display`. ### `WriteDisplay` ```rux pub func WriteDisplay( self: &CommandLineError, writer: &var TextWriter, spec: FormatSpec ) -> ! FormatError ``` Writes what went wrong, naming the argument, option or positional involved. The text is lower case without a final full stop, such as `unknown option '--frob'` or `option '--output' needs a value`. No style is understood. Reports whatever the writer reported, and `UnsupportedRequest` for a style. | Name | Type | Description | | -------- | ----------------- | ------------------------------ | | `writer` | `&var TextWriter` | the destination | | `spec` | `FormatSpec` | what the placeholder asked for | **Returns**: success when the whole description was accepted [Source](https://github.com/rux-lang/Rux/blob/main/Packages/CommandLine/Src/Error.rux#L108){rel=""nofollow""} ## Implements Debug `CommandLineError` conforms to `Debug`. ### `WriteDebug` ```rux pub func WriteDebug( self: &CommandLineError, writer: &var TextWriter, spec: FormatSpec ) -> ! FormatError ``` The same text as `Display`: the description already names everything involved. The failures [`WriteDisplay`](https://rux-lang.dev/docs/api/commandline/command-line-error#write-display) reports. | Name | Type | Description | | -------- | ----------------- | ------------------------------ | | `writer` | `&var TextWriter` | the destination | | `spec` | `FormatSpec` | what the placeholder asked for | **Returns**: success when the whole description was accepted [Source](https://github.com/rux-lang/Rux/blob/main/Packages/CommandLine/Src/Error.rux#L163){rel=""nofollow""} # Parsed Arguments that matched a command. ```rux pub struct Parsed { // private fields } ``` `Copy`, owning nothing: it borrows the specification and the arguments, both of which must outlive it. ## Methods ### `WriteHelp` ```rux pub func WriteHelp( self: &Parsed, writer: &var TextWriter ) -> ! FormatError ``` Writes the help text of the command this parse is for, naming its parent in the usage line when it is a subcommand. Reports whatever the writer reported. | Name | Type | Description | | -------- | ----------------- | --------------- | | `writer` | `&var TextWriter` | the destination | **Returns**: success when the whole text was accepted [Source](https://github.com/rux-lang/Rux/blob/main/Packages/CommandLine/Src/Parsed.rux#L224){rel=""nofollow""} ### `HelpRequested` ```rux pub func HelpRequested(self: &Parsed) -> bool ``` Whether `--help` or `-h` was given. A program usually writes the help text and exits successfully when this is true. Cannot fail. **Returns**: whether help was asked for [Source](https://github.com/rux-lang/Rux/blob/main/Packages/CommandLine/Src/Parsed.rux#L193){rel=""nofollow""} ### `VersionRequested` ```rux pub func VersionRequested(self: &Parsed) -> bool ``` Whether `--version` or `-V` was given, which a command only understands when it has a version. Cannot fail. **Returns**: whether the version was asked for [Source](https://github.com/rux-lang/Rux/blob/main/Packages/CommandLine/Src/Parsed.rux#L201){rel=""nofollow""} ### `Count` ```rux pub func Count(self: &Parsed, name: char8[..]) -> uint ``` How many times the option with long name `name` was given. Counting is how `-vvv` means more than `-v`. An option the command does not declare was given zero times. Runs in time linear in the number of arguments and allocates nothing. | Name | Type | Description | | ------ | ----------- | ----------------------------------------- | | `name` | `char8[..]` | the option's long name without its dashes | **Returns**: the number of times it was given [Source](https://github.com/rux-lang/Rux/blob/main/Packages/CommandLine/Src/Parsed.rux#L211){rel=""nofollow""} ### `Has` ```rux pub func Has(self: &Parsed, name: char8[..]) -> bool ``` Whether the option with long name `name` was given at least once. | Name | Type | Description | | ------ | ----------- | ----------------------------------------- | | `name` | `char8[..]` | the option's long name without its dashes | **Returns**: whether it was given [Source](https://github.com/rux-lang/Rux/blob/main/Packages/CommandLine/Src/Parsed.rux#L226){rel=""nofollow""} ### `Value` ```rux pub func Value( self: &Parsed, name: char8[..] ) -> OsStringView? ``` The value of the option with long name `name`, the last one given when it was given more than once. The last value wins so that a later argument can override an earlier one, as a script adding to a fixed command line expects. Runs in time linear in the number of arguments and allocates nothing. | Name | Type | Description | | ------ | ----------- | ----------------------------------------- | | `name` | `char8[..]` | the option's long name without its dashes | **Returns**: the value as typed, or none when the option was not given or takes no value [Source](https://github.com/rux-lang/Rux/blob/main/Packages/CommandLine/Src/Parsed.rux#L236){rel=""nofollow""} ### `Values` ```rux pub func Values( self: &Parsed, name: char8[..] ) -> ValueIterator ``` Every value the option with long name `name` was given, in order. | Name | Type | Description | | ------ | ----------- | ----------------------------------------- | | `name` | `char8[..]` | the option's long name without its dashes | **Returns**: a walk over the values, empty when the option was not given [Source](https://github.com/rux-lang/Rux/blob/main/Packages/CommandLine/Src/Parsed.rux#L252){rel=""nofollow""} ### `Positional` ```rux pub func Positional( self: &Parsed, name: char8[..] ) -> OsStringView? ``` The positional argument named `name`, the first one when it takes the remaining arguments. | Name | Type | Description | | ------ | ----------- | --------------------- | | `name` | `char8[..]` | the positional's name | **Returns**: the argument as typed, or none when it was not given [Source](https://github.com/rux-lang/Rux/blob/main/Packages/CommandLine/Src/Parsed.rux#L265){rel=""nofollow""} ### `Positionals` ```rux pub func Positionals( self: &Parsed, name: char8[..] ) -> ValueIterator ``` Every argument the positional named `name` was given, which is more than one only for a [`Remaining`](https://rux-lang.dev/docs/api/commandline/spec#remaining) positional. | Name | Type | Description | | ------ | ----------- | --------------------- | | `name` | `char8[..]` | the positional's name | **Returns**: a walk over the arguments, empty when none was given [Source](https://github.com/rux-lang/Rux/blob/main/Packages/CommandLine/Src/Parsed.rux#L275){rel=""nofollow""} ### `CommandName` ```rux pub func CommandName(self: &Parsed) -> char8[..]? ``` The name of the subcommand that was given, for a command that has subcommands. **Returns**: the subcommand's name as its specification spells it, or none [Source](https://github.com/rux-lang/Rux/blob/main/Packages/CommandLine/Src/Parsed.rux#L287){rel=""nofollow""} ### `Subcommand` ```rux pub func Subcommand(self: &Parsed) -> Parsed? ``` The parse of the subcommand's own arguments, everything after its name. Those arguments were validated with this parse, so this cannot fail. **Returns**: the subcommand's parse, or none when no subcommand was given [Source](https://github.com/rux-lang/Rux/blob/main/Packages/CommandLine/Src/Parsed.rux#L296){rel=""nofollow""} ### `Integer` ```rux pub func Integer( self: &Parsed, name: char8[..] ) -> int64? ! CommandLineError ``` The value of the option or positional named `name` read as a decimal integer, or none when it was not given. An optional leading `-` or `+` is accepted, then one or more decimal digits and nothing else. Reports `InvalidValue` for any other text and for a number outside the range of `int64`. Allocates nothing. | Name | Type | Description | | ------ | ----------- | --------------------------------------------- | | `name` | `char8[..]` | an option's long name, or a positional's name | **Returns**: the number, none when the value was not given, or why it is not a number [Source](https://github.com/rux-lang/Rux/blob/main/Packages/CommandLine/Src/Parsed.rux#L310){rel=""nofollow""} ## Related ### `Parse` ```rux pub func Parse( spec: *CommandSpec, arguments: OsStringView[..] ) -> Parsed ! CommandLineError ``` Checks `arguments` against `spec`. `arguments` are the arguments after the program's name. Reports the first mismatch: an unknown option, an option missing its value or given one it does not take, an unknown or missing subcommand, a missing required positional, or an argument beyond what the command accepts. Asking for `--help` or `--version` succeeds whatever else is missing, and [`HelpRequested`](https://rux-lang.dev/docs/api/commandline/parsed#help-requested) or [`VersionRequested`](https://rux-lang.dev/docs/api/commandline/parsed#version-requested) then says so. Allocates nothing; both `spec` and `arguments` must outlive the result. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/CommandLine/Src/Parsed.rux#L91){rel=""nofollow""} **Parameters** | Name | Type | Description | | ----------- | ------------------ | ----------------------------------------- | | `spec` | `*CommandSpec` | the command the arguments are for | | `arguments` | `OsStringView[..]` | the arguments, without the program's name | **Returns**: the parse, or why the arguments do not match ### `ParseProcess` ```rux pub func ParseProcess(spec: *CommandSpec) -> Parsed ! CommandLineError ``` Checks the process's own arguments against `spec`. The same checks as [`Parse`](https://rux-lang.dev/docs/api/commandline/parsed#parse), over every argument after the program's name. The arguments last as long as the process; `spec` must outlive the result. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/CommandLine/Src/Parsed.rux#L101){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------ | -------------- | --------------------------------- | | `spec` | `*CommandSpec` | the command the arguments are for | **Returns**: the parse, or why the arguments do not match ### `ValueIterator` ```rux pub struct ValueIterator { // private fields } ``` A walk over the values one option or positional was given, in the order they were given. `Copy`, holding a position in the arguments and nothing else. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/CommandLine/Src/Parsed.rux#L142){rel=""nofollow""} **Methods** #### `Iterate` ```rux pub func Iterate(self: &ValueIterator) -> ValueIterator ``` The walk itself, so that a `for` loop reads every value. **Returns**: a copy of this walk from its current position [Source](https://github.com/rux-lang/Rux/blob/main/Packages/CommandLine/Src/Parsed.rux#L153){rel=""nofollow""} **Implements Iterator** `ValueIterator` conforms to `Iterator`. #### `Next` ```rux pub func Next(self: &var ValueIterator) -> OsStringView? ``` The next value, or none after the last. **Returns**: the value as typed, borrowing the arguments [Source](https://github.com/rux-lang/Rux/blob/main/Packages/CommandLine/Src/Parsed.rux#L162){rel=""nofollow""} ### `ArgumentSource` ```rux pub variant ArgumentSource { Given(OsStringView[..]), ProcessArguments } ``` Where the arguments being parsed come from. `Copy`. A slice is borrowed and must outlive every parse made from it; the process's own arguments last as long as the process. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/CommandLine/Src/Scan.rux#L18){rel=""nofollow""} **Cases** | Name | Description | | ------------------------- | ----------------------------------------------------- | | `Given(OsStringView[..])` | Arguments given as views, without the program's name. | | `ProcessArguments` | The process's own arguments after the program's name. | **Methods** #### `Count` ```rux pub func Count(self: &ArgumentSource) -> uint ``` How many arguments there are. **Returns**: the argument count, not counting the program's name [Source](https://github.com/rux-lang/Rux/blob/main/Packages/CommandLine/Src/Scan.rux#L29){rel=""nofollow""} #### `At` ```rux pub func At( self: &ArgumentSource, index: uint ) -> OsStringView ``` The argument at `index`, counting from zero after the program's name. | Name | Type | Description | | ------- | ------ | ----------------------- | | `index` | `uint` | the argument's position | **Returns**: the argument, or an empty view past the last one [Source](https://github.com/rux-lang/Rux/blob/main/Packages/CommandLine/Src/Scan.rux#L41){rel=""nofollow""} # Help Writing the help, usage and version text generated from a specification. ## `WriteUsage` ```rux pub func WriteUsage( spec: &CommandSpec, writer: &var TextWriter, parent: char8[..] ) -> ! FormatError ``` Writes the usage line, such as `Usage: tool [options] <input> [output]`. `parent` names the command a subcommand belongs to, so that its usage reads `tool build ...`; it is empty for the program itself. Reports whatever the writer reported. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/CommandLine/Src/Help.rux#L98){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | ----------------- | ------------------------------------------------------------- | | `spec` | `&CommandSpec` | the command | | `writer` | `&var TextWriter` | the destination | | `parent` | `char8[..]` | the name of the command this one is a subcommand of, or empty | **Returns**: success when the whole line was accepted ## `WriteHelp` ```rux pub func WriteHelp( spec: &CommandSpec, writer: &var TextWriter, parent: char8[..] ) -> ! FormatError ``` Writes the full help text: the summary, the usage line, and the arguments, options and subcommands with their descriptions aligned. Reports whatever the writer reported. Allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/CommandLine/Src/Help.rux#L125){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | ----------------- | ------------------------------------------------------------- | | `spec` | `&CommandSpec` | the command | | `writer` | `&var TextWriter` | the destination | | `parent` | `char8[..]` | the name of the command this one is a subcommand of, or empty | **Returns**: success when the whole text was accepted ## `WriteVersion` ```rux pub func WriteVersion( spec: &CommandSpec, writer: &var TextWriter ) -> ! FormatError ``` Writes the version line, such as `tool 1.4.2`. Reports whatever the writer reported. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/CommandLine/Src/Help.rux#L207){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | ----------------- | --------------- | | `spec` | `&CommandSpec` | the command | | `writer` | `&var TextWriter` | the destination | **Returns**: success when the whole line was accepted # Specification Declaring a command: its flags, valued options, positional arguments, subcommands and version. ## `OptionSpec` ```rux pub struct OptionSpec { pub name: char8[..]; pub short: char32; pub value: char8[..]; pub help: char8[..]; } ``` One option a command accepts, such as `--output FILE` or `-v`. `Copy`; the text it holds is borrowed and must outlive the specification. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/CommandLine/Src/Spec.rux#L12){rel=""nofollow""} **Fields** | Name | Type | Description | | ------- | ----------- | ----------------------------------------------------------------------------------------------------- | | `name` | `char8[..]` | The long name without its dashes, such as `output` for `--output`. Never empty. | | `short` | `char32` | The short name, such as `o` for `-o`, or `'\0'` for none. An ASCII letter or digit. | | `value` | `char8[..]` | What the help text calls the option's value, such as `FILE`, or empty for a flag that takes no value. | | `help` | `char8[..]` | One line saying what the option does. | ## `PositionalKind` ```rux pub enum PositionalKind { Required, Optional, Remaining } ``` How a positional argument may be given. `Copy`, carrying no payload. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/CommandLine/Src/Spec.rux#L26){rel=""nofollow""} **Cases** | Name | Description | | ----------- | ----------------------------------------------------------------------------------------------------------- | | `Required` | Exactly once; parsing fails without it. | | `Optional` | At most once. | | `Remaining` | Any number of times, taking every remaining positional argument. Only the last positional may be this kind. | ## `PositionalSpec` ```rux pub struct PositionalSpec { pub name: char8[..]; pub kind: PositionalKind; pub help: char8[..]; } ``` One positional argument a command accepts, such as `<input>`. `Copy`; the text it holds is borrowed and must outlive the specification. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/CommandLine/Src/Spec.rux#L38){rel=""nofollow""} **Fields** | Name | Type | Description | | ------ | ---------------- | --------------------------------------------------------------------- | | `name` | `char8[..]` | The name queries and the help text use, such as `input`. Never empty. | | `kind` | `PositionalKind` | How the argument may be given. | | `help` | `char8[..]` | One line saying what the argument is. | ## `CommandSpec` ```rux pub struct CommandSpec { pub name: char8[..]; pub summary: char8[..]; pub version: char8[..]; pub options: OptionSpec[..]; pub positionals: PositionalSpec[..]; pub commands: CommandSpec[..]; } ``` A command: what it is called, what it accepts, and the subcommands under it. `Copy`; every slice and text it holds is borrowed and must outlive it and every parse made from it. A command with subcommands takes the first positional argument as the subcommand's name, so it should declare no positionals of its own. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/CommandLine/Src/Spec.rux#L52){rel=""nofollow""} **Fields** | Name | Type | Description | | ------------- | -------------------- | -------------------------------------------------------------------------------------- | | `name` | `char8[..]` | The command's name: the program's name at the top, and the word that selects it below. | | `summary` | `char8[..]` | One line saying what the command does. | | `version` | `char8[..]` | The version `--version` reports, or empty when the command has none. | | `options` | `OptionSpec[..]` | The options, in the order the help text lists them. | | `positionals` | `PositionalSpec[..]` | The positional arguments, in the order they are given. | | `commands` | `CommandSpec[..]` | The subcommands, in the order the help text lists them. | **Methods** ### `WithVersion` ```rux pub func WithVersion( self: &CommandSpec, version: char8[..] ) -> CommandSpec ``` This command with `version`, which `--version` then reports. | Name | Type | Description | | --------- | ----------- | --------------------------------- | | `version` | `char8[..]` | the version text, such as `1.4.2` | **Returns**: the changed copy [Source](https://github.com/rux-lang/Rux/blob/main/Packages/CommandLine/Src/Spec.rux#L132){rel=""nofollow""} ### `WithOptions` ```rux pub func WithOptions( self: &CommandSpec, options: OptionSpec[..] ) -> CommandSpec ``` This command with `options`, which must outlive it. | Name | Type | Description | | --------- | ---------------- | -------------------------------------------------- | | `options` | `OptionSpec[..]` | the options, in the order the help text lists them | **Returns**: the changed copy [Source](https://github.com/rux-lang/Rux/blob/main/Packages/CommandLine/Src/Spec.rux#L147){rel=""nofollow""} ### `WithPositionals` ```rux pub func WithPositionals( self: &CommandSpec, positionals: PositionalSpec[..] ) -> CommandSpec ``` This command with `positionals`, which must outlive it. | Name | Type | Description | | ------------- | -------------------- | ----------------------------------------------------- | | `positionals` | `PositionalSpec[..]` | the positional arguments, in the order they are given | **Returns**: the changed copy [Source](https://github.com/rux-lang/Rux/blob/main/Packages/CommandLine/Src/Spec.rux#L162){rel=""nofollow""} ### `WithCommands` ```rux pub func WithCommands( self: &CommandSpec, commands: CommandSpec[..] ) -> CommandSpec ``` This command with `commands`, which must outlive it. | Name | Type | Description | | ---------- | ----------------- | ------------------------------------------------------ | | `commands` | `CommandSpec[..]` | the subcommands, in the order the help text lists them | **Returns**: the changed copy [Source](https://github.com/rux-lang/Rux/blob/main/Packages/CommandLine/Src/Spec.rux#L177){rel=""nofollow""} ## `Flag` ```rux pub func Flag( name: char8[..], short: char32, help: char8[..] ) -> OptionSpec ``` An option that is present or absent and takes no value, such as `--verbose`. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/CommandLine/Src/Spec.rux#L73){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------- | ----------- | ------------------------------------ | | `name` | `char8[..]` | the long name without its dashes | | `short` | `char32` | the short name, or `'\0'` for none | | `help` | `char8[..]` | one line saying what the option does | **Returns**: the option's specification ## `ValueOption` ```rux pub func ValueOption( name: char8[..], short: char32, value: char8[..], help: char8[..] ) -> OptionSpec ``` An option that takes a value, such as `--output FILE`. The value may follow the option as the next argument, after `=` in the long form, or directly after the short letter, so `--output a.txt`, `--output=a.txt`, `-o a.txt` and `-oa.txt` all give `a.txt`. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/CommandLine/Src/Spec.rux#L86){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------- | ----------- | --------------------------------------------------------------- | | `name` | `char8[..]` | the long name without its dashes | | `short` | `char32` | the short name, or `'\0'` for none | | `value` | `char8[..]` | what the help text calls the value, such as `FILE`; never empty | | `help` | `char8[..]` | one line saying what the option does | **Returns**: the option's specification ## `Required` ```rux pub func Required( name: char8[..], help: char8[..] ) -> PositionalSpec ``` A positional argument that must be given. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/CommandLine/Src/Spec.rux#L95){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------ | ----------- | -------------------------------------- | | `name` | `char8[..]` | the name queries and the help text use | | `help` | `char8[..]` | one line saying what the argument is | **Returns**: the positional's specification ## `Optional` ```rux pub func Optional( name: char8[..], help: char8[..] ) -> PositionalSpec ``` A positional argument that may be left out. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/CommandLine/Src/Spec.rux#L104){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------ | ----------- | -------------------------------------- | | `name` | `char8[..]` | the name queries and the help text use | | `help` | `char8[..]` | one line saying what the argument is | **Returns**: the positional's specification ## `Remaining` ```rux pub func Remaining( name: char8[..], help: char8[..] ) -> PositionalSpec ``` A positional argument that takes every positional argument left, which may be none. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/CommandLine/Src/Spec.rux#L113){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------ | ----------- | -------------------------------------- | | `name` | `char8[..]` | the name queries and the help text use | | `help` | `char8[..]` | one line saying what the arguments are | **Returns**: the positional's specification ## `Command` ```rux pub func Command( name: char8[..], summary: char8[..] ) -> CommandSpec ``` A command with a name and a summary, and as yet no version, options, positionals or subcommands. The `With` methods fill in the rest, each returning the changed copy. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/CommandLine/Src/Spec.rux#L123){rel=""nofollow""} **Parameters** | Name | Type | Description | | --------- | ----------- | --------------------------------------------------------- | | `name` | `char8[..]` | the program's name, or the word that selects a subcommand | | `summary` | `char8[..]` | one line saying what the command does | **Returns**: the command's specification # Log Structured logging: levels, typed fields, text and JSON-lines records, a process-wide log for every thread, and log files that rotate by size. ## Installation Add `Log` to the `[Dependencies]` table of your package's `Rux.toml`: ```toml [Dependencies] Log = { Namespace = "Rux", Version = "0.1.0" } ``` Standard packages are declared by hand: the registry does not serve them, so `rux add Rux/Log` cannot add them. ## Dependencies - [`Allocator`](https://rux-lang.dev/docs/api/allocator) 0.1.0 - [`Core`](https://rux-lang.dev/docs/api/core) 0.1.0 - [`FileSystem`](https://rux-lang.dev/docs/api/filesystem) 0.1.0 - [`Format`](https://rux-lang.dev/docs/api/format) 0.1.0 - [`Io`](https://rux-lang.dev/docs/api/io) 0.1.0 - [`Path`](https://rux-lang.dev/docs/api/path) 0.1.0 - [`Sync`](https://rux-lang.dev/docs/api/sync) 0.1.0 - [`Text`](https://rux-lang.dev/docs/api/text) 0.1.0 - [`Time`](https://rux-lang.dev/docs/api/time) 0.1.0 ## Guide Structured logging: levels, typed fields, one line of text or JSON per record, a process-wide log that every thread can write to, and log files that rotate by size. ### What it provides | Module | Covers | | ----------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | [`Level`](https://rux-lang.dev/docs/api/log/level#level) | [`Level`](https://rux-lang.dev/docs/api/log/level#level) from `Trace` to `Error` with [`Name`](https://rux-lang.dev/docs/api/log/level#name), [`Label`](https://rux-lang.dev/docs/api/log/level#label) and [`Parse`](https://rux-lang.dev/docs/api/log/level#parse), and [`CompiledLevel`](https://rux-lang.dev/docs/api/log/level#compiled-level) from the `LogLevel` define | | [`Field`](https://rux-lang.dev/docs/api/log/field#field) | [`Field`](https://rux-lang.dev/docs/api/log/field#field) with [`Text`](https://rux-lang.dev/docs/api/log/field#text), [`Integer`](https://rux-lang.dev/docs/api/log/field#integer), [`Unsigned`](https://rux-lang.dev/docs/api/log/field#unsigned), [`Float`](https://rux-lang.dev/docs/api/log/field#float) and [`Boolean`](https://rux-lang.dev/docs/api/log/field#boolean), and its [`Value`](https://rux-lang.dev/docs/api/log/field#value) | | `Record` | [`LogFormat`](https://rux-lang.dev/docs/api/log/record#log-format): [`Text`](https://rux-lang.dev/docs/api/log/field#text) or `JsonLines` | | [`Logger`](https://rux-lang.dev/docs/api/log/logger#logger) | [`Logger`](https://rux-lang.dev/docs/api/log/logger#logger) over any `Io::Writer`, with a level, context fields, optional times, and `Trace` to `Error` | | `Global` | the process-wide log on standard error: `Trace` to `Error`, `Log`, `SetLevel`, [`SetFormat`](https://rux-lang.dev/docs/api/log/global#set-format), `SetTimestamps`, `Enabled` | | `Rotation` | [`RotatingFile`](https://rux-lang.dev/docs/api/log/rotating-file), a log file moved aside for a fresh one before a write would take it past a size, and its [`RotatingStream`](https://rux-lang.dev/docs/api/log/rotating-stream) | The module names describe where each declaration comes from; they are not part of an import path. ### Example ```rux import Log::{ Field, Info, LogFormat, SetFormat, Warn }; func Serve(port: uint64) { SetFormat(LogFormat::JsonLines); Info("listening", [Field::Unsigned("port", port)]); Warn("no certificate configured"); } ``` ### Design A record has a level, a message, and fields whose values keep their types. As text it is one line: the time, the level, the message, then `key=value` for each field, with a value that holds spaces, quotes or `=` in quotes. As JSON lines it is one object per line, with `time`, `level` and `message` members followed by the fields, and a number that is not finite written as `null`. Line breaks and other control characters are escaped in both formats, so a record never spans lines. Times are RFC 3339 in UTC to the millisecond. They can be turned off for a destination that adds its own, such as a service manager's journal. Each record is built whole and handed to its destination in a single write. The process-wide functions write to standard error. Their level, format and time settings are read and written atomically, and a lock is held only for the write of a finished record, so threads build records at the same time and their lines never interleave. A [`Logger`](https://rux-lang.dev/docs/api/log/logger#logger) writes to any `Io::Writer`, such as a file or a socket, and is used by one thread at a time. Logging never fails: a [`Logger`](https://rux-lang.dev/docs/api/log/logger#logger) keeps the first failure to write for [`Failure`](https://rux-lang.dev/docs/api/log/logger#failure) to report, and the process-wide log drops a record it cannot write. A [`RotatingFile`](https://rux-lang.dev/docs/api/log/rotating-file) is a `Writer` over a path that keeps a log from growing without end. Before a write would take the current file past its limit, the file is renamed to `path.1`, after an older `path.1` becomes `path.2` and so on up to the number of older files kept, and an empty file takes its place. Rotation happens only between writes, and a [`Logger`](https://rux-lang.dev/docs/api/log/logger#logger) writes each record in one call, so no record is ever split across two files; a record larger than the limit gets a file of its own. Hand one to a [`Logger`](https://rux-lang.dev/docs/api/log/logger#logger) with `(@file).Stream()`, keeping the file in place while the logger uses it. The `LogLevel` build define sets the least severe level a build keeps: `trace`, `debug`, `info`, `warn` or `error`. A record below it is dropped before any of it is built, whatever level a logger is set to. So a release build defined with `LogLevel = "info"` does no tracing work, while the process-wide level, which starts at `Info`, and each logger's own level are changed at run time. ## Index ### Types | Name | Summary | | --------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | [`Value`](https://rux-lang.dev/docs/api/log/field#value) | The value of a field. | | [`Field`](https://rux-lang.dev/docs/api/log/field#field) | A named value of a record. | | [`Level`](https://rux-lang.dev/docs/api/log/level#level) | How severe a record is, from the most detailed to the most serious. | | [`Logger`](https://rux-lang.dev/docs/api/log/logger#logger) | Writes records at or above a level to a stream, each as one write. | | [`LogFormat`](https://rux-lang.dev/docs/api/log/record#log-format) | How records are written. | | [`RotatingFile`](https://rux-lang.dev/docs/api/log/rotating-file) | A log file that starts afresh before a write would take it past a size. | | [`RotatingStream`](https://rux-lang.dev/docs/api/log/rotating-stream) | A stored borrow of a [`RotatingFile`](https://rux-lang.dev/docs/api/log/rotating-file) that speaks `Writer`, for a [`Logger`](https://rux-lang.dev/docs/api/log/logger#logger) to keep. | ### Functions | Name | Summary | | -------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- | | [`SetLevel`](https://rux-lang.dev/docs/api/log/global#set-level) | Writes process-wide records at `level` and above from now on. | | [`SetFormat`](https://rux-lang.dev/docs/api/log/global#set-format) | Writes process-wide records in `format` from now on. | | [`SetTimestamps`](https://rux-lang.dev/docs/api/log/global#set-timestamps) | Whether process-wide records start with the time. | | [`Enabled`](https://rux-lang.dev/docs/api/log/global#enabled) | Whether a process-wide record at `level` would be written. | | [`Log`](https://rux-lang.dev/docs/api/log/global#log) | Writes a process-wide record at `level` with `message` and `fields` to standard error, if the level is enabled. | | [`Trace`](https://rux-lang.dev/docs/api/log/global#trace) | Writes a process-wide `Trace` record with no fields. | | [`Debug`](https://rux-lang.dev/docs/api/log/global#debug) | Writes a process-wide `Debug` record with no fields. | | [`Info`](https://rux-lang.dev/docs/api/log/global#info) | Writes a process-wide `Info` record with no fields. | | [`Warn`](https://rux-lang.dev/docs/api/log/global#warn) | Writes a process-wide `Warn` record with no fields. | | [`Error`](https://rux-lang.dev/docs/api/log/global#error) | Writes a process-wide `Error` record with no fields. | | [`CompiledLevel`](https://rux-lang.dev/docs/api/log/level#compiled-level) | The least severe level this build keeps, from the `LogLevel` build define: `trace`, `debug`, `info`, `warn` or `error`, and `trace` when it is not defined. | # Fields Typed key-value fields that a record carries. ## `Value` ```rux pub variant Value { Text(char8[..]), Integer(int64), Unsigned(uint64), Float(float64), Boolean(bool) } ``` The value of a field. `Copy`. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Log/Src/Field.rux#L5){rel=""nofollow""} **Cases** | Name | Description | | ------------------ | --------------------------------------------------------------------------------- | | `Text(char8[..])` | Text, borrowed from the caller for as long as the record is being written. | | `Integer(int64)` | A signed integer. | | `Unsigned(uint64)` | An unsigned integer. | | `Float(float64)` | A floating-point number. JSON records write a value that is not finite as `null`. | | `Boolean(bool)` | A truth value. | ## `Field` ```rux pub struct Field { pub key: char8[..]; pub value: Value; } ``` A named value of a record. `Copy`. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Log/Src/Field.rux#L20){rel=""nofollow""} **Fields** | Name | Type | Description | | ------- | ----------- | ------------------------------------------------------------------------------------- | | `key` | `char8[..]` | The name, which should be a plain identifier so that every format writes it unquoted. | | `value` | `Value` | The value. | **Associated functions** ### `Text` ```rux pub func Text(key: char8[..], value: char8[..]) -> Field ``` A field of text. | Name | Type | Description | | ------- | ----------- | ---------------------------------------------- | | `key` | `char8[..]` | the name | | `value` | `char8[..]` | the text, borrowed until the record is written | **Returns**: the field [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Log/Src/Field.rux#L33){rel=""nofollow""} ### `Integer` ```rux pub func Integer(key: char8[..], value: int64) -> Field ``` A field of a signed integer. | Name | Type | Description | | ------- | ----------- | ----------- | | `key` | `char8[..]` | the name | | `value` | `int64` | the number | **Returns**: the field [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Log/Src/Field.rux#L42){rel=""nofollow""} ### `Unsigned` ```rux pub func Unsigned(key: char8[..], value: uint64) -> Field ``` A field of an unsigned integer. | Name | Type | Description | | ------- | ----------- | ----------- | | `key` | `char8[..]` | the name | | `value` | `uint64` | the number | **Returns**: the field [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Log/Src/Field.rux#L51){rel=""nofollow""} ### `Float` ```rux pub func Float(key: char8[..], value: float64) -> Field ``` A field of a floating-point number. | Name | Type | Description | | ------- | ----------- | ----------- | | `key` | `char8[..]` | the name | | `value` | `float64` | the number | **Returns**: the field [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Log/Src/Field.rux#L60){rel=""nofollow""} ### `Boolean` ```rux pub func Boolean(key: char8[..], value: bool) -> Field ``` A field of a truth value. | Name | Type | Description | | ------- | ----------- | ----------- | | `key` | `char8[..]` | the name | | `value` | `bool` | the value | **Returns**: the field [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Log/Src/Field.rux#L69){rel=""nofollow""} # Levels The severity levels, their names, and the level compiled into a build. ## `Level` ```rux pub enum Level: uint8 { Trace = 0, Debug = 1, Info = 2, Warn = 3, Error = 4 } ``` How severe a record is, from the most detailed to the most serious. `Copy`. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Log/Src/Level.rux#L7){rel=""nofollow""} **Cases** | Name | Value | Description | | ------- | ----- | -------------------------------------------------------- | | `Trace` | `0` | The finest detail, for following a program step by step. | | `Debug` | `1` | Detail for diagnosing a problem. | | `Info` | `2` | The ordinary progress of a program. | | `Warn` | `3` | Something unexpected that the program recovered from. | | `Error` | `4` | Something that failed. | **Associated functions** ### `Parse` ```rux pub func Parse(text: char8[..]) -> Level? ``` The level named `text`, in any case; `warning` is read as `warn`. | Name | Type | Description | | ------ | ----------- | ----------- | | `text` | `char8[..]` | the name | **Returns**: the level, or `none` for a name that is not one [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Log/Src/Level.rux#L51){rel=""nofollow""} **Methods** ### `Name` ```rux pub func Name(self: &Level) -> char8[..] ``` The level's name in lower case, as JSON records give it: `trace`, `debug`, `info`, `warn` or `error`. **Returns**: the name [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Log/Src/Level.rux#L24){rel=""nofollow""} ### `Label` ```rux pub func Label(self: &Level) -> char8[..] ``` The level's label in upper case and five columns wide, as text records give it. **Returns**: the label [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Log/Src/Level.rux#L37){rel=""nofollow""} ## `CompiledLevel` ```rux pub func CompiledLevel() -> Level ``` The least severe level this build keeps, from the `LogLevel` build define: `trace`, `debug`, `info`, `warn` or `error`, and `trace` when it is not defined. A record below it is dropped before anything about it is done, whatever level a logger is set to, so a release build can leave out its tracing entirely. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Log/Src/Level.rux#L79){rel=""nofollow""} **Returns**: the level # Logger A logger over any writer: levels, context fields and timestamps. ## `Logger` ```rux pub struct Logger { // private fields } ``` Writes records at or above a level to a stream, each as one write. Not copied. A logging call never fails: the first failure to write is kept for [`Failure`](https://rux-lang.dev/docs/api/log/logger#failure) to report, and the records after it are still attempted. A logger is used by one thread at a time; the process-wide functions such as [`Info`](https://rux-lang.dev/docs/api/log/logger#info) are the ones to share between threads. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Log/Src/Logger.rux#L13){rel=""nofollow""} **Associated functions** ### `New` ```rux pub func New( allocator: Allocator, sink: Writer, format: LogFormat ) -> Logger ``` A logger writing records in `format` to `sink`, at level [`Info`](https://rux-lang.dev/docs/api/log/logger#info) and above, with times. | Name | Type | Description | | ----------- | ----------- | ------------------------------------------------- | | `allocator` | `Allocator` | what each record is built in before it is written | | `sink` | `Writer` | where the records go | | `format` | `LogFormat` | how they are written | **Returns**: the logger [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Log/Src/Logger.rux#L32){rel=""nofollow""} **Methods** ### `SetLevel` ```rux pub func SetLevel(self: &var Logger, level: Level) ``` Writes records at `level` and above from now on. | Name | Type | Description | | ------- | ------- | ------------------------------ | | `level` | `Level` | the least severe level written | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Log/Src/Logger.rux#L47){rel=""nofollow""} ### `MinimumLevel` ```rux pub func MinimumLevel(self: &Logger) -> Level ``` The least severe level written. **Returns**: the level [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Log/Src/Logger.rux#L54){rel=""nofollow""} ### `Enabled` ```rux pub func Enabled(self: &Logger, level: Level) -> bool ``` Whether a record at `level` would be written, by this logger's level and the build's [`CompiledLevel`](https://rux-lang.dev/docs/api/log/level#compiled-level). Worth asking before working out fields that cost something to compute. | Name | Type | Description | | ------- | ------- | ---------------------- | | `level` | `Level` | the level to ask about | **Returns**: whether it would be written [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Log/Src/Logger.rux#L63){rel=""nofollow""} ### `SetTimestamps` ```rux pub func SetTimestamps(self: &var Logger, enabled: bool) ``` Whether records start with the time. Leaving it out suits a destination that adds its own, such as a service manager's journal. | Name | Type | Description | | --------- | ------ | ------------------------- | | `enabled` | `bool` | whether to write the time | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Log/Src/Logger.rux#L71){rel=""nofollow""} ### `SetContext` ```rux pub func SetContext(self: &var Logger, fields: Field[..]) ``` Fields written with every record, before the record's own, such as a request's identifier. | Name | Type | Description | | -------- | ----------- | -------------------------------------------- | | `fields` | `Field[..]` | the fields, borrowed until they are replaced | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Log/Src/Logger.rux#L78){rel=""nofollow""} ### `Failure` ```rux pub func Failure(self: &Logger) -> IoError? ``` The first failure to write a record, or `none` when every record was written. **Returns**: the failure [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Log/Src/Logger.rux#L85){rel=""nofollow""} ### `Log` ```rux pub func Log( self: &var Logger, level: Level, message: char8[..], fields: Field[..] ) ``` Writes a record at `level` with `message` and `fields`, if the level is enabled. | Name | Type | Description | | --------- | ----------- | -------------------------- | | `level` | `Level` | how severe it is | | `message` | `char8[..]` | what happened | | `fields` | `Field[..]` | the values that go with it | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Log/Src/Logger.rux#L94){rel=""nofollow""} ### `Flush` ```rux pub func Flush(self: &var Logger) ``` Asks the stream to deliver what it holds. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Log/Src/Logger.rux#L108){rel=""nofollow""} ### `Trace` ```rux pub func Trace( self: &var Logger, message: char8[..], fields: Field[..] ) pub func Trace(self: &var Logger, message: char8[..]) ``` Writes a `Trace` record with no fields. | Overload | Summary | | -------------------------------------------------------------------------- | --------------------------------------- | | `pub func Trace(self: &var Logger, message: char8[..], fields: Field[..])` | Writes a `Trace` record. | | `pub func Trace(self: &var Logger, message: char8[..])` | Writes a `Trace` record with no fields. | | Name | Type | Description | | --------- | ----------- | -------------------------- | | `message` | `char8[..]` | what happened | | `fields` | `Field[..]` | the values that go with it | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Log/Src/Logger.rux#L121){rel=""nofollow""} ### `Debug` ```rux pub func Debug( self: &var Logger, message: char8[..], fields: Field[..] ) pub func Debug(self: &var Logger, message: char8[..]) ``` Writes a `Debug` record with no fields. | Overload | Summary | | -------------------------------------------------------------------------- | --------------------------------------- | | `pub func Debug(self: &var Logger, message: char8[..], fields: Field[..])` | Writes a `Debug` record. | | `pub func Debug(self: &var Logger, message: char8[..])` | Writes a `Debug` record with no fields. | | Name | Type | Description | | --------- | ----------- | -------------------------- | | `message` | `char8[..]` | what happened | | `fields` | `Field[..]` | the values that go with it | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Log/Src/Logger.rux#L136){rel=""nofollow""} ### `Info` ```rux pub func Info( self: &var Logger, message: char8[..], fields: Field[..] ) pub func Info(self: &var Logger, message: char8[..]) ``` Writes an `Info` record with no fields. | Overload | Summary | | ------------------------------------------------------------------------- | --------------------------------------- | | `pub func Info(self: &var Logger, message: char8[..], fields: Field[..])` | Writes an `Info` record. | | `pub func Info(self: &var Logger, message: char8[..])` | Writes an `Info` record with no fields. | | Name | Type | Description | | --------- | ----------- | -------------------------- | | `message` | `char8[..]` | what happened | | `fields` | `Field[..]` | the values that go with it | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Log/Src/Logger.rux#L151){rel=""nofollow""} ### `Warn` ```rux pub func Warn( self: &var Logger, message: char8[..], fields: Field[..] ) pub func Warn(self: &var Logger, message: char8[..]) ``` Writes a `Warn` record with no fields. | Overload | Summary | | ------------------------------------------------------------------------- | -------------------------------------- | | `pub func Warn(self: &var Logger, message: char8[..], fields: Field[..])` | Writes a `Warn` record. | | `pub func Warn(self: &var Logger, message: char8[..])` | Writes a `Warn` record with no fields. | | Name | Type | Description | | --------- | ----------- | -------------------------- | | `message` | `char8[..]` | what happened | | `fields` | `Field[..]` | the values that go with it | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Log/Src/Logger.rux#L166){rel=""nofollow""} ### `Error` ```rux pub func Error( self: &var Logger, message: char8[..], fields: Field[..] ) pub func Error(self: &var Logger, message: char8[..]) ``` Writes an `Error` record with no fields. | Overload | Summary | | -------------------------------------------------------------------------- | ---------------------------------------- | | `pub func Error(self: &var Logger, message: char8[..], fields: Field[..])` | Writes an `Error` record. | | `pub func Error(self: &var Logger, message: char8[..])` | Writes an `Error` record with no fields. | | Name | Type | Description | | --------- | ----------- | -------------------------- | | `message` | `char8[..]` | what happened | | `fields` | `Field[..]` | the values that go with it | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Log/Src/Logger.rux#L181){rel=""nofollow""} # Records The formats a log record is written in: text or JSON lines. ## `LogFormat` ```rux pub enum LogFormat: uint8 { Text = 0, JsonLines = 1 } ``` How records are written. `Copy`. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Log/Src/Record.rux#L13){rel=""nofollow""} **Cases** | Name | Value | Description | | ----------- | ----- | ----------------------------------------------------------------------------------------------------------------------------------------------------- | | `Text` | `0` | One line of text per record: the time, the level, the message, then each field as `key=value`, with values that hold spaces, quotes or `=` in quotes. | | `JsonLines` | `1` | One JSON object per line, with `time`, `level` and `message` members followed by the fields. | # RotatingFile A log file that starts afresh before a write would take it past a size. ```rux pub struct RotatingFile { // private fields } ``` The current file keeps the path it was opened at. Moving it aside renames it to `path.1`, after renaming an older `path.1` to `path.2` and so on up to `path.<keep>`, whose previous contents are replaced; with `keep` zero the current file is emptied instead. The file is moved aside only before a write, never during one, and a [`Logger`](https://rux-lang.dev/docs/api/log/logger#logger) hands each record over in one write, so a record never spans two files: one larger than the limit goes whole into a file of its own. Move-only: the file closes exactly once, through [`Close`](https://rux-lang.dev/docs/api/log/rotating-file#close) or the destructor. ## Associated functions ### `Open` ```rux pub func Open( allocator: Allocator, path: Path, limit: uint64, keep: uint ) -> RotatingFile ! IoError ``` Opens `path` for appending, creating it if missing, to be moved aside before it grows past `limit` bytes. | Name | Type | Description | | ----------- | ----------- | -------------------------------------------------------------------------- | | `allocator` | `Allocator` | where the storage comes from | | `path` | `Path` | the current log file's path | | `limit` | `uint64` | the size in bytes a write may not take the current file past; at least one | | `keep` | `uint` | how many older files to keep, as `path.1` to `path.<keep>` | **Returns**: the open file, or why it could not be opened; `InvalidInput` for a zero limit or an overlong path [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Log/Src/Rotation.rux#L48){rel=""nofollow""} ## Methods ### `Size` ```rux pub func Size(self: &RotatingFile) -> uint64 ``` How many bytes the current file holds. **Returns**: its size, counting what this value wrote [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Log/Src/Rotation.rux#L61){rel=""nofollow""} ### `Rotate` ```rux pub func Rotate(self: &var RotatingFile) -> ! IoError ``` Moves the current file aside now and starts an empty one, whatever its size. The file is closed first, because Windows renames no open file. A failure leaves the current file closed, and every later write fails with `InvalidHandle` until a rotation succeeds. **Returns**: success when an empty current file is open [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Log/Src/Rotation.rux#L70){rel=""nofollow""} ### `Close` ```rux pub func Close(self: &var RotatingFile) -> ! IoError ``` Closes the current file, reporting what closing it said. **Returns**: success when the file is closed [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Log/Src/Rotation.rux#L88){rel=""nofollow""} ### `Stream` ```rux pub func Stream(self: *var RotatingFile) -> RotatingStream ``` A stored borrow of this file for a [`Logger`](https://rux-lang.dev/docs/api/log/logger#logger), which keeps its destination. The file must outlive the stream and must not be moved while one exists; nothing tracks either. **Returns**: a stream writing through this file [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Log/Src/Rotation.rux#L96){rel=""nofollow""} ## Implements Writer `RotatingFile` conforms to `Writer`. ### `Write` ```rux pub func Write( self: &var RotatingFile, bytes: char8[..] ) -> uint ! IoError ``` Writes `bytes`, moving the current file aside first when they would take it past the limit. An empty current file is never moved aside, so a write larger than the limit lands whole in a fresh file. | Name | Type | Description | | ------- | ----------- | ------------------ | | `bytes` | `char8[..]` | the bytes to write | **Returns**: how many bytes were taken [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Log/Src/Rotation.rux#L107){rel=""nofollow""} ### `Flush` ```rux pub func Flush(self: &var RotatingFile) -> ! IoError ``` Flushes the current file, which holds nothing back. **Returns**: success when everything written reached the system [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Log/Src/Rotation.rux#L119){rel=""nofollow""} # RotatingStream A stored borrow of a [`RotatingFile`](https://rux-lang.dev/docs/api/log/rotating-file) that speaks `Writer`, for a [`Logger`](https://rux-lang.dev/docs/api/log/logger#logger) to keep. ```rux pub struct RotatingStream { // private fields } ``` The address is private, and [`RotatingFile::Stream`](https://rux-lang.dev/docs/api/log/rotating-file#stream) is the only way to obtain one. ## Implements Writer `RotatingStream` conforms to `Writer`. ### `Write` ```rux pub func Write( self: &var RotatingStream, bytes: char8[..] ) -> uint ! IoError ``` Writes through the borrowed file, which may move its current file aside first. | Name | Type | Description | | ------- | ----------- | ------------------ | | `bytes` | `char8[..]` | the bytes to write | **Returns**: how many bytes were taken [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Log/Src/Rotation.rux#L137){rel=""nofollow""} ### `Flush` ```rux pub func Flush(self: &var RotatingStream) -> ! IoError ``` Flushes the borrowed file. **Returns**: success when everything written reached the system [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Log/Src/Rotation.rux#L144){rel=""nofollow""} # Process-wide log The log every thread shares, written to standard error. ## `SetLevel` ```rux pub func SetLevel(level: Level) ``` Writes process-wide records at `level` and above from now on. The level starts as `Info`. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Log/Src/Global.rux#L20){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------- | ------- | ------------------------------ | | `level` | `Level` | the least severe level written | ## `SetFormat` ```rux pub func SetFormat(format: LogFormat) ``` Writes process-wide records in `format` from now on. The format starts as [`Text`](https://rux-lang.dev/docs/api/log/field#text). [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Log/Src/Global.rux#L27){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | ----------- | ----------------------- | | `format` | `LogFormat` | how records are written | ## `SetTimestamps` ```rux pub func SetTimestamps(enabled: bool) ``` Whether process-wide records start with the time. They start with it. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Log/Src/Global.rux#L34){rel=""nofollow""} **Parameters** | Name | Type | Description | | --------- | ------ | ------------------------- | | `enabled` | `bool` | whether to write the time | ## `Enabled` ```rux pub func Enabled(level: Level) -> bool ``` Whether a process-wide record at `level` would be written. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Log/Src/Global.rux#L42){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------- | ------- | ---------------------- | | `level` | `Level` | the level to ask about | **Returns**: whether it would be written ## `Log` ```rux pub func Log( level: Level, message: char8[..], fields: Field[..] ) ``` Writes a process-wide record at `level` with `message` and `fields` to standard error, if the level is enabled. A record that cannot be written is dropped. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Log/Src/Global.rux#L53){rel=""nofollow""} **Parameters** | Name | Type | Description | | --------- | ----------- | -------------------------- | | `level` | `Level` | how severe it is | | `message` | `char8[..]` | what happened | | `fields` | `Field[..]` | the values that go with it | ## `Trace` ```rux pub func Trace(message: char8[..], fields: Field[..]) pub func Trace(message: char8[..]) ``` Writes a process-wide `Trace` record with no fields. | Overload | Summary | | ------------------------------------------------------- | ---------------------------------------------------- | | `pub func Trace(message: char8[..], fields: Field[..])` | Writes a process-wide `Trace` record. | | `pub func Trace(message: char8[..])` | Writes a process-wide `Trace` record with no fields. | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Log/Src/Global.rux#L69){rel=""nofollow""} **Parameters** | Name | Type | Description | | --------- | ----------- | -------------------------- | | `message` | `char8[..]` | what happened | | `fields` | `Field[..]` | the values that go with it | ## `Debug` ```rux pub func Debug(message: char8[..], fields: Field[..]) pub func Debug(message: char8[..]) ``` Writes a process-wide `Debug` record with no fields. | Overload | Summary | | ------------------------------------------------------- | ---------------------------------------------------- | | `pub func Debug(message: char8[..], fields: Field[..])` | Writes a process-wide `Debug` record. | | `pub func Debug(message: char8[..])` | Writes a process-wide `Debug` record with no fields. | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Log/Src/Global.rux#L84){rel=""nofollow""} **Parameters** | Name | Type | Description | | --------- | ----------- | -------------------------- | | `message` | `char8[..]` | what happened | | `fields` | `Field[..]` | the values that go with it | ## `Info` ```rux pub func Info(message: char8[..], fields: Field[..]) pub func Info(message: char8[..]) ``` Writes a process-wide `Info` record with no fields. | Overload | Summary | | ------------------------------------------------------ | --------------------------------------------------- | | `pub func Info(message: char8[..], fields: Field[..])` | Writes a process-wide `Info` record. | | `pub func Info(message: char8[..])` | Writes a process-wide `Info` record with no fields. | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Log/Src/Global.rux#L99){rel=""nofollow""} **Parameters** | Name | Type | Description | | --------- | ----------- | -------------------------- | | `message` | `char8[..]` | what happened | | `fields` | `Field[..]` | the values that go with it | ## `Warn` ```rux pub func Warn(message: char8[..], fields: Field[..]) pub func Warn(message: char8[..]) ``` Writes a process-wide `Warn` record with no fields. | Overload | Summary | | ------------------------------------------------------ | --------------------------------------------------- | | `pub func Warn(message: char8[..], fields: Field[..])` | Writes a process-wide `Warn` record. | | `pub func Warn(message: char8[..])` | Writes a process-wide `Warn` record with no fields. | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Log/Src/Global.rux#L114){rel=""nofollow""} **Parameters** | Name | Type | Description | | --------- | ----------- | -------------------------- | | `message` | `char8[..]` | what happened | | `fields` | `Field[..]` | the values that go with it | ## `Error` ```rux pub func Error(message: char8[..], fields: Field[..]) pub func Error(message: char8[..]) ``` Writes a process-wide `Error` record with no fields. | Overload | Summary | | ------------------------------------------------------- | ---------------------------------------------------- | | `pub func Error(message: char8[..], fields: Field[..])` | Writes a process-wide `Error` record. | | `pub func Error(message: char8[..])` | Writes a process-wide `Error` record with no fields. | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Log/Src/Global.rux#L129){rel=""nofollow""} **Parameters** | Name | Type | Description | | --------- | ----------- | -------------------------- | | `message` | `char8[..]` | what happened | | `fields` | `Field[..]` | the values that go with it | # TimeZone Time zones: the tz database, POSIX rules, the local zone, and local times that happen twice or never. ## Installation Add `TimeZone` to the `[Dependencies]` table of your package's `Rux.toml`: ```toml [Dependencies] TimeZone = { Namespace = "Rux", Version = "0.1.0" } ``` Standard packages are declared by hand: the registry does not serve them, so `rux add Rux/TimeZone` cannot add them. ## Dependencies - [`Allocator`](https://rux-lang.dev/docs/api/allocator) 0.1.0 - [`Collections`](https://rux-lang.dev/docs/api/collections) 0.1.0 - [`Core`](https://rux-lang.dev/docs/api/core) 0.1.0 - [`FileSystem`](https://rux-lang.dev/docs/api/filesystem) 0.1.0 - [`Io`](https://rux-lang.dev/docs/api/io) 0.1.0 - [`Path`](https://rux-lang.dev/docs/api/path) 0.1.0 - [`Process`](https://rux-lang.dev/docs/api/process) 0.1.0 - [`Time`](https://rux-lang.dev/docs/api/time) 0.1.0 - [`Windows`](https://rux-lang.dev/docs/api/windows) 0.1.0 (Windows only) ## Guide ### What it provides | Module | Covers | | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `Zone` | [`TimeZone`](https://rux-lang.dev/docs/api/timezone/zone#time-zone) with [`FromTzif`](https://rux-lang.dev/docs/api/timezone/zone#from-tzif), [`FromRule`](https://rux-lang.dev/docs/api/timezone/zone#from-rule), [`Utc`](https://rux-lang.dev/docs/api/timezone/zone#utc), [`StateAt`](https://rux-lang.dev/docs/api/timezone/zone#state-at), [`OffsetAt`](https://rux-lang.dev/docs/api/timezone/zone#offset-at), [`ToLocal`](https://rux-lang.dev/docs/api/timezone/zone#to-local) and [`Resolve`](https://rux-lang.dev/docs/api/timezone/zone#resolve); [`ZoneState`](https://rux-lang.dev/docs/api/timezone/zone#zone-state) and [`LocalTime`](https://rux-lang.dev/docs/api/timezone/zone#local-time) | | `System` | [`TimeZone::Load`](https://rux-lang.dev/docs/api/timezone/zone#load) by tz database name, and [`TimeZone::Local`](https://rux-lang.dev/docs/api/timezone/zone#local) | | `Error` | [`TimeZoneError`](https://rux-lang.dev/docs/api/timezone/error#time-zone-error) | The module names describe where each declaration comes from; they are not part of an import path. ### Example ```rux import Allocator::SystemAllocator; import Time::Timestamp; import TimeZone::{ TimeZone, TimeZoneError }; func KyivOffset() -> int32 ! TimeZoneError { let zone = TimeZone::Load(SystemAllocator(), "Europe/Kyiv")?; return zone.OffsetAt(Timestamp::Now()).seconds; } ``` ### Design A zone is the tz database's history of the offsets it kept and when they changed, read from a TZif file as RFC 8536 describes it, followed by the POSIX `TZ` rule it keeps after its last listed change; or a rule alone. Versions 1 to 4 of TZif are read, using the 64-bit history and the footer rule from version 2 on; leap-second records are skipped, so the `right/` zones read as their `posix/` twins. Rules take quoted abbreviations such as `<+0330>`, offsets with minutes and seconds, the `Jn`, `n` and `Mm.w.d` dates and the extended change times of TZif version 3, and work south of the equator, where daylight time spans the new year. [`StateAt`](https://rux-lang.dev/docs/api/timezone/zone#state-at) gives a moment's offset, whether it is daylight time, and its abbreviation; [`ToLocal`](https://rux-lang.dev/docs/api/timezone/zone#to-local) gives its local date and time. [`Resolve`](https://rux-lang.dev/docs/api/timezone/zone#resolve) goes the other way, and says whether a local date and time happened once, twice as clocks fell back, or never as they sprang forward, with both candidate moments. [`Load`](https://rux-lang.dev/docs/api/timezone/zone#load) looks a zone up by name in the directory `TZDIR` names, or else in the directories the Unix systems keep the database in. Names that leave the directory are refused. Windows keeps no such directory, so there a zone loads only from a `TZDIR` the program provides. [`Local`](https://rux-lang.dev/docs/api/timezone/zone#local) reads `TZ` or `/etc/localtime` on the Unix systems; on Windows it reads the system's zone as rules for standard and daylight time, which describe current practice rather than the zone's history. ## Index ### Types | Name | Summary | | ------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------- | | [`TimeZoneError`](https://rux-lang.dev/docs/api/timezone/error#time-zone-error) | Why a time zone could not be loaded or built. | | [`ZoneState`](https://rux-lang.dev/docs/api/timezone/zone#zone-state) | The local time a zone keeps at a moment: its offset, whether it is daylight time, and its abbreviation. | | [`LocalTimeKind`](https://rux-lang.dev/docs/api/timezone/zone#local-time-kind) | What a local date and time is in a zone. | | [`LocalTime`](https://rux-lang.dev/docs/api/timezone/zone#local-time) | The moments a local date and time stands for in a zone. | | [`TimeZone`](https://rux-lang.dev/docs/api/timezone/zone#time-zone) | A time zone, built from a TZif file, a POSIX rule, or the system's settings. | # Errors Why a time zone could not be loaded. ## `TimeZoneError` ```rux pub enum TimeZoneError: uint8 { NotFound = 1, InvalidName = 2, InvalidData = 3, InvalidRule = 4, Unreadable = 5, OutOfMemory = 6 } ``` Why a time zone could not be loaded or built. `Copy`. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/TimeZone/Src/Error.rux#L5){rel=""nofollow""} **Cases** | Name | Value | Description | | ------------- | ----- | -------------------------------------------------------------------------------------------------- | | `NotFound` | `1` | No zone of that name was found in any time-zone directory. | | `InvalidName` | `2` | The name is not one a zone can have: empty, absolute, or reaching outside the directory with `..`. | | `InvalidData` | `3` | The zone's data is not a well-formed TZif file. | | `InvalidRule` | `4` | A POSIX `TZ` rule is malformed. | | `Unreadable` | `5` | The zone's file could not be read for a reason other than its absence. | | `OutOfMemory` | `6` | The allocator could not supply the storage. | # Time zones A place's rules: loading them, and converting between UTC and local time. ## `ZoneState` ```rux pub struct ZoneState { pub offset: UtcOffset; pub daylight: bool; pub abbreviation: char8[..]; } ``` The local time a zone keeps at a moment: its offset, whether it is daylight time, and its abbreviation. `Copy`. The abbreviation is a view of the zone's own text, valid while the zone lives. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/TimeZone/Src/Zone.rux#L15){rel=""nofollow""} **Fields** | Name | Type | Description | | -------------- | ----------- | ----------------------------------------------------------------- | | `offset` | `UtcOffset` | The offset from UTC. | | `daylight` | `bool` | Whether this is daylight-saving time. | | `abbreviation` | `char8[..]` | The abbreviation, such as `CEST`, or a numeric one such as `+03`. | ## `LocalTimeKind` ```rux pub enum LocalTimeKind: uint8 { Unique = 0, Ambiguous = 1, Skipped = 2 } ``` What a local date and time is in a zone. `Copy`. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/TimeZone/Src/Zone.rux#L26){rel=""nofollow""} **Cases** | Name | Value | Description | | ----------- | ----- | ---------------------------------------------------------------- | | `Unique` | `0` | The local time happened once. | | `Ambiguous` | `1` | The local time happened twice, as clocks fell back over it. | | `Skipped` | `2` | The local time never happened, as clocks sprang forward over it. | ## `LocalTime` ```rux pub struct LocalTime { pub kind: LocalTimeKind; pub earlier: Timestamp; pub later: Timestamp; } ``` The moments a local date and time stands for in a zone. `Copy`. For a unique time both moments are the same. For an ambiguous one they are its first and second occurrence. For a skipped one they are what it would mean under the offset after the change and before it; `Later` is the one most programs want, as it keeps the wall-clock distance from the hour before. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/TimeZone/Src/Zone.rux#L40){rel=""nofollow""} **Fields** | Name | Type | Description | | --------- | --------------- | ----------------------------------- | | `kind` | `LocalTimeKind` | What the local time is in the zone. | | `earlier` | `Timestamp` | The earlier candidate moment. | | `later` | `Timestamp` | The later candidate moment. | ## `TimeZone` ```rux pub struct TimeZone { // private fields } ``` A time zone, built from a TZif file, a POSIX rule, or the system's settings. Not copied. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/TimeZone/Src/Zone.rux#L51){rel=""nofollow""} **Associated functions** ### `Load` ```rux pub func Load( allocator: Allocator, name: char8[..] ) -> TimeZone ! TimeZoneError ``` Loads the zone named `name` from the tz database: from the directory `TZDIR` names, or else, on the Unix systems, from the directories the database is kept in. | Name | Type | Description | | ----------- | ----------- | --------------------------------------- | | `allocator` | `Allocator` | what the zone is kept in | | `name` | `char8[..]` | the zone's name, such as `Europe/Paris` | **Returns**: the zone, or fails with `NotFound`, `InvalidName` or `InvalidData` [Source](https://github.com/rux-lang/Rux/blob/main/Packages/TimeZone/Src/Zone.rux#L99){rel=""nofollow""} ### `Local` ```rux pub func Local(allocator: Allocator) -> TimeZone ! TimeZoneError ``` The zone the system is set to. On the Unix systems that is the one `TZ` gives, as a zone name, a file path after `:` or a POSIX rule, or else the one in `/etc/localtime`. On Windows it is the system's zone, as rules for its standard and daylight time, which describe the current year's practice and so not the zone's history. | Name | Type | Description | | ----------- | ----------- | ------------------------ | | `allocator` | `Allocator` | what the zone is kept in | **Returns**: the zone, or fails when the system's setting cannot be read [Source](https://github.com/rux-lang/Rux/blob/main/Packages/TimeZone/Src/Zone.rux#L145){rel=""nofollow""} ### `Utc` ```rux pub func Utc(allocator: Allocator) -> TimeZone ! TimeZoneError ``` UTC, which has no offset and never changes. | Name | Type | Description | | ----------- | ----------- | ------------------------ | | `allocator` | `Allocator` | what the zone is kept in | **Returns**: the zone, or fails when the allocator refused [Source](https://github.com/rux-lang/Rux/blob/main/Packages/TimeZone/Src/Zone.rux#L92){rel=""nofollow""} ### `FromRule` ```rux pub func FromRule( allocator: Allocator, name: char8[..], rule: char8[..] ) -> TimeZone ! TimeZoneError ``` A zone kept by the POSIX `TZ` rule `rule`, such as `EST5EDT,M3.2.0,M11.1.0`. | Name | Type | Description | | ----------- | ----------- | ------------------------ | | `allocator` | `Allocator` | what the zone is kept in | | `name` | `char8[..]` | what to call the zone | | `rule` | `char8[..]` | the rule | **Returns**: the zone, or fails with `InvalidRule` [Source](https://github.com/rux-lang/Rux/blob/main/Packages/TimeZone/Src/Zone.rux#L102){rel=""nofollow""} ### `FromTzif` ```rux pub func FromTzif( allocator: Allocator, name: char8[..], data: byte[..] ) -> TimeZone ! TimeZoneError ``` A zone read from TZif data, the format of the files in a time-zone directory. Versions 1 to 4 are read; from version 2 on, the 64-bit history and the footer rule are used. Leap-second records are skipped, so a zone from the `right/` directories reads as its `posix/` twin. | Name | Type | Description | | ----------- | ----------- | -------------------------------------------- | | `allocator` | `Allocator` | what the zone is kept in | | `name` | `char8[..]` | what to call the zone, such as `Europe/Kyiv` | | `data` | `byte[..]` | the TZif data | **Returns**: the zone, or fails with `InvalidData` [Source](https://github.com/rux-lang/Rux/blob/main/Packages/TimeZone/Src/Zone.rux#L116){rel=""nofollow""} **Methods** ### `Name` ```rux pub func Name(self: &TimeZone) -> char8[..] ``` The zone's name. **Returns**: the name it was given or loaded under [Source](https://github.com/rux-lang/Rux/blob/main/Packages/TimeZone/Src/Zone.rux#L191){rel=""nofollow""} ### `StateAt` ```rux pub func StateAt( self: &TimeZone, moment: Timestamp ) -> ZoneState ``` The local time the zone keeps at `moment`. | Name | Type | Description | | -------- | ----------- | ----------- | | `moment` | `Timestamp` | the moment | **Returns**: its offset, whether it is daylight time, and its abbreviation [Source](https://github.com/rux-lang/Rux/blob/main/Packages/TimeZone/Src/Zone.rux#L199){rel=""nofollow""} ### `OffsetAt` ```rux pub func OffsetAt( self: &TimeZone, moment: Timestamp ) -> UtcOffset ``` The zone's offset from UTC at `moment`. | Name | Type | Description | | -------- | ----------- | ----------- | | `moment` | `Timestamp` | the moment | **Returns**: the offset [Source](https://github.com/rux-lang/Rux/blob/main/Packages/TimeZone/Src/Zone.rux#L212){rel=""nofollow""} ### `ToLocal` ```rux pub func ToLocal( self: &TimeZone, moment: Timestamp ) -> OffsetDateTime ``` The local date and time `moment` is in the zone, with its offset. | Name | Type | Description | | -------- | ----------- | ----------- | | `moment` | `Timestamp` | the moment | **Returns**: the local date, time and offset [Source](https://github.com/rux-lang/Rux/blob/main/Packages/TimeZone/Src/Zone.rux#L220){rel=""nofollow""} ### `Resolve` ```rux pub func Resolve( self: &TimeZone, local: DateTime ) -> LocalTime ``` The moments the local date and time `local` stands for in the zone. | Name | Type | Description | | ------- | ---------- | ------------------------------------ | | `local` | `DateTime` | a date and time on the zone's clocks | **Returns**: whether it happened once, twice or never, and the candidate moments [Source](https://github.com/rux-lang/Rux/blob/main/Packages/TimeZone/Src/Zone.rux#L229){rel=""nofollow""} # Net Networking: IP and socket addresses, TCP listeners and streams, UDP sockets, and name resolution. ## Installation Add `Net` to the `[Dependencies]` table of your package's `Rux.toml`: ```toml [Dependencies] Net = { Namespace = "Rux", Version = "0.1.0" } ``` Standard packages are declared by hand: the registry does not serve them, so `rux add Rux/Net` cannot add them. ## Dependencies - [`Allocator`](https://rux-lang.dev/docs/api/allocator) 0.1.0 - [`Collections`](https://rux-lang.dev/docs/api/collections) 0.1.0 - [`Core`](https://rux-lang.dev/docs/api/core) 0.1.0 - [`FreeBSD`](https://rux-lang.dev/docs/api/freebsd) 0.1.0 (FreeBSD only) - [`Io`](https://rux-lang.dev/docs/api/io) 0.1.0 - [`Linux`](https://rux-lang.dev/docs/api/linux) 0.1.0 (Linux only) - [`macOS`](https://rux-lang.dev/docs/api/macos) 0.1.0 (macOS only) - [`Text`](https://rux-lang.dev/docs/api/text) 0.1.0 - [`Time`](https://rux-lang.dev/docs/api/time) 0.1.0 - [`Windows`](https://rux-lang.dev/docs/api/windows) 0.1.0 (Windows only) ## Guide Networking: IPv4 and IPv6 addresses, TCP listeners and streams, UDP sockets, and host name resolution. ### What it provides | Module | Covers | | -------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `Address` | [`Ipv4Address`](https://rux-lang.dev/docs/api/net/address#ipv4-address), [`Ipv6Address`](https://rux-lang.dev/docs/api/net/address#ipv6-address), [`IpAddress`](https://rux-lang.dev/docs/api/net/address#ip-address) and [`SocketAddress`](https://rux-lang.dev/docs/api/net/address#socket-address), each with `Parse`, `WriteText`, `Equals` and `Display` | | `Tcp` | [`TcpListener`](https://rux-lang.dev/docs/api/net/tcp#tcp-listener) with `Bind`, [`Accept`](https://rux-lang.dev/docs/api/net/tcp#accept) and `LocalAddress`; [`TcpStream`](https://rux-lang.dev/docs/api/net/tcp#tcp-stream), an `Io` reader and writer, with `Connect`, [`Shutdown`](https://rux-lang.dev/docs/api/net/tcp#shutdown), [`SetNoDelay`](https://rux-lang.dev/docs/api/net/tcp#set-no-delay) and timeouts; `SetNonBlocking` and `PollSource` on both | | `Udp` | [`UdpSocket`](https://rux-lang.dev/docs/api/net/udp#udp-socket) with `Bind`, [`SendTo`](https://rux-lang.dev/docs/api/net/udp#send-to), [`ReceiveFrom`](https://rux-lang.dev/docs/api/net/udp#receive-from), `Connect`, [`Send`](https://rux-lang.dev/docs/api/net/udp#send), [`Receive`](https://rux-lang.dev/docs/api/net/udp#receive), a read timeout, `SetNonBlocking` and `PollSource`; [`Datagram`](https://rux-lang.dev/docs/api/net/udp#datagram) | | [`Resolve`](https://rux-lang.dev/docs/api/net/resolve#resolve) | [`Resolve`](https://rux-lang.dev/docs/api/net/resolve#resolve), the addresses of a host name | | `Dns` | [`Resolver`](https://rux-lang.dev/docs/api/net/resolver), a DNS client with [`WithServers`](https://rux-lang.dev/docs/api/net/resolver#with-servers), [`FromSystem`](https://rux-lang.dev/docs/api/net/resolver#from-system), [`SetTimeout`](https://rux-lang.dev/docs/api/net/resolver#set-timeout), [`SetAttempts`](https://rux-lang.dev/docs/api/net/resolver#set-attempts) and [`Lookup`](https://rux-lang.dev/docs/api/net/resolver#lookup) | | `Poll` | [`Poller`](https://rux-lang.dev/docs/api/net/poller) with [`Register`](https://rux-lang.dev/docs/api/net/poller#register), [`Modify`](https://rux-lang.dev/docs/api/net/poller#modify), [`Deregister`](https://rux-lang.dev/docs/api/net/poller#deregister) and [`Wait`](https://rux-lang.dev/docs/api/net/poller#wait); [`Interest`](https://rux-lang.dev/docs/api/net/poller#interest), `PollSource` and [`PollEvent`](https://rux-lang.dev/docs/api/net/poller#poll-event) | The module names describe where each declaration comes from; they are not part of an import path. ### Example ```rux import Allocator::SystemAllocator; import Io::{ IoError, ReadExact, WriteAll }; import Net::{ Resolve, TcpStream }; func Greet(host: char8[..]) -> ! IoError { let addresses = Resolve(SystemAllocator(), host, 7)?; var stream = TcpStream::Connect(addresses.AsSlice()[0])?; WriteAll(stream, "hello")?; var echoed: char8[5] = ['\0'; 5]; ReadExact(stream, echoed[..])?; } ``` ### Design Sockets block by default: a call waits until it can do its work, or until the timeout set for it runs out and it fails with `TimedOut`. `SetNonBlocking` makes a socket's calls fail with `WouldBlock` instead whenever they would wait, and a [`Poller`](https://rux-lang.dev/docs/api/net/poller) says when they would not: sockets are registered with a token and the readiness wanted, and [`Wait`](https://rux-lang.dev/docs/api/net/poller#wait) reports the ready ones by token, waiting up to a timeout. It is level-triggered, so a socket is reported for as long as it is ready, and runs on epoll on Linux, kqueue on FreeBSD and macOS, and `WSAPoll` on Windows. A stream a listener accepts starts blocking whatever the listener is. Failures are `Io::IoError` values, so a [`TcpStream`](https://rux-lang.dev/docs/api/net/tcp#tcp-stream) passes straight to anything that takes an `Io` reader or writer, and the reasons a connection fails — refused, reset, aborted, unreachable, an address in use — have kinds of their own. Writing to a connection the peer has closed fails with `BrokenPipe` rather than ending the process with a signal. Every socket is closed when its value is dropped, and none is inherited by a child process. Addresses are plain values. IPv4 addresses are read in the four-part decimal form only, without the leading zeros some systems read as octal; IPv6 addresses take the `::` shorthand and an embedded IPv4 tail, and are written as RFC 5952 asks, in lower case with the longest run of zeros shortened and an IPv4-mapped address with its IPv4 tail, as in `::ffff:192.0.2.1`. A socket address writes an IPv6 address in brackets, as in `[::1]:8080`. Every address type also renders through `{}`, padded to the placeholder's width, and answers `IsLoopback`, `IsUnspecified`, `IsPrivate` (RFC 1918, or a unique local IPv6 address), `IsLinkLocal` and `IsMulticast`. On Linux and FreeBSD the sockets are system calls. On macOS they come from libSystem and on Windows from Winsock, which is started the first time a socket is opened. On FreeBSD, macOS and Windows [`Resolve`](https://rux-lang.dev/docs/api/net/resolve#resolve) asks the system's resolver, `getaddrinfo`, so names resolve as they do for every other program on the machine. On Linux that resolver belongs to the C library, so [`Resolve`](https://rux-lang.dev/docs/api/net/resolve#resolve) reads `/etc/hosts` and asks the name servers in `/etc/resolv.conf` itself, and a program that resolves names stays a static binary; search domains and the name service switch are not followed. [`Resolver`](https://rux-lang.dev/docs/api/net/resolver) is that DNS client, usable on every system with servers of the caller's choosing: it asks each server in turn for the IPv4 and then the IPv6 addresses over UDP, and over TCP when an answer is too long for a datagram. A numeric host is read directly. ## Index ### Types | Name | Summary | | ------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------- | | [`Ipv4Address`](https://rux-lang.dev/docs/api/net/address#ipv4-address) | An IPv4 address. | | [`Ipv6Address`](https://rux-lang.dev/docs/api/net/address#ipv6-address) | An IPv6 address. | | [`IpAddress`](https://rux-lang.dev/docs/api/net/address#ip-address) | An IPv4 or IPv6 address. | | [`SocketAddress`](https://rux-lang.dev/docs/api/net/address#socket-address) | An IP address and a port: where a socket is bound or connected. | | [`Resolver`](https://rux-lang.dev/docs/api/net/resolver) | Asks name servers for a host's addresses. | | [`Interest`](https://rux-lang.dev/docs/api/net/poller#interest) | The readiness a registration waits for. | | [`PollSource`](https://rux-lang.dev/docs/api/net/poller#poll-source) | A socket as a [`Poller`](https://rux-lang.dev/docs/api/net/poller) watches it, from the socket's `PollSource`. | | [`PollEvent`](https://rux-lang.dev/docs/api/net/poller#poll-event) | One socket a wait found ready. | | [`Poller`](https://rux-lang.dev/docs/api/net/poller) | Waits on many sockets at once. | | [`TcpListener`](https://rux-lang.dev/docs/api/net/tcp#tcp-listener) | A socket listening for TCP connections. | | [`TcpStream`](https://rux-lang.dev/docs/api/net/tcp#tcp-stream) | A connected TCP stream: an `Io::Reader` of what the peer sends and an `Io::Writer` to it. | | [`ShutdownDirection`](https://rux-lang.dev/docs/api/net/tcp#shutdown-direction) | Which directions of a connection [`Shutdown`](https://rux-lang.dev/docs/api/net/tcp#shutdown) ends. | | [`Datagram`](https://rux-lang.dev/docs/api/net/udp#datagram) | A datagram received, and where it came from. | | [`UdpSocket`](https://rux-lang.dev/docs/api/net/udp#udp-socket) | A UDP socket. | ### Functions | Name | Summary | | -------------------------------------------------------------- | --------------------------------------------------------------------------------------------------- | | [`Resolve`](https://rux-lang.dev/docs/api/net/resolve#resolve) | The addresses of `host`, each with `port`, in the order the resolver prefers them, without repeats. | # Addresses IPv4, IPv6 and socket addresses: reading them, writing them and classifying them. ## `Ipv4Address` ```rux pub struct Ipv4Address { pub octets: uint8[N]; } ``` An IPv4 address. `Copy`. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Net/Src/Address.rux#L12){rel=""nofollow""} **Fields** | Name | Type | Description | | -------- | ---------- | ---------------------------------------- | | `octets` | `uint8[N]` | The four octets, most significant first. | **Associated functions** ### `New` ```rux pub func New( a: uint8, b: uint8, c: uint8, d: uint8 ) -> Ipv4Address ``` The address `a.b.c.d`. | Name | Type | Description | | ---- | ------- | ---------------- | | `a` | `uint8` | the first octet | | `b` | `uint8` | the second octet | | `c` | `uint8` | the third octet | | `d` | `uint8` | the fourth octet | **Returns**: the address [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Net/Src/Address.rux#L87){rel=""nofollow""} ### `Localhost` ```rux pub func Localhost() -> Ipv4Address ``` `127.0.0.1`, this machine. **Returns**: the loopback address [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Net/Src/Address.rux#L94){rel=""nofollow""} ### `Unspecified` ```rux pub func Unspecified() -> Ipv4Address ``` `0.0.0.0`, every address of this machine when binding. **Returns**: the unspecified address [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Net/Src/Address.rux#L101){rel=""nofollow""} ### `Parse` ```rux pub func Parse(text: char8[..]) -> Ipv4Address? ``` Reads dotted-decimal text such as `192.168.0.1`, each octet without leading zeros. | Name | Type | Description | | ------ | ----------- | ----------- | | `text` | `char8[..]` | the text | **Returns**: the address, or none when the text is not one [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Net/Src/Address.rux#L109){rel=""nofollow""} **Methods** ### `IsLoopback` ```rux pub func IsLoopback(self: &Ipv4Address) -> bool ``` Whether this is a loopback address, in `127.0.0.0/8`. **Returns**: true for loopback [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Net/Src/Address.rux#L137){rel=""nofollow""} ### `IsUnspecified` ```rux pub func IsUnspecified(self: &Ipv4Address) -> bool ``` Whether this is the unspecified address, `0.0.0.0`, which binds every local address. **Returns**: true for `0.0.0.0` [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Net/Src/Address.rux#L144){rel=""nofollow""} ### `IsPrivate` ```rux pub func IsPrivate(self: &Ipv4Address) -> bool ``` Whether this is a private address of RFC 1918: in `10.0.0.0/8`, `172.16.0.0/12` or `192.168.0.0/16`. **Returns**: true for a private address [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Net/Src/Address.rux#L151){rel=""nofollow""} ### `IsLinkLocal` ```rux pub func IsLinkLocal(self: &Ipv4Address) -> bool ``` Whether this is a link-local address, in `169.254.0.0/16`. **Returns**: true for a link-local address [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Net/Src/Address.rux#L159){rel=""nofollow""} ### `IsMulticast` ```rux pub func IsMulticast(self: &Ipv4Address) -> bool ``` Whether this is a multicast address, in `224.0.0.0/4`. **Returns**: true for a multicast address [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Net/Src/Address.rux#L166){rel=""nofollow""} ### `WriteText` ```rux pub func WriteText( self: &Ipv4Address, into: var char8[..] ) -> uint ``` Writes the address in dotted-decimal form into `into`, at most 15 characters. | Name | Type | Description | | ------ | --------------- | -------------- | | `into` | `var char8[..]` | where to write | **Returns**: how many characters the text takes, which is more than were written when `into` is too short [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Net/Src/Address.rux#L174){rel=""nofollow""} ### `Equals` ```rux pub func Equals( self: &Ipv4Address, other: Ipv4Address ) -> bool ``` Whether two addresses are the same. | Name | Type | Description | | ------- | ------------- | --------------------------- | | `other` | `Ipv4Address` | the address to compare with | **Returns**: true when they are equal [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Net/Src/Address.rux#L189){rel=""nofollow""} **Implements Display** `Ipv4Address` conforms to `Display`. ### `WriteDisplay` ```rux pub func WriteDisplay( self: &Ipv4Address, writer: &var TextWriter, spec: FormatSpec ) -> ! FormatError ``` Writes the address in dotted-decimal form, under the placeholder's width, fill and alignment. No style is understood. Reports whatever the writer reported, and `UnsupportedRequest` for a style. | Name | Type | Description | | -------- | ----------------- | ------------------------------ | | `writer` | `&var TextWriter` | the destination | | `spec` | `FormatSpec` | what the placeholder asked for | **Returns**: success when the whole address was accepted [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Net/Src/Address.rux#L639){rel=""nofollow""} ## `Ipv6Address` ```rux pub struct Ipv6Address { pub octets: uint8[N]; } ``` An IPv6 address. `Copy`. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Net/Src/Address.rux#L19){rel=""nofollow""} **Fields** | Name | Type | Description | | -------- | ---------- | ------------------------------------------- | | `octets` | `uint8[N]` | The sixteen octets, most significant first. | **Associated functions** ### `Localhost` ```rux pub func Localhost() -> Ipv6Address ``` `::1`, this machine. **Returns**: the loopback address [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Net/Src/Address.rux#L199){rel=""nofollow""} ### `Unspecified` ```rux pub func Unspecified() -> Ipv6Address ``` `::`, every address of this machine when binding. **Returns**: the unspecified address [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Net/Src/Address.rux#L208){rel=""nofollow""} ### `Parse` ```rux pub func Parse(text: char8[..]) -> Ipv6Address? ``` Reads text such as `2001:db8::1` or `::ffff:192.0.2.1`. A zone such as `%eth0` is not accepted. | Name | Type | Description | | ------ | ----------- | ----------- | | `text` | `char8[..]` | the text | **Returns**: the address, or none when the text is not one [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Net/Src/Address.rux#L216){rel=""nofollow""} **Methods** ### `IsLoopback` ```rux pub func IsLoopback(self: &Ipv6Address) -> bool ``` Whether this is the loopback address, `::1`. **Returns**: true for loopback [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Net/Src/Address.rux#L299){rel=""nofollow""} ### `IsUnspecified` ```rux pub func IsUnspecified(self: &Ipv6Address) -> bool ``` Whether this is the unspecified address, `::`, which binds every local address. **Returns**: true for `::` [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Net/Src/Address.rux#L311){rel=""nofollow""} ### `IsPrivate` ```rux pub func IsPrivate(self: &Ipv6Address) -> bool ``` Whether this is a unique local address of RFC 4193, in `fc00::/7`: the IPv6 counterpart of a private IPv4 address. **Returns**: true for a unique local address [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Net/Src/Address.rux#L324){rel=""nofollow""} ### `IsLinkLocal` ```rux pub func IsLinkLocal(self: &Ipv6Address) -> bool ``` Whether this is a link-local address, in `fe80::/10`. **Returns**: true for a link-local address [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Net/Src/Address.rux#L331){rel=""nofollow""} ### `IsMulticast` ```rux pub func IsMulticast(self: &Ipv6Address) -> bool ``` Whether this is a multicast address, in `ff00::/8`. **Returns**: true for a multicast address [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Net/Src/Address.rux#L338){rel=""nofollow""} ### `AsMappedIpv4` ```rux pub func AsMappedIpv4(self: &Ipv6Address) -> Ipv4Address? ``` The IPv4 address this one maps, for an address in `::ffff:0:0/96`, or none for any other. **Returns**: the mapped IPv4 address [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Net/Src/Address.rux#L345){rel=""nofollow""} ### `WriteText` ```rux pub func WriteText( self: &Ipv6Address, into: var char8[..] ) -> uint ``` Writes the address in the canonical form of RFC 5952 into `into`, at most 45 characters. An IPv4-mapped address keeps its IPv4 tail in dotted-decimal form, as `::ffff:192.0.2.1`. | Name | Type | Description | | ------ | --------------- | -------------- | | `into` | `var char8[..]` | where to write | **Returns**: how many characters the text takes, which is more than were written when `into` is too short [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Net/Src/Address.rux#L360){rel=""nofollow""} ### `Equals` ```rux pub func Equals( self: &Ipv6Address, other: Ipv6Address ) -> bool ``` Whether two addresses are the same. | Name | Type | Description | | ------- | ------------- | --------------------------- | | `other` | `Ipv6Address` | the address to compare with | **Returns**: true when they are equal [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Net/Src/Address.rux#L422){rel=""nofollow""} **Implements Display** `Ipv6Address` conforms to `Display`. ### `WriteDisplay` ```rux pub func WriteDisplay( self: &Ipv6Address, writer: &var TextWriter, spec: FormatSpec ) -> ! FormatError ``` Writes the address in the canonical form of RFC 5952, under the placeholder's width, fill and alignment. No style is understood. Reports whatever the writer reported, and `UnsupportedRequest` for a style. | Name | Type | Description | | -------- | ----------------- | ------------------------------ | | `writer` | `&var TextWriter` | the destination | | `spec` | `FormatSpec` | what the placeholder asked for | **Returns**: success when the whole address was accepted [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Net/Src/Address.rux#L654){rel=""nofollow""} ## `IpAddress` ```rux pub struct IpAddress { // private fields } ``` An IPv4 or IPv6 address. `Copy`. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Net/Src/Address.rux#L26){rel=""nofollow""} **Associated functions** ### `FromIpv4` ```rux pub func FromIpv4(address: Ipv4Address) -> IpAddress ``` An IPv4 address as an IP address. | Name | Type | Description | | --------- | ------------- | ---------------- | | `address` | `Ipv4Address` | the IPv4 address | **Returns**: the IP address [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Net/Src/Address.rux#L437){rel=""nofollow""} ### `FromIpv6` ```rux pub func FromIpv6(address: Ipv6Address) -> IpAddress ``` An IPv6 address as an IP address. | Name | Type | Description | | --------- | ------------- | ---------------- | | `address` | `Ipv6Address` | the IPv6 address | **Returns**: the IP address [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Net/Src/Address.rux#L445){rel=""nofollow""} ### `Parse` ```rux pub func Parse(text: char8[..]) -> IpAddress? ``` Reads an IPv4 or IPv6 address. | Name | Type | Description | | ------ | ----------- | ----------- | | `text` | `char8[..]` | the text | **Returns**: the address, or none when the text is neither [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Net/Src/Address.rux#L453){rel=""nofollow""} **Methods** ### `IsIpv6` ```rux pub func IsIpv6(self: &IpAddress) -> bool ``` Whether this is an IPv6 address. **Returns**: true for IPv6 [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Net/Src/Address.rux#L467){rel=""nofollow""} ### `AsIpv4` ```rux pub func AsIpv4(self: &IpAddress) -> Ipv4Address? ``` The IPv4 address, or none for an IPv6 one. **Returns**: the IPv4 address [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Net/Src/Address.rux#L474){rel=""nofollow""} ### `AsIpv6` ```rux pub func AsIpv6(self: &IpAddress) -> Ipv6Address? ``` The IPv6 address, or none for an IPv4 one. **Returns**: the IPv6 address [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Net/Src/Address.rux#L482){rel=""nofollow""} ### `IsLoopback` ```rux pub func IsLoopback(self: &IpAddress) -> bool ``` Whether this is a loopback address. **Returns**: true for loopback [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Net/Src/Address.rux#L490){rel=""nofollow""} ### `IsUnspecified` ```rux pub func IsUnspecified(self: &IpAddress) -> bool ``` Whether this is the unspecified address, `0.0.0.0` or `::`. **Returns**: true for the unspecified address [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Net/Src/Address.rux#L497){rel=""nofollow""} ### `IsPrivate` ```rux pub func IsPrivate(self: &IpAddress) -> bool ``` Whether this is a private IPv4 address or a unique local IPv6 address. **Returns**: true for a private address [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Net/Src/Address.rux#L504){rel=""nofollow""} ### `IsLinkLocal` ```rux pub func IsLinkLocal(self: &IpAddress) -> bool ``` Whether this is a link-local address. **Returns**: true for a link-local address [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Net/Src/Address.rux#L511){rel=""nofollow""} ### `IsMulticast` ```rux pub func IsMulticast(self: &IpAddress) -> bool ``` Whether this is a multicast address. **Returns**: true for a multicast address [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Net/Src/Address.rux#L518){rel=""nofollow""} ### `WriteText` ```rux pub func WriteText( self: &IpAddress, into: var char8[..] ) -> uint ``` Writes the address into `into`, at most 45 characters. | Name | Type | Description | | ------ | --------------- | -------------- | | `into` | `var char8[..]` | where to write | **Returns**: how many characters the text takes [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Net/Src/Address.rux#L526){rel=""nofollow""} ### `Equals` ```rux pub func Equals(self: &IpAddress, other: IpAddress) -> bool ``` Whether two addresses are the same, which an IPv4 and an IPv6 address never are. | Name | Type | Description | | ------- | ----------- | --------------------------- | | `other` | `IpAddress` | the address to compare with | **Returns**: true when they are equal [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Net/Src/Address.rux#L534){rel=""nofollow""} **Implements Display** `IpAddress` conforms to `Display`. ### `WriteDisplay` ```rux pub func WriteDisplay( self: &IpAddress, writer: &var TextWriter, spec: FormatSpec ) -> ! FormatError ``` Writes the address as its IPv4 or IPv6 form does, under the placeholder's width, fill and alignment. No style is understood. Reports whatever the writer reported, and `UnsupportedRequest` for a style. | Name | Type | Description | | -------- | ----------------- | ------------------------------ | | `writer` | `&var TextWriter` | the destination | | `spec` | `FormatSpec` | what the placeholder asked for | **Returns**: success when the whole address was accepted [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Net/Src/Address.rux#L669){rel=""nofollow""} ## `SocketAddress` ```rux pub struct SocketAddress { pub ip: IpAddress; pub port: uint16; } ``` An IP address and a port: where a socket is bound or connected. `Copy`. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Net/Src/Address.rux#L34){rel=""nofollow""} **Fields** | Name | Type | Description | | ------ | ----------- | ------------ | | `ip` | `IpAddress` | The address. | | `port` | `uint16` | The port. | **Associated functions** ### `New` ```rux pub func New(ip: IpAddress, port: uint16) -> SocketAddress ``` An address and a port. | Name | Type | Description | | ------ | ----------- | ----------- | | `ip` | `IpAddress` | the address | | `port` | `uint16` | the port | **Returns**: the socket address [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Net/Src/Address.rux#L546){rel=""nofollow""} ### `Parse` ```rux pub func Parse(text: char8[..]) -> SocketAddress? ``` Reads `address:port`, with an IPv6 address in brackets, as in `[::1]:8080`. | Name | Type | Description | | ------ | ----------- | ----------- | | `text` | `char8[..]` | the text | **Returns**: the socket address, or none when the text is not one [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Net/Src/Address.rux#L554){rel=""nofollow""} **Methods** ### `WriteText` ```rux pub func WriteText( self: &SocketAddress, into: var char8[..] ) -> uint ``` Writes `address:port` into `into`, an IPv6 address in brackets, at most 47 characters. | Name | Type | Description | | ------ | --------------- | -------------- | | `into` | `var char8[..]` | where to write | **Returns**: how many characters the text takes [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Net/Src/Address.rux#L597){rel=""nofollow""} ### `ToString` ```rux pub func ToString( self: &SocketAddress, allocator: Allocator ) -> String ! TextError ``` The text of the address, as [`WriteText`](https://rux-lang.dev/docs/api/net/address#socket-address-write-text) writes it. | Name | Type | Description | | ----------- | ----------- | ------------------------ | | `allocator` | `Allocator` | what the text is kept in | **Returns**: the text [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Net/Src/Address.rux#L615){rel=""nofollow""} ### `Equals` ```rux pub func Equals( self: &SocketAddress, other: SocketAddress ) -> bool ``` Whether two socket addresses are the same. | Name | Type | Description | | ------- | --------------- | --------------------------- | | `other` | `SocketAddress` | the address to compare with | **Returns**: true when they are equal [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Net/Src/Address.rux#L625){rel=""nofollow""} **Implements Display** `SocketAddress` conforms to `Display`. ### `WriteDisplay` ```rux pub func WriteDisplay( self: &SocketAddress, writer: &var TextWriter, spec: FormatSpec ) -> ! FormatError ``` Writes the address and port, an IPv6 address in brackets, under the placeholder's width, fill and alignment. No style is understood. Reports whatever the writer reported, and `UnsupportedRequest` for a style. | Name | Type | Description | | -------- | ----------------- | ------------------------------ | | `writer` | `&var TextWriter` | the destination | | `spec` | `FormatSpec` | what the placeholder asked for | **Returns**: success when the whole address was accepted [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Net/Src/Address.rux#L684){rel=""nofollow""} # Poller Waits on many sockets at once. ```rux pub struct Poller { // private fields } ``` Not copied. ## Associated functions ### `New` ```rux pub func New(allocator: Allocator) -> Poller ! IoError ``` A poller with no sockets registered. | Name | Type | Description | | ----------- | ----------- | -------------------------------------------------------------- | | `allocator` | `Allocator` | where Windows' registrations and the room for events come from | **Returns**: the poller, or why the system would not make one [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Net/Src/Poll.rux#L134){rel=""nofollow""} ## Methods ### `Register` ```rux pub func Register( self: &var Poller, source: PollSource, token: uint64, interest: Interest ) -> ! IoError ``` Watches `source` for `interest`, reporting it with `token`. | Name | Type | Description | | ---------- | ------------ | ------------------------------------------ | | `source` | `PollSource` | the socket | | `token` | `uint64` | the word reported with the socket's events | | `interest` | `Interest` | the readiness wanted | **Returns**: success, or `AlreadyExists` when the socket is registered already [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Net/Src/Poll.rux#L159){rel=""nofollow""} ### `Modify` ```rux pub func Modify( self: &var Poller, source: PollSource, token: uint64, interest: Interest ) -> ! IoError ``` Changes what a registered socket is watched for, and the token it is reported with. | Name | Type | Description | | ---------- | ------------ | ------------------------------------------ | | `source` | `PollSource` | the socket | | `token` | `uint64` | the word reported with the socket's events | | `interest` | `Interest` | the readiness wanted | **Returns**: success, or `NotFound` when the socket is not registered [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Net/Src/Poll.rux#L169){rel=""nofollow""} ### `Deregister` ```rux pub func Deregister( self: &var Poller, source: PollSource ) -> ! IoError ``` Stops watching a socket. | Name | Type | Description | | -------- | ------------ | ----------- | | `source` | `PollSource` | the socket | **Returns**: success, or `NotFound` when the socket is not registered [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Net/Src/Poll.rux#L177){rel=""nofollow""} ### `Wait` ```rux pub func Wait( self: &var Poller, events: var PollEvent[..], timeout: Duration? ) -> uint ! IoError ``` Waits until a registered socket is ready or `timeout` passes, and reports the ready sockets into `events`. | Name | Type | Description | | --------- | ------------------- | -------------------------------------------------------------------------------------------- | | `events` | `var PollEvent[..]` | room for the events; a wait reports at most this many, and the rest are reported by the next | | `timeout` | `Duration?` | how long to wait, zero to only look, or `none` to wait without end | **Returns**: how many events were filled; zero after the timeout or when a signal ended the wait early [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Net/Src/Poll.rux#L200){rel=""nofollow""} ## Destructor ```rux func ~Poller(self: &var Poller) ``` [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Net/Src/Poll.rux#L373){rel=""nofollow""} ## Related ### `Interest` ```rux pub struct Interest { pub readable: bool; pub writable: bool; } ``` The readiness a registration waits for. `Copy`. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Net/Src/Poll.rux#L35){rel=""nofollow""} **Fields** | Name | Type | Description | | ---------- | ------ | --------------------------------------------- | | `readable` | `bool` | Something to read, or a connection to accept. | | `writable` | `bool` | Room to write. | **Associated functions** #### `Readable` ```rux pub func Readable() -> Interest ``` Waiting for something to read, or a connection to accept. **Returns**: the interest [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Net/Src/Poll.rux#L46){rel=""nofollow""} #### `Writable` ```rux pub func Writable() -> Interest ``` Waiting for room to write. **Returns**: the interest [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Net/Src/Poll.rux#L53){rel=""nofollow""} #### `Both` ```rux pub func Both() -> Interest ``` Waiting for either. **Returns**: the interest [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Net/Src/Poll.rux#L60){rel=""nofollow""} ### `PollSource` ```rux pub struct PollSource { // private fields } ``` A socket as a [`Poller`](https://rux-lang.dev/docs/api/net/poller) watches it, from the socket's `PollSource`. It does not keep the socket open, so it is deregistered before the socket is dropped. `Copy`. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Net/Src/Poll.rux#L68){rel=""nofollow""} ### `PollEvent` ```rux pub struct PollEvent { pub token: uint64; pub readable: bool; pub writable: bool; pub closed: bool; } ``` One socket a wait found ready. `Copy`. A socket ready both to read and to write may be reported once with both, or once for each. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Net/Src/Poll.rux#L75){rel=""nofollow""} **Fields** | Name | Type | Description | | ---------- | -------- | --------------------------------------------------------------------------------------------- | | `token` | `uint64` | The token the socket was registered with. | | `readable` | `bool` | A read would not wait, or a listener has a connection to accept. | | `writable` | `bool` | A write would not wait. | | `closed` | `bool` | The peer has closed the connection or an error is pending; the next read or write says which. | **Constructors** #### `PollEvent` ```rux pub func PollEvent() -> PollEvent ``` An event for nothing, to fill the room a wait reports into. **Returns**: the event [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Net/Src/Poll.rux#L90){rel=""nofollow""} # Resolver Asks name servers for a host's addresses. ```rux pub struct Resolver { // private fields } ``` Not copied. A query goes to each server in turn, for the IPv4 addresses and then the IPv6 ones, until a server answers; the whole round is tried again as many times as the attempts allow. Each query waits for its answer up to the timeout, and a name the server says does not exist ends the lookup at once. ## Associated functions ### `WithServers` ```rux pub func WithServers( allocator: Allocator, servers: SocketAddress[..] ) -> Resolver ``` A resolver that asks `servers`, waiting five seconds for each answer and going round them twice. | Name | Type | Description | | ----------- | ------------------- | ------------------------------------------------------------------- | | `allocator` | `Allocator` | what the server list and every lookup's results are kept in | | `servers` | `SocketAddress[..]` | the name servers, in the order they are asked; port 53 is DNS's own | **Returns**: the resolver [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Net/Src/Dns.rux#L152){rel=""nofollow""} ### `FromSystem` ```rux pub func FromSystem(allocator: Allocator) -> Resolver ``` A resolver configured as the C library's would be: the name servers, and the `timeout` and `attempts` options, of `/etc/resolv.conf` on Linux. With no servers to read, the one on this machine is asked. | Name | Type | Description | | ----------- | ----------- | ----------------------------------------------------------- | | `allocator` | `Allocator` | what the server list and every lookup's results are kept in | **Returns**: the resolver [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Net/Src/Dns.rux#L164){rel=""nofollow""} ## Methods ### `SetTimeout` ```rux pub func SetTimeout(self: &var Resolver, timeout: Duration) ``` How long a query waits for its answer. | Name | Type | Description | | --------- | ---------- | ------------------------ | | `timeout` | `Duration` | the wait for each answer | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Net/Src/Dns.rux#L171){rel=""nofollow""} ### `SetAttempts` ```rux pub func SetAttempts(self: &var Resolver, attempts: uint) ``` How many times the servers are gone round before a lookup gives up. | Name | Type | Description | | ---------- | ------ | ---------------------------------- | | `attempts` | `uint` | the number of rounds, at least one | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Net/Src/Dns.rux#L178){rel=""nofollow""} ### `Lookup` ```rux pub func Lookup( self: &Resolver, allocator: Allocator, host: char8[..], port: uint16 ) -> Vector<SocketAddress> ! IoError ``` Asks the servers for `host`'s addresses: its IPv4 addresses first, then its IPv6 ones, each with `port`. The hosts file is not read; [`Resolve`](https://rux-lang.dev/docs/api/net/resolve#resolve) reads it first. | Name | Type | Description | | ----------- | ----------- | ------------------------------- | | `allocator` | `Allocator` | what the list is kept in | | `host` | `char8[..]` | the name, such as `example.com` | | `port` | `uint16` | the port every address gets | **Returns**: the addresses; `NotFound` when the name has none or does not exist, `TimedOut` when no server answered [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Net/Src/Dns.rux#L189){rel=""nofollow""} # TCP Listeners that accept connections, and the streams they produce. ## `TcpListener` ```rux pub struct TcpListener { // private fields } ``` A socket listening for TCP connections. Not copied. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Net/Src/Tcp.rux#L16){rel=""nofollow""} **Associated functions** ### `Bind` ```rux pub func Bind(address: SocketAddress) -> TcpListener ! IoError ``` Listens at `address`. Port zero lets the system choose a free port, which [`LocalAddress`](https://rux-lang.dev/docs/api/net/tcp#listener-local-address) then gives. | Name | Type | Description | | --------- | --------------- | --------------------------------------------------------------------------------------- | | `address` | `SocketAddress` | the address to listen at, such as `127.0.0.1:8080`, or `0.0.0.0:8080` for every address | **Returns**: the listener, or fails with `AddressInUse`, `AddressUnavailable` or `PermissionDenied` [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Net/Src/Tcp.rux#L44){rel=""nofollow""} **Methods** ### `Accept` ```rux pub func Accept(self: &TcpListener) -> TcpStream ! IoError ``` Waits for a connection and accepts it. **Returns**: the connected stream, whose [`PeerAddress`](https://rux-lang.dev/docs/api/net/tcp#peer-address) says who connected [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Net/Src/Tcp.rux#L55){rel=""nofollow""} ### `LocalAddress` ```rux pub func LocalAddress(self: &TcpListener) -> SocketAddress ! IoError ``` The address the listener is bound to, with the port the system chose for port zero. **Returns**: the address [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Net/Src/Tcp.rux#L64){rel=""nofollow""} ### `SetNonBlocking` ```rux pub func SetNonBlocking( self: &TcpListener, enabled: bool ) -> ! IoError ``` Makes calls on the listener fail with `WouldBlock` when they would wait, or wait again. A non-blocking socket is meant for a [`Poller`](https://rux-lang.dev/docs/api/net/poller), which says when a call would not wait. [`Accept`](https://rux-lang.dev/docs/api/net/tcp#accept) then fails with `WouldBlock` when no connection is waiting; the streams it gives start blocking all the same. | Name | Type | Description | | --------- | ------ | ----------------------------------- | | `enabled` | `bool` | whether calls fail rather than wait | **Returns**: success when the mode is set [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Net/Src/Tcp.rux#L74){rel=""nofollow""} ### `PollSource` ```rux pub func PollSource(self: &TcpListener) -> PollSource ``` The listener as a [`Poller`](https://rux-lang.dev/docs/api/net/poller) watches it, valid while the listener is open. **Returns**: the source to register [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Net/Src/Tcp.rux#L81){rel=""nofollow""} **Destructor** ### `~TcpListener` ```rux func ~TcpListener(self: &var TcpListener) ``` [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Net/Src/Tcp.rux#L85){rel=""nofollow""} ## `TcpStream` ```rux pub struct TcpStream { // private fields } ``` A connected TCP stream: an `Io::Reader` of what the peer sends and an `Io::Writer` to it. Not copied. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Net/Src/Tcp.rux#L22){rel=""nofollow""} **Associated functions** ### `Connect` ```rux pub func Connect(address: SocketAddress) -> TcpStream ! IoError ``` Connects to `address`, waiting until the connection is made or refused. | Name | Type | Description | | --------- | --------------- | ---------------- | | `address` | `SocketAddress` | where to connect | **Returns**: the stream, or fails with `ConnectionRefused`, `Unreachable` or `TimedOut` [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Net/Src/Tcp.rux#L98){rel=""nofollow""} **Methods** ### `LocalAddress` ```rux pub func LocalAddress(self: &TcpStream) -> SocketAddress ! IoError ``` The address of this end of the connection. **Returns**: the address [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Net/Src/Tcp.rux#L108){rel=""nofollow""} ### `PeerAddress` ```rux pub func PeerAddress(self: &TcpStream) -> SocketAddress ! IoError ``` The address of the other end. **Returns**: the address [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Net/Src/Tcp.rux#L115){rel=""nofollow""} ### `Shutdown` ```rux pub func Shutdown( self: &TcpStream, direction: ShutdownDirection ) -> ! IoError ``` Ends one or both directions of the connection while the socket stays open. | Name | Type | Description | | ----------- | ------------------- | ----------- | | `direction` | `ShutdownDirection` | what to end | **Returns**: nothing, or fails when the connection is already gone [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Net/Src/Tcp.rux#L123){rel=""nofollow""} ### `SetNoDelay` ```rux pub func SetNoDelay( self: &TcpStream, enabled: bool ) -> ! IoError ``` Sends small writes at once rather than gathering them, which suits request and response exchanges. | Name | Type | Description | | --------- | ------ | ----------- | | `enabled` | `bool` | whether to | **Returns**: nothing, or fails when the system refused [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Net/Src/Tcp.rux#L131){rel=""nofollow""} ### `SetReadTimeout` ```rux pub func SetReadTimeout( self: &TcpStream, timeout: Duration? ) -> ! IoError ``` How long a read may wait before failing with `TimedOut`, or none to wait without a limit. | Name | Type | Description | | --------- | ----------- | ----------- | | `timeout` | `Duration?` | the limit | **Returns**: nothing, or fails when the system refused [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Net/Src/Tcp.rux#L139){rel=""nofollow""} ### `SetWriteTimeout` ```rux pub func SetWriteTimeout( self: &TcpStream, timeout: Duration? ) -> ! IoError ``` How long a write may wait before failing with `TimedOut`, or none to wait without a limit. | Name | Type | Description | | --------- | ----------- | ----------- | | `timeout` | `Duration?` | the limit | **Returns**: nothing, or fails when the system refused [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Net/Src/Tcp.rux#L147){rel=""nofollow""} ### `SetNonBlocking` ```rux pub func SetNonBlocking( self: &TcpStream, enabled: bool ) -> ! IoError ``` Makes calls on the stream fail with `WouldBlock` when they would wait, or wait again. A non-blocking socket is meant for a [`Poller`](https://rux-lang.dev/docs/api/net/poller), which says when a call would not wait. | Name | Type | Description | | --------- | ------ | ----------------------------------- | | `enabled` | `bool` | whether calls fail rather than wait | **Returns**: success when the mode is set [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Net/Src/Tcp.rux#L156){rel=""nofollow""} ### `PollSource` ```rux pub func PollSource(self: &TcpStream) -> PollSource ``` The stream as a [`Poller`](https://rux-lang.dev/docs/api/net/poller) watches it, valid while the stream is open. **Returns**: the source to register [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Net/Src/Tcp.rux#L163){rel=""nofollow""} **Implements Reader** `TcpStream` conforms to `Reader`. ### `Read` ```rux pub func Read( self: &var TcpStream, into: var char8[..] ) -> uint ! IoError ``` Reads what the peer has sent, waiting while it has sent nothing. | Name | Type | Description | | ------ | --------------- | ---------------------- | | `into` | `var char8[..]` | where to put the bytes | **Returns**: how many were read, or fails with `EndOfStream` once the peer closed its side [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Net/Src/Tcp.rux#L189){rel=""nofollow""} **Implements Writer** `TcpStream` conforms to `Writer`. ### `Write` ```rux pub func Write( self: &var TcpStream, bytes: char8[..] ) -> uint ! IoError ``` Sends some of `bytes`, waiting while the connection's buffer is full. | Name | Type | Description | | ------- | ----------- | ----------- | | `bytes` | `char8[..]` | the bytes | **Returns**: how many were sent [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Net/Src/Tcp.rux#L202){rel=""nofollow""} ### `Flush` ```rux pub func Flush(self: &var TcpStream) -> ! IoError ``` Does nothing: a stream sends what is written to it without holding any back. **Returns**: nothing [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Net/Src/Tcp.rux#L210){rel=""nofollow""} **Destructor** ### `~TcpStream` ```rux func ~TcpStream(self: &var TcpStream) ``` [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Net/Src/Tcp.rux#L167){rel=""nofollow""} ## `ShutdownDirection` ```rux pub enum ShutdownDirection: int32 { Read = 0, Write = 1, Both = 2 } ``` Which directions of a connection [`Shutdown`](https://rux-lang.dev/docs/api/net/tcp#shutdown) ends. `Copy`. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Net/Src/Tcp.rux#L28){rel=""nofollow""} **Cases** | Name | Value | Description | | ------- | ----- | ------------------------------------------------------------------- | | `Read` | `0` | Nothing more will be read. | | `Write` | `1` | Nothing more will be written; the peer reads the end of the stream. | | `Both` | `2` | Both. | # UDP Datagram sockets and the datagrams they receive. ## `Datagram` ```rux pub struct Datagram { pub length: uint; pub source: SocketAddress; } ``` A datagram received, and where it came from. `Copy`. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Net/Src/Udp.rux#L14){rel=""nofollow""} **Fields** | Name | Type | Description | | -------- | --------------- | -------------------------------------- | | `length` | `uint` | How many bytes of it the buffer holds. | | `source` | `SocketAddress` | Who sent it. | ## `UdpSocket` ```rux pub struct UdpSocket { // private fields } ``` A UDP socket. Not copied. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Net/Src/Udp.rux#L23){rel=""nofollow""} **Associated functions** ### `Bind` ```rux pub func Bind(address: SocketAddress) -> UdpSocket ! IoError ``` A socket bound to `address`. Port zero lets the system choose a free port, which [`LocalAddress`](https://rux-lang.dev/docs/api/net/udp#local-address) then gives. | Name | Type | Description | | --------- | --------------- | ------------------------- | | `address` | `SocketAddress` | the address to receive at | **Returns**: the socket, or fails with `AddressInUse` or `AddressUnavailable` [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Net/Src/Udp.rux#L34){rel=""nofollow""} **Methods** ### `SendTo` ```rux pub func SendTo( self: &UdpSocket, bytes: char8[..], target: SocketAddress ) -> uint ! IoError ``` Sends `bytes` as one datagram to `target`. | Name | Type | Description | | -------- | --------------- | ---------------- | | `bytes` | `char8[..]` | the datagram | | `target` | `SocketAddress` | where to send it | **Returns**: how many bytes were sent [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Net/Src/Udp.rux#L46){rel=""nofollow""} ### `ReceiveFrom` ```rux pub func ReceiveFrom( self: &UdpSocket, into: var char8[..] ) -> Datagram ! IoError ``` Waits for a datagram and puts it in `into`. | Name | Type | Description | | ------ | --------------- | --------------- | | `into` | `var char8[..]` | where to put it | **Returns**: its length and its sender [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Net/Src/Udp.rux#L54){rel=""nofollow""} ### `Connect` ```rux pub func Connect( self: &UdpSocket, peer: SocketAddress ) -> ! IoError ``` Sends to and receives from `peer` only, so [`Send`](https://rux-lang.dev/docs/api/net/udp#send) and [`Receive`](https://rux-lang.dev/docs/api/net/udp#receive) need no address. | Name | Type | Description | | ------ | --------------- | -------------------------- | | `peer` | `SocketAddress` | the one address to talk to | **Returns**: nothing, or fails when the system refused [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Net/Src/Udp.rux#L64){rel=""nofollow""} ### `Send` ```rux pub func Send( self: &UdpSocket, bytes: char8[..] ) -> uint ! IoError ``` Sends `bytes` as one datagram to the connected peer. | Name | Type | Description | | ------- | ----------- | ------------ | | `bytes` | `char8[..]` | the datagram | **Returns**: how many bytes were sent [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Net/Src/Udp.rux#L72){rel=""nofollow""} ### `Receive` ```rux pub func Receive( self: &UdpSocket, into: var char8[..] ) -> uint ! IoError ``` Waits for a datagram from the connected peer and puts it in `into`. | Name | Type | Description | | ------ | --------------- | --------------- | | `into` | `var char8[..]` | where to put it | **Returns**: its length [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Net/Src/Udp.rux#L80){rel=""nofollow""} ### `LocalAddress` ```rux pub func LocalAddress(self: &UdpSocket) -> SocketAddress ! IoError ``` The address the socket is bound to. **Returns**: the address [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Net/Src/Udp.rux#L87){rel=""nofollow""} ### `SetReadTimeout` ```rux pub func SetReadTimeout( self: &UdpSocket, timeout: Duration? ) -> ! IoError ``` How long a receive may wait before failing with `TimedOut`, or none to wait without a limit. | Name | Type | Description | | --------- | ----------- | ----------- | | `timeout` | `Duration?` | the limit | **Returns**: nothing, or fails when the system refused [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Net/Src/Udp.rux#L95){rel=""nofollow""} ### `SetNonBlocking` ```rux pub func SetNonBlocking( self: &UdpSocket, enabled: bool ) -> ! IoError ``` Makes calls on the socket fail with `WouldBlock` when they would wait, or wait again. A non-blocking socket is meant for a [`Poller`](https://rux-lang.dev/docs/api/net/poller), which says when a call would not wait. | Name | Type | Description | | --------- | ------ | ----------------------------------- | | `enabled` | `bool` | whether calls fail rather than wait | **Returns**: success when the mode is set [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Net/Src/Udp.rux#L104){rel=""nofollow""} ### `PollSource` ```rux pub func PollSource(self: &UdpSocket) -> PollSource ``` The socket as a [`Poller`](https://rux-lang.dev/docs/api/net/poller) watches it, valid while the socket is open. **Returns**: the source to register [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Net/Src/Udp.rux#L111){rel=""nofollow""} **Destructor** ### `~UdpSocket` ```rux func ~UdpSocket(self: &var UdpSocket) ``` [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Net/Src/Udp.rux#L115){rel=""nofollow""} # Name resolution The addresses a host name resolves to. ## `Resolve` ```rux pub func Resolve( allocator: Allocator, host: char8[..], port: uint16 ) -> Vector<SocketAddress> ! IoError ``` The addresses of `host`, each with `port`, in the order the resolver prefers them, without repeats. A host that is a numeric IPv4 or IPv6 address gives just that address. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Net/Src/Resolve.rux#L29){rel=""nofollow""} **Parameters** | Name | Type | Description | | ----------- | ----------- | -------------------------------------------------------- | | `allocator` | `Allocator` | what the list is kept in | | `host` | `char8[..]` | a host name, such as `example.com`, or a numeric address | | `port` | `uint16` | the port every address gets | **Returns**: the addresses, or fails with `NotFound` when the name has none, or with the resolver's reason # Test Unit tests: checks with readable failures, and the runner that #Test() functions are gathered into. ## Installation Add `Test` to the `[Dependencies]` table of your package's `Rux.toml`: ```toml [Dependencies] Test = { Namespace = "Rux", Version = "0.1.0" } ``` Standard packages are declared by hand: the registry does not serve them, so `rux add Rux/Test` cannot add them. ## Dependencies - [`Allocator`](https://rux-lang.dev/docs/api/allocator) 0.1.0 - [`Collections`](https://rux-lang.dev/docs/api/collections) 0.1.0 - [`Core`](https://rux-lang.dev/docs/api/core) 0.1.0 - [`Format`](https://rux-lang.dev/docs/api/format) 0.1.0 - [`Io`](https://rux-lang.dev/docs/api/io) 0.1.0 - [`Process`](https://rux-lang.dev/docs/api/process) 0.1.0 - [`Text`](https://rux-lang.dev/docs/api/text) 0.1.0 - [`Time`](https://rux-lang.dev/docs/api/time) 0.1.0 ## Guide Unit tests: functions marked `#Test()`, checks whose failures say what was expected and what was found, and the runner a test build gathers them into. ### What it provides | Module | Covers | | ------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | [`Expect`](https://rux-lang.dev/docs/api/test/expect#expect) | [`Expect`](https://rux-lang.dev/docs/api/test/expect#expect), [`ExpectEqual`](https://rux-lang.dev/docs/api/test/expect#expect-equal), [`ExpectNotEqual`](https://rux-lang.dev/docs/api/test/expect#expect-not-equal), [`ExpectNear`](https://rux-lang.dev/docs/api/test/expect#expect-near), [`ExpectText`](https://rux-lang.dev/docs/api/test/expect#expect-text), [`ExpectSome`](https://rux-lang.dev/docs/api/test/expect#expect-some), [`ExpectNone`](https://rux-lang.dev/docs/api/test/expect#expect-none), [`ExpectSuccess`](https://rux-lang.dev/docs/api/test/expect#expect-success) and [`ExpectFailure`](https://rux-lang.dev/docs/api/test/expect#expect-failure) | | `Failure` | [`TestFailure`](https://rux-lang.dev/docs/api/test/failure#test-failure), a failure with its message or a skip with its reason | | `Runner` | [`TestCase`](https://rux-lang.dev/docs/api/test/runner#test-case), [`TestOptions`](https://rux-lang.dev/docs/api/test/runner#test-options), [`RunTests`](https://rux-lang.dev/docs/api/test/runner#run-tests), which reads its filters from the command line, and [`RunTestsWith`](https://rux-lang.dev/docs/api/test/runner#run-tests-with) | | `Benchmark` | [`BenchmarkCase`](https://rux-lang.dev/docs/api/test/benchmark#benchmark-case), [`BenchmarkOptions`](https://rux-lang.dev/docs/api/test/benchmark#benchmark-options), [`BenchmarkResult`](https://rux-lang.dev/docs/api/test/benchmark#benchmark-result), [`Measure`](https://rux-lang.dev/docs/api/test/benchmark#measure), [`Consume`](https://rux-lang.dev/docs/api/test/benchmark#consume), [`RunBenchmarks`](https://rux-lang.dev/docs/api/test/benchmark#run-benchmarks) and [`RunBenchmarksWith`](https://rux-lang.dev/docs/api/test/benchmark#run-benchmarks-with) | The module names describe where each declaration comes from; they are not part of an import path. ### Example ```rux import Test::{ ExpectEqual, ExpectText, TestFailure }; func Greeting(name: char8[..]) -> char8[..] { return name.length == 0 ? "hello" : "hello, friend"; } #Test() func GreetsAnyone() -> ! TestFailure { ExpectText(Greeting(""), "hello")?; ExpectEqual(Greeting("ann").length, 13u)?; } ``` `rux test` builds the package in test mode and runs it, reporting each test with its time, and `rux test -- Greets` runs only the tests whose names hold `Greets`. ### Design A test is a function marked `#Test()` that takes nothing and returns nothing or `! TestFailure`. It is declared at the top level of a source file or inside a `module` block, which then prefixes its name, as in `Parser::ReadsNumbers`. Each check returns `! TestFailure`, so a test passes a failed check on with `?` and stops there. The failure says what was expected and what was found: [`ExpectText`](https://rux-lang.dev/docs/api/test/expect#expect-text) names the byte where two texts part and shows each around it. A test ends with `fail TestFailure::Skip("reason")` to be counted as skipped rather than failed. A failure keeps its message inline, so failing never allocates and never fails itself. A test build of a package with `#Test()` functions generates its `Main`: a table of [`TestCase`](https://rux-lang.dev/docs/api/test/runner#test-case) values handed to [`RunTests`](https://rux-lang.dev/docs/api/test/runner#run-tests). This works for libraries too, so a `SourceLibrary` can hold its own tests beside its code. The package must depend on `Test` and must not declare a `Main` of its own. `rux test` runs every executable package under `Tests/` and every package whose sources mark tests, and passes the arguments after `--` to each. The runner reads each plain argument as a filter on test names and runs the tests any of them matches, with `--exact` to match whole names, `--skip <text>` to leave some out, `--list` to list them and `--quiet` to report only failures. A filter that matches no test fails the run rather than passing with nothing run. When arguments are given, `rux test` shows each package's report even when it passed, so `rux test -- --list` lists the tests. A benchmark is a [`BenchmarkCase`](https://rux-lang.dev/docs/api/test/benchmark#benchmark-case): a name and a function that repeats the measured work as many times as it is told. [`Measure`](https://rux-lang.dev/docs/api/test/benchmark#measure) times the whole call, so setup before the loop is counted too, spread over the iterations; keep it small next to the work, or do it once outside the function. [`Measure`](https://rux-lang.dev/docs/api/test/benchmark#measure) runs it with a count that grows from one, at least twofold and at most a hundredfold a round, aiming past the minimum time from the rate so far, until a run lasts 200 milliseconds or reaches its cap, and reports that run; [`RunBenchmarks`](https://rux-lang.dev/docs/api/test/benchmark#run-benchmarks) measures a table of them and prints the time per iteration of each, with a name filter and `--quick` from the command line. `Consume(@result)` keeps a result the compiler would otherwise see as unused, and the work that made it, from being optimized away. Tests run one after another in one process. A failed check ends only its own test. A panic or a failed `Assert` ends the whole run, which `rux test` then reports with the output up to that point. ## Index ### Types | Name | Summary | | ------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------- | | [`BenchmarkCase`](https://rux-lang.dev/docs/api/test/benchmark#benchmark-case) | A benchmark: its name, which the runner reports and filters on, and the function that repeats the measured work as many times as it is told. | | [`BenchmarkResult`](https://rux-lang.dev/docs/api/test/benchmark#benchmark-result) | What a measurement found: how many iterations its final run made and how long that run took. | | [`BenchmarkOptions`](https://rux-lang.dev/docs/api/test/benchmark#benchmark-options) | Which benchmarks a run chooses and how long each is measured. | | [`TestFailure`](https://rux-lang.dev/docs/api/test/failure#test-failure) | Why a test did not pass. | | [`TestCase`](https://rux-lang.dev/docs/api/test/runner#test-case) | A test: its name, which the runner reports and filters on, and the function that runs it. | | [`TestOptions`](https://rux-lang.dev/docs/api/test/runner#test-options) | Which tests a run chooses and how it reports them. | ### Functions | Name | Summary | | --------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | [`Consume<T>`](https://rux-lang.dev/docs/api/test/benchmark#consume) | Marks `value` as used, so the work that computed it is not removed as having no effect. | | [`Measure`](https://rux-lang.dev/docs/api/test/benchmark#measure) | Runs `run` with a growing iteration count until one run lasts at least `options.minimumTime` or reaches `options.maximumIterations`, and reports that run. | | [`RunBenchmarksWith`](https://rux-lang.dev/docs/api/test/benchmark#run-benchmarks-with) | Measures the benchmarks that `options` choose, in order, and reports each as its time per iteration and the iterations it was measured over, then how many were measured. | | [`RunBenchmarks`](https://rux-lang.dev/docs/api/test/benchmark#run-benchmarks) | Measures the benchmarks the process's arguments choose. | | [`Expect`](https://rux-lang.dev/docs/api/test/expect#expect) | Fails unless `condition` holds. | | [`ExpectEqual<T>`](https://rux-lang.dev/docs/api/test/expect#expect-equal) | Fails unless `actual` equals `expected`, saying both. | | [`ExpectNotEqual<T>`](https://rux-lang.dev/docs/api/test/expect#expect-not-equal) | Fails if `actual` equals `unexpected`. | | [`ExpectNear`](https://rux-lang.dev/docs/api/test/expect#expect-near) | Fails unless `actual` is within `tolerance` of `expected`. | | [`ExpectText`](https://rux-lang.dev/docs/api/test/expect#expect-text) | Fails unless `actual` is the same text as `expected`, saying at which byte they part and showing each around it. | | [`ExpectSome<T>`](https://rux-lang.dev/docs/api/test/expect#expect-some) | The value of `value`, failing when there is none. | | [`ExpectNone<T>`](https://rux-lang.dev/docs/api/test/expect#expect-none) | Fails when `value` is present. | | [`ExpectSuccess<T, E>`](https://rux-lang.dev/docs/api/test/expect#expect-success) | The success of `outcome`, failing when it failed. | | [`ExpectFailure<T, E>`](https://rux-lang.dev/docs/api/test/expect#expect-failure) | The failure of `outcome`, failing the test when it succeeded. | | [`RunTestsWith`](https://rux-lang.dev/docs/api/test/runner#run-tests-with) | Runs the tests that `options` choose, in order, and reports each as `ok`, `FAILED` with its message, or `skipped` with its reason, then a summary of the counts and the time taken. | | [`RunTests`](https://rux-lang.dev/docs/api/test/runner#run-tests) | Runs the tests the process's arguments choose. | # Failures The failure a test returns, and skipping a test. ## `TestFailure` ```rux pub struct TestFailure { // private fields } ``` Why a test did not pass. `Copy`. A test fails with it through `fail` or `?`, and is counted as skipped rather than failed when it was made with [`Skip`](https://rux-lang.dev/docs/api/test/failure#skip). [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Test/Src/Failure.rux#L14){rel=""nofollow""} **Associated functions** ### `Of` ```rux pub func Of(message: char8[..]) -> TestFailure ``` A failure saying `message`. | Name | Type | Description | | --------- | ----------- | --------------- | | `message` | `char8[..]` | what went wrong | **Returns**: the failure [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Test/Src/Failure.rux#L25){rel=""nofollow""} ### `Skip` ```rux pub func Skip(reason: char8[..]) -> TestFailure ``` A skip, which the runner counts apart from failures, saying why the test did not run. | Name | Type | Description | | -------- | ----------- | ------------------ | | `reason` | `char8[..]` | why it was skipped | **Returns**: the skip [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Test/Src/Failure.rux#L35){rel=""nofollow""} **Methods** ### `Message` ```rux pub func Message(self: &TestFailure) -> char8[..] ``` The message, or a skip's reason. **Returns**: the message [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Test/Src/Failure.rux#L44){rel=""nofollow""} ### `IsSkip` ```rux pub func IsSkip(self: &TestFailure) -> bool ``` Whether this is a skip rather than a failure. **Returns**: whether the test was skipped [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Test/Src/Failure.rux#L51){rel=""nofollow""} # Runner Running a table of tests with filters, as the generated test runner does. ## `TestCase` ```rux pub struct TestCase { pub name: char8[..]; pub run: func() -> ! TestFailure; } ``` A test: its name, which the runner reports and filters on, and the function that runs it. `Copy`. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Test/Src/Runner.rux#L15){rel=""nofollow""} **Fields** | Name | Type | Description | | ------ | ------------------------- | ------------------------------------------------ | | `name` | `char8[..]` | The test's name, such as `Parser::ReadsNumbers`. | | `run` | `func() -> ! TestFailure` | What runs it. | ## `TestOptions` ```rux pub struct TestOptions { pub filter: char8[..]; pub filters: char8[..][..]; pub exact: bool; pub skip: char8[..]; pub list: bool; pub quiet: bool; } ``` Which tests a run chooses and how it reports them. `Copy`. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Test/Src/Runner.rux#L24){rel=""nofollow""} **Fields** | Name | Type | Description | | --------- | --------------- | ----------------------------------------------------------------------------------------------- | | `filter` | `char8[..]` | Run only tests whose names hold this text, or every test when it is empty and `filters` is too. | | `filters` | `char8[..][..]` | More texts like `filter`: a test runs when its name holds any of them, or `filter`. | | `exact` | `bool` | Whether a filter must be the whole name rather than part of it. | | `skip` | `char8[..]` | Leave out tests whose names hold this text, unless it is empty. | | `list` | `bool` | List the chosen tests rather than running them. | | `quiet` | `bool` | Report only failures and the summary. | **Constructors** ### `TestOptions` ```rux pub func TestOptions() -> TestOptions ``` Options that run every test and report each one. **Returns**: the options [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Test/Src/Runner.rux#L43){rel=""nofollow""} ## `RunTestsWith` ```rux pub func RunTestsWith( tests: TestCase[..], options: TestOptions ) -> int ``` Runs the tests that `options` choose, in order, and reports each as `ok`, `FAILED` with its message, or `skipped` with its reason, then a summary of the counts and the time taken. A filter that chooses no test at all is reported as `no test matches` and given a code of its own, so that `rux test`, which hands one filter to every package, can fail the run when no package had a test it matched instead of passing with nothing run. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Test/Src/Runner.rux#L100){rel=""nofollow""} **Parameters** | Name | Type | Description | | --------- | -------------- | ----------------------------------- | | `tests` | `TestCase[..]` | the tests | | `options` | `TestOptions` | which to run and how to report them | **Returns**: 0 when none failed, 1 when some did, 3 when filters chose no test ## `RunTests` ```rux pub func RunTests(tests: TestCase[..]) -> int ``` Runs the tests the process's arguments choose. A plain argument is a filter that a test's name must hold, and a test runs when its name holds any of them; `--exact` makes each the whole name, `--skip <text>` leaves out names holding the text, `--list` lists the chosen tests without running them, and `--quiet` reports only failures and the summary. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Test/Src/Runner.rux#L167){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------- | -------------- | ----------- | | `tests` | `TestCase[..]` | the tests | **Returns**: 0 when none failed, 1 when some did, 2 for arguments it does not understand, 3 when filters chose no test # Benchmarks Measuring how long code takes per iteration, and keeping its results alive. ## `BenchmarkCase` ```rux pub struct BenchmarkCase { pub name: char8[..]; pub run: func(uint64); } ``` A benchmark: its name, which the runner reports and filters on, and the function that repeats the measured work as many times as it is told. `Copy`. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Test/Src/Benchmark.rux#L17){rel=""nofollow""} **Fields** | Name | Type | Description | | ------ | -------------- | ------------------------------------------------------ | | `name` | `char8[..]` | The benchmark's name, such as `Parser::SmallDocument`. | | `run` | `func(uint64)` | Runs the measured work the given number of times. | ## `BenchmarkResult` ```rux pub struct BenchmarkResult { pub iterations: uint64; pub elapsed: Duration; } ``` What a measurement found: how many iterations its final run made and how long that run took. `Copy`. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Test/Src/Benchmark.rux#L26){rel=""nofollow""} **Fields** | Name | Type | Description | | ------------ | ---------- | ------------------------------------------ | | `iterations` | `uint64` | How many iterations the measured run made. | | `elapsed` | `Duration` | How long the measured run took. | **Methods** ### `NanosecondsPerIteration` ```rux pub func NanosecondsPerIteration(self: &BenchmarkResult) -> float64 ``` The average time one iteration took, in nanoseconds. **Returns**: the time per iteration, or zero for a run of no iterations [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Test/Src/Benchmark.rux#L37){rel=""nofollow""} ## `BenchmarkOptions` ```rux pub struct BenchmarkOptions { pub filter: char8[..]; pub filters: char8[..][..]; pub minimumTime: Duration; pub maximumIterations: uint64; } ``` Which benchmarks a run chooses and how long each is measured. `Copy`. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Test/Src/Benchmark.rux#L46){rel=""nofollow""} **Fields** | Name | Type | Description | | ------------------- | --------------- | --------------------------------------------------------------------------------------------------------- | | `filter` | `char8[..]` | Run only benchmarks whose names hold this text, or every benchmark when it is empty and `filters` is too. | | `filters` | `char8[..][..]` | More texts like `filter`: a benchmark runs when its name holds any of them, or `filter`. | | `minimumTime` | `Duration` | How long the measured run must last, at the least. | | `maximumIterations` | `uint64` | The most iterations one run makes, which ends the growth for work too fast to reach `minimumTime`. | **Constructors** ### `BenchmarkOptions` ```rux pub func BenchmarkOptions() -> BenchmarkOptions ``` Options that measure every benchmark for at least 200 milliseconds and at most a billion iterations. **Returns**: the options [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Test/Src/Benchmark.rux#L61){rel=""nofollow""} ## `Consume<T>` ```rux pub func Consume<T>(value: *T) ``` Marks `value` as used, so the work that computed it is not removed as having no effect. It stores the value's address where the compiler cannot see it read, which costs one store. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Test/Src/Benchmark.rux#L75){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | ---------------- | | `T` | the value's type | **Parameters** | Name | Type | Description | | ------- | ---- | ------------------ | | `value` | `*T` | the result to keep | ## `Measure` ```rux pub func Measure( run: func(uint64), options: BenchmarkOptions ) -> BenchmarkResult ``` Runs `run` with a growing iteration count until one run lasts at least `options.minimumTime` or reaches `options.maximumIterations`, and reports that run. Each next count aims a little past the minimum from the rate measured so far, growing at least twofold and at most a hundredfold, so a measurement makes few runs whatever the work costs. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Test/Src/Benchmark.rux#L87){rel=""nofollow""} **Parameters** | Name | Type | Description | | --------- | ------------------ | ---------------------------------------------- | | `run` | `func(uint64)` | the work, repeated as many times as it is told | | `options` | `BenchmarkOptions` | how long to measure | **Returns**: the final run's iterations and time ## `RunBenchmarksWith` ```rux pub func RunBenchmarksWith( benchmarks: BenchmarkCase[..], options: BenchmarkOptions ) -> int ``` Measures the benchmarks that `options` choose, in order, and reports each as its time per iteration and the iterations it was measured over, then how many were measured. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Test/Src/Benchmark.rux#L130){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------------ | ------------------- | ----------------------------------------- | | `benchmarks` | `BenchmarkCase[..]` | the benchmarks | | `options` | `BenchmarkOptions` | which to run and how long to measure each | **Returns**: 0 ## `RunBenchmarks` ```rux pub func RunBenchmarks(benchmarks: BenchmarkCase[..]) -> int ``` Measures the benchmarks the process's arguments choose. A plain argument is a filter, and a benchmark runs when its name holds any of them; `--quick` measures each for 10 milliseconds rather than 200, for checking that benchmarks still run. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Test/Src/Benchmark.rux#L150){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------------ | ------------------- | -------------- | | `benchmarks` | `BenchmarkCase[..]` | the benchmarks | **Returns**: 0, or 2 for arguments it does not understand # Checks Checks that return a readable failure: equality, nearness, text, optionals and outcomes. ## `Expect` ```rux pub func Expect( condition: bool, message: char8[..] ) -> ! TestFailure ``` Fails unless `condition` holds. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Test/Src/Expect.rux#L13){rel=""nofollow""} **Parameters** | Name | Type | Description | | ----------- | ----------- | ------------------------------ | | `condition` | `bool` | what must be true | | `message` | `char8[..]` | what it means, for the failure | **Returns**: nothing, or the failure ## `ExpectEqual<T>` ```rux pub func ExpectEqual<T: Display>( actual: T, expected: T ) -> ! TestFailure ``` Fails unless `actual` equals `expected`, saying both. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Test/Src/Expect.rux#L23){rel=""nofollow""} **Type parameters** | Name | Description | | ------------ | -------------------------------------- | | `T: Display` | a type with `==` that can be displayed | **Parameters** | Name | Type | Description | | ---------- | ---- | ------------------------- | | `actual` | `T` | what the code gave | | `expected` | `T` | what it should have given | **Returns**: nothing, or the failure ## `ExpectNotEqual<T>` ```rux pub func ExpectNotEqual<T: Display>( actual: T, unexpected: T ) -> ! TestFailure ``` Fails if `actual` equals `unexpected`. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Test/Src/Expect.rux#L38){rel=""nofollow""} **Type parameters** | Name | Description | | ------------ | -------------------------------------- | | `T: Display` | a type with `==` that can be displayed | **Parameters** | Name | Type | Description | | ------------ | ---- | ----------------------------- | | `actual` | `T` | what the code gave | | `unexpected` | `T` | what it should not have given | **Returns**: nothing, or the failure ## `ExpectNear` ```rux pub func ExpectNear( actual: float64, expected: float64, tolerance: float64 ) -> ! TestFailure ``` Fails unless `actual` is within `tolerance` of `expected`. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Test/Src/Expect.rux#L53){rel=""nofollow""} **Parameters** | Name | Type | Description | | ----------- | --------- | ------------------------- | | `actual` | `float64` | what the code gave | | `expected` | `float64` | what it should have given | | `tolerance` | `float64` | how far apart they may be | **Returns**: nothing, or the failure ## `ExpectText` ```rux pub func ExpectText( actual: char8[..], expected: char8[..] ) -> ! TestFailure ``` Fails unless `actual` is the same text as `expected`, saying at which byte they part and showing each around it. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Test/Src/Expect.rux#L88){rel=""nofollow""} **Parameters** | Name | Type | Description | | ---------- | ----------- | ------------------------- | | `actual` | `char8[..]` | what the code gave | | `expected` | `char8[..]` | what it should have given | **Returns**: nothing, or the failure ## `ExpectSome<T>` ```rux pub func ExpectSome<T>( value: T?, message: char8[..] ) -> T ! TestFailure ``` The value of `value`, failing when there is none. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Test/Src/Expect.rux#L110){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | ---------------- | | `T` | the value's type | **Parameters** | Name | Type | Description | | --------- | ----------- | --------------------------------------- | | `value` | `T?` | the optional value | | `message` | `char8[..]` | what its absence means, for the failure | **Returns**: the value, or the failure ## `ExpectNone<T>` ```rux pub func ExpectNone<T>( value: T?, message: char8[..] ) -> ! TestFailure ``` Fails when `value` is present. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Test/Src/Expect.rux#L123){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | ---------------- | | `T` | the value's type | **Parameters** | Name | Type | Description | | --------- | ----------- | ---------------------------------------- | | `value` | `T?` | the optional value | | `message` | `char8[..]` | what its presence means, for the failure | **Returns**: nothing, or the failure ## `ExpectSuccess<T, E>` ```rux pub func ExpectSuccess<T, E>( outcome: T ! E, message: char8[..] ) -> T ! TestFailure ``` The success of `outcome`, failing when it failed. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Test/Src/Expect.rux#L137){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | ------------------ | | `T` | the success's type | | `E` | the failure's type | **Parameters** | Name | Type | Description | | --------- | ----------- | ---------------------------------------------- | | `outcome` | `T ! E` | what the code gave | | `message` | `char8[..]` | what its failure means, for the test's failure | **Returns**: the success, or the failure ## `ExpectFailure<T, E>` ```rux pub func ExpectFailure<T, E>( outcome: T ! E, message: char8[..] ) -> E ! TestFailure ``` The failure of `outcome`, failing the test when it succeeded. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Test/Src/Expect.rux#L151){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | ------------------ | | `T` | the success's type | | `E` | the failure's type | **Parameters** | Name | Type | Description | | --------- | ----------- | ---------------------------------------------- | | `outcome` | `T ! E` | what the code gave | | `message` | `char8[..]` | what its success means, for the test's failure | **Returns**: the failure the code gave, or the test's failure # Thread Threads of execution: starting, joining and detaching them, and asking about the current one. ## Installation Add `Thread` to the `[Dependencies]` table of your package's `Rux.toml`: ```toml [Dependencies] Thread = { Namespace = "Rux", Version = "0.1.0" } ``` Standard packages are declared by hand: the registry does not serve them, so `rux add Rux/Thread` cannot add them. ## Dependencies - [`Core`](https://rux-lang.dev/docs/api/core) 0.1.0 - [`FreeBSD`](https://rux-lang.dev/docs/api/freebsd) 0.1.0 (FreeBSD only) - [`Linux`](https://rux-lang.dev/docs/api/linux) 0.1.0 (Linux only) - [`macOS`](https://rux-lang.dev/docs/api/macos) 0.1.0 (macOS only) - [`Memory`](https://rux-lang.dev/docs/api/memory) 0.1.0 - [`Windows`](https://rux-lang.dev/docs/api/windows) 0.1.0 (Windows only) ## Guide ### What it provides | Module | Covers | | ----------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | [`Spawn`](https://rux-lang.dev/docs/api/thread/spawn#spawn) | [`Spawn`](https://rux-lang.dev/docs/api/thread/spawn#spawn), [`SpawnWith`](https://rux-lang.dev/docs/api/thread/spawn#spawn-with), [`ThreadOptions`](https://rux-lang.dev/docs/api/thread/spawn#thread-options) with a stack size, and [`JoinHandle<R>`](https://rux-lang.dev/docs/api/thread/spawn#join-handle) with [`Join`](https://rux-lang.dev/docs/api/thread/spawn#join) and [`Detach`](https://rux-lang.dev/docs/api/thread/spawn#detach) | | `Current` | [`CurrentId`](https://rux-lang.dev/docs/api/thread/current#current-id), [`Yield`](https://rux-lang.dev/docs/api/thread/current#yield) and [`AvailableParallelism`](https://rux-lang.dev/docs/api/thread/current#available-parallelism) | | `Error` | [`ThreadError`](https://rux-lang.dev/docs/api/thread/error#thread-error), why a thread could not be started | The module names describe where each declaration comes from; they are not part of an import path. ### Example ```rux import Thread::Spawn; func Square(value: uint64) -> uint64 { return value * value; } func Main() -> int { var handle = Spawn(Square, 12u64) catch { else => return 1 }; return handle.Join() == 144u64 ? 0 : 2; } ``` ### Design Rux has no closures, so a thread runs a function on a context value the caller moves to it, and leaves the function's result for whoever joins it. `Spawn(entry, context)` returns a [`JoinHandle<R>`](https://rux-lang.dev/docs/api/thread/spawn#join-handle); [`Join`](https://rux-lang.dev/docs/api/thread/spawn#join) waits for the thread and returns the result. The context and the result must be `Core::Sendable`, so neither can be a reference or hold an `Rc`. Dropping the handle, or calling [`Detach`](https://rux-lang.dev/docs/api/thread/spawn#detach), lets the thread run on and release itself when it finishes, destroying a result nobody took. On Linux, FreeBSD and macOS threads are started with the C library's `pthread_create`, which gives each one its stack and its thread-local block, so a program that starts threads is linked against the C library. On Windows they are started with `CreateThread`. Each thread has its own copy of every `thread var`, starting at its initial value. A panic on any thread ends the whole process, as it does on the main thread. Sharing data between threads takes an `Atomic<T>` or a lock from the `Sync` package; this package only starts and joins them. ## Index ### Types | Name | Summary | | ---------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------- | | [`ThreadError`](https://rux-lang.dev/docs/api/thread/error#thread-error) | Why [`Spawn`](https://rux-lang.dev/docs/api/thread/spawn#spawn) could not start a thread. | | [`ThreadOptions`](https://rux-lang.dev/docs/api/thread/spawn#thread-options) | How a thread is started: its stack size, for now. | | [`JoinHandle<R>`](https://rux-lang.dev/docs/api/thread/spawn#join-handle) | A started thread, and the result it will leave. | ### Functions | Name | Summary | | -------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------- | | [`CurrentId`](https://rux-lang.dev/docs/api/thread/current#current-id) | The calling thread's system-wide identifier. | | [`Yield`](https://rux-lang.dev/docs/api/thread/current#yield) | Offers the processor to another thread that is ready to run, and returns when this one is scheduled again. | | [`AvailableParallelism`](https://rux-lang.dev/docs/api/thread/current#available-parallelism) | How many threads can usefully run at once: the number of processors online, and at least one. | | [`Spawn<T, R>`](https://rux-lang.dev/docs/api/thread/spawn#spawn) | Starts a thread running `entry(context)` with the system's default stack size. | | [`SpawnWith<T, R>`](https://rux-lang.dev/docs/api/thread/spawn#spawn-with) | Starts a thread running `entry(context)` as `options` say. | # Errors Why a thread could not be started. ## `ThreadError` ```rux pub enum ThreadError: uint8 { Exhausted = 1, InvalidStackSize = 2, Failed = 3 } ``` Why [`Spawn`](https://rux-lang.dev/docs/api/thread/spawn#spawn) could not start a thread. `Copy`. Once a thread is running nothing about it can fail this way: joining and detaching a started thread always work. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Thread/Src/Error.rux#L6){rel=""nofollow""} **Cases** | Name | Value | Description | | ------------------ | ----- | ------------------------------------------------------------------------------------- | | `Exhausted` | `1` | The system had no memory, or no thread, to spare. | | `InvalidStackSize` | `2` | The system refused the requested stack size, usually because it is below its minimum. | | `Failed` | `3` | The system reported a failure this package has no name for. | # Starting threads Starting a thread on a context, its options, and joining it for its result. ## `ThreadOptions` ```rux pub struct ThreadOptions { // private fields } ``` How a thread is started: its stack size, for now. `Copy`. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Thread/Src/Spawn.rux#L32){rel=""nofollow""} **Constructors** ### `ThreadOptions` ```rux pub func ThreadOptions() -> ThreadOptions ``` The defaults: the system's own stack size. **Returns**: the default options [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Thread/Src/Spawn.rux#L40){rel=""nofollow""} **Methods** ### `WithStackSize` ```rux pub func WithStackSize( self: &ThreadOptions, size: uint ) -> ThreadOptions ``` These options with a stack of `size` bytes. Zero asks for the system's default. The system rounds the size up to its page size, and refuses one below its minimum. | Name | Type | Description | | ------ | ------ | ----------------------- | | `size` | `uint` | the stack size in bytes | **Returns**: the changed options [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Thread/Src/Spawn.rux#L49){rel=""nofollow""} ### `StackSize` ```rux pub func StackSize(self: &ThreadOptions) -> uint ``` The stack size these options ask for, or zero for the system's default. **Returns**: the stack size in bytes [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Thread/Src/Spawn.rux#L56){rel=""nofollow""} ## `JoinHandle<R>` ```rux pub struct JoinHandle<R> { // private fields } ``` A started thread, and the result it will leave. Joining waits for the thread and hands back what its function returned. Dropping the handle without joining lets the thread run on and clean up after itself; nothing can then wait for it. A handle is not copied. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Thread/Src/Spawn.rux#L66){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | ------------------------------- | | `R` | the type of the thread's result | **Methods** ### `Join` ```rux pub func Join(self: &var JoinHandle<R>) -> R ``` Waits for the thread to finish and returns what its function returned. Joining a handle that was already joined or detached is a program error and panics. **Returns**: the thread's result [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Thread/Src/Spawn.rux#L78){rel=""nofollow""} ### `Detach` ```rux pub func Detach(self: &var JoinHandle<R>) ``` Lets the thread run on without anyone waiting for it. It releases itself, and its result, when it finishes. Detaching a handle that was already joined or detached does nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Thread/Src/Spawn.rux#L93){rel=""nofollow""} ### `IsJoinable` ```rux pub func IsJoinable(self: &JoinHandle<R>) -> bool ``` Whether the handle can still be joined. **Returns**: false once it was joined or detached [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Thread/Src/Spawn.rux#L108){rel=""nofollow""} **Destructor** ### `~JoinHandle` ```rux func ~JoinHandle(self: &var JoinHandle<R>) ``` [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Thread/Src/Spawn.rux#L112){rel=""nofollow""} ## `Spawn<T, R>` ```rux pub func Spawn<T: Sendable, R: Sendable>( entry: func(T) -> R, context: T ) -> JoinHandle<R> ! ThreadError ``` Starts a thread running `entry(context)` with the system's default stack size. The context moves to the new thread. Whatever `entry` returns waits in the handle until it is joined. A panic on any thread ends the whole process, as it does on the main one. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Thread/Src/Spawn.rux#L126){rel=""nofollow""} **Type parameters** | Name | Description | | ------------- | ------------------------------- | | `T: Sendable` | the type of the context | | `R: Sendable` | the type of the thread's result | **Parameters** | Name | Type | Description | | --------- | -------------- | ------------------------------------- | | `entry` | `func(T) -> R` | the function the thread runs | | `context` | `T` | the value the function is called with | **Returns**: a handle to join the thread with ## `SpawnWith<T, R>` ```rux pub func SpawnWith<T: Sendable, R: Sendable>( options: ThreadOptions, entry: func(T) -> R, context: T ) -> JoinHandle<R> ! ThreadError ``` Starts a thread running `entry(context)` as `options` say. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Thread/Src/Spawn.rux#L138){rel=""nofollow""} **Type parameters** | Name | Description | | ------------- | ------------------------------- | | `T: Sendable` | the type of the context | | `R: Sendable` | the type of the thread's result | **Parameters** | Name | Type | Description | | --------- | --------------- | ------------------------------------- | | `options` | `ThreadOptions` | how to start the thread | | `entry` | `func(T) -> R` | the function the thread runs | | `context` | `T` | the value the function is called with | **Returns**: a handle to join the thread with # The current thread Its identifier, giving way to other threads, and how many can run at once. ## `CurrentId` ```rux pub func CurrentId() -> uint64 ``` The calling thread's system-wide identifier. No two live threads share one, but the system may give a finished thread's identifier to a new thread. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Thread/Src/Current.rux#L9){rel=""nofollow""} **Returns**: the identifier ## `Yield` ```rux pub func Yield() ``` Offers the processor to another thread that is ready to run, and returns when this one is scheduled again. A hint for code that waits on another thread, not a way to order threads. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Thread/Src/Current.rux#L16){rel=""nofollow""} ## `AvailableParallelism` ```rux pub func AvailableParallelism() -> uint ``` How many threads can usefully run at once: the number of processors online, and at least one. The answer can change while a program runs, as processors go online or offline. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Thread/Src/Current.rux#L24){rel=""nofollow""} **Returns**: the number of processors, never zero # Atomic Values that threads share without a lock: atomic integers, flags and pointers. ## Installation Add `Atomic` to the `[Dependencies]` table of your package's `Rux.toml`: ```toml [Dependencies] Atomic = { Namespace = "Rux", Version = "0.1.0" } ``` Standard packages are declared by hand: the registry does not serve them, so `rux add Rux/Atomic` cannot add them. ## Dependencies - [`Core`](https://rux-lang.dev/docs/api/core) 0.1.0 ## Guide ### What it provides | Module | Covers | | ------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | [`Atomic`](https://rux-lang.dev/docs/api/atomic/atomic) | [`Atomic<T>`](https://rux-lang.dev/docs/api/atomic/atomic) with [`Load`](https://rux-lang.dev/docs/api/atomic/atomic#load), [`Store`](https://rux-lang.dev/docs/api/atomic/atomic#store), [`Exchange`](https://rux-lang.dev/docs/api/atomic/atomic#exchange), [`CompareExchange`](https://rux-lang.dev/docs/api/atomic/atomic#compare-exchange) and [`FetchAdd`](https://rux-lang.dev/docs/api/atomic/atomic#fetch-add)/`Sub`/`And`/`Or`/`Xor`, and `With` forms that take a `MemoryOrder`; `Zero` for every integer width and [`False`](https://rux-lang.dev/docs/api/atomic/atomic#false) for `bool` | The module names describe where each declaration comes from; they are not part of an import path. ### Example ```rux import Atomic::Atomic; import Core::MemoryOrder; func Count(hits: &Atomic<uint64>) -> uint64 { hits.FetchAddWith(1, MemoryOrder::Relaxed); return hits.Load(); } ``` ### Design [`Atomic<T>`](https://rux-lang.dev/docs/api/atomic/atomic) holds one integer of 8 to 64 bits, `bool` or pointer and touches it only through `Core`'s atomic intrinsics, so no thread ever sees a value half written and each change is one indivisible step. Its methods take the value by shared reference, because several threads reaching it at once is the point; the hardware keeps their accesses apart. Any other `T` is refused where the methods are used. A call such as `Atomic(0u64)` is no compile-time value, so a module variable starts as a constant instead: each integer width's `Zero`, or `bool`'s [`False`](https://rux-lang.dev/docs/api/atomic/atomic#false), reached through an alias of the instantiation, as in `type Hits = Atomic<uint64>;` and `var Count: Hits = Hits::Zero;`. The plain methods are sequentially consistent: every thread agrees on one order of all of them, which is never wrong. The `With` forms take a weaker `MemoryOrder` for code that has worked out it is enough, such as a relaxed counter or a release decrement of a reference count. An order an operation cannot have is strengthened to the nearest one it can, so `LoadWith(MemoryOrder::Release)` loads with `Acquire`. Because the intrinsics need their order written as a case, a `With` method selects among them; the plain methods involve no such choice. [`CompareExchange`](https://rux-lang.dev/docs/api/atomic/atomic#compare-exchange) succeeds with the value it replaced and fails with the value it found, so a retry loop starts again from what is really there. It never fails spuriously. ## Index ### Types | Name | Summary | | ---------------------------------------------------------- | ------------------------------------------------------ | | [`Atomic<T>`](https://rux-lang.dev/docs/api/atomic/atomic) | One value that threads read and change without a lock. | # Atomic\<T> One value that threads read and change without a lock. ```rux pub struct Atomic<T> { // private fields } ``` `T` must be an integer of 8 to 64 bits, `bool` or a pointer; any other type is refused where the methods are used. Shared by reference between threads; the value lives inside, so it must outlive every thread that reaches it. Copying an `Atomic` copies its current value into a new, unrelated one. ## Type parameters | Name | Description | | ---- | ------------------------------------------------------------------ | | `T` | the value's type: an integer of 8 to 64 bits, `bool`, or a pointer | ## Constructors ### `Atomic` ```rux pub func Atomic(value: T) -> Atomic<T> ``` An atomic value holding `value`. Making one is not itself atomic: it must be finished before another thread can reach it, as any value must be. | Name | Type | Description | | ------- | ---- | ----------------- | | `value` | `T` | the initial value | **Returns**: an atomic holding `value` [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Atomic/Src/Atomic.rux#L30){rel=""nofollow""} ## Methods ### `Load` ```rux pub func Load(self: &Atomic<T>) -> T ``` The current value, read with sequential consistency. **Returns**: the value [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Atomic/Src/Atomic.rux#L43){rel=""nofollow""} ### `LoadWith` ```rux pub func LoadWith(self: &Atomic<T>, order: MemoryOrder) -> T ``` The current value, read with `order`, which must be `Relaxed`, `Acquire` or `SequentiallyConsistent`. `Release` and `AcquireRelease` read as `Acquire` and `SequentiallyConsistent` respectively, the nearest orders a load can have. | Name | Type | Description | | ------- | ------------- | ----------------------------------------------- | | `order` | `MemoryOrder` | which other operations may move across this one | **Returns**: the value [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Atomic/Src/Atomic.rux#L53){rel=""nofollow""} ### `Store` ```rux pub func Store(self: &Atomic<T>, value: T) ``` Replaces the value, with sequential consistency. | Name | Type | Description | | ------- | ---- | ------------- | | `value` | `T` | the new value | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Atomic/Src/Atomic.rux#L65){rel=""nofollow""} ### `StoreWith` ```rux pub func StoreWith( self: &Atomic<T>, value: T, order: MemoryOrder ) ``` Replaces the value with `order`, which must be `Relaxed`, `Release` or `SequentiallyConsistent`. `Acquire` and `AcquireRelease` store as `Release` and `SequentiallyConsistent` respectively, the nearest orders a store can have. | Name | Type | Description | | ------- | ------------- | ----------------------------------------------- | | `value` | `T` | the new value | | `order` | `MemoryOrder` | which other operations may move across this one | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Atomic/Src/Atomic.rux#L75){rel=""nofollow""} ### `Exchange` ```rux pub func Exchange(self: &Atomic<T>, value: T) -> T ``` Replaces the value and returns the one replaced, as one step, with sequential consistency. | Name | Type | Description | | ------- | ---- | ------------- | | `value` | `T` | the new value | **Returns**: the value before [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Atomic/Src/Atomic.rux#L88){rel=""nofollow""} ### `CompareExchange` ```rux pub func CompareExchange( self: &Atomic<T>, expected: T, desired: T ) -> T ! T ``` Replaces the value with `desired` if it is `expected`, as one step, with sequential consistency. Succeeds with the value before, which is `expected`, when it replaced it, and fails with the value it found otherwise, so a loop can retry from what is really there. Never fails spuriously. | Name | Type | Description | | ---------- | ---- | ---------------------------- | | `expected` | `T` | the value that must be there | | `desired` | `T` | the value to put there | **Returns**: the value before, as success when it was replaced and as failure when it was not [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Atomic/Src/Atomic.rux#L99){rel=""nofollow""} ### `CompareExchangeWith` ```rux pub func CompareExchangeWith( self: &Atomic<T>, expected: T, desired: T, success: MemoryOrder, failure: MemoryOrder ) -> T ! T ``` Replaces the value with `desired` if it is `expected`, with `success` when it does and `failure` when it does not. Orders a failure cannot have are strengthened to the nearest it can: `Release` reads as `Relaxed`, `AcquireRelease` as `Acquire`, and a failure order stronger than the success order as the success order's acquire part. | Name | Type | Description | | ---------- | ------------- | ------------------------------------ | | `expected` | `T` | the value that must be there | | `desired` | `T` | the value to put there | | `success` | `MemoryOrder` | the order when the value is replaced | | `failure` | `MemoryOrder` | the order when it is not | **Returns**: the value before, as success when it was replaced and as failure when it was not [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Atomic/Src/Atomic.rux#L117){rel=""nofollow""} ### `FetchAdd` ```rux pub func FetchAdd(self: &Atomic<T>, value: T) -> T ``` Adds `value`, wrapping on overflow, and returns the value before, as one step, with sequential consistency. Only for integer `T`. | Name | Type | Description | | ------- | ---- | ----------- | | `value` | `T` | what to add | **Returns**: the value before the addition [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Atomic/Src/Atomic.rux#L146){rel=""nofollow""} ### `FetchSub` ```rux pub func FetchSub(self: &Atomic<T>, value: T) -> T ``` Subtracts `value`, wrapping on overflow, and returns the value before, as one step, with sequential consistency. Only for integer `T`. | Name | Type | Description | | ------- | ---- | ---------------- | | `value` | `T` | what to subtract | **Returns**: the value before the subtraction [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Atomic/Src/Atomic.rux#L156){rel=""nofollow""} ### `FetchAddWith` ```rux pub func FetchAddWith( self: &Atomic<T>, value: T, order: MemoryOrder ) -> T ``` Adds `value` with `order`, wrapping on overflow, and returns the value before. The relaxed form is what a counter whose value nothing else depends on needs. Only for integer `T`. | Name | Type | Description | | ------- | ------------- | ----------------------------------------------- | | `value` | `T` | what to add | | `order` | `MemoryOrder` | which other operations may move across this one | **Returns**: the value before the addition [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Atomic/Src/Atomic.rux#L166){rel=""nofollow""} ### `FetchSubWith` ```rux pub func FetchSubWith( self: &Atomic<T>, value: T, order: MemoryOrder ) -> T ``` Subtracts `value` with `order`, wrapping on overflow, and returns the value before. The release form is what dropping one reference to shared data needs, so that the last one sees every write the others made. Only for integer `T`. | Name | Type | Description | | ------- | ------------- | ----------------------------------------------- | | `value` | `T` | what to subtract | | `order` | `MemoryOrder` | which other operations may move across this one | **Returns**: the value before the subtraction [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Atomic/Src/Atomic.rux#L183){rel=""nofollow""} ### `FetchAnd` ```rux pub func FetchAnd(self: &Atomic<T>, value: T) -> T ``` Combines the value with `value` by bitwise and, and returns the value before, with sequential consistency. Only for integer or `bool` `T`. | Name | Type | Description | | ------- | ---- | ---------------- | | `value` | `T` | the bits to keep | **Returns**: the value before [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Atomic/Src/Atomic.rux#L198){rel=""nofollow""} ### `FetchOr` ```rux pub func FetchOr(self: &Atomic<T>, value: T) -> T ``` Combines the value with `value` by bitwise or, and returns the value before, with sequential consistency. Only for integer or `bool` `T`. | Name | Type | Description | | ------- | ---- | --------------- | | `value` | `T` | the bits to set | **Returns**: the value before [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Atomic/Src/Atomic.rux#L207){rel=""nofollow""} ### `FetchXor` ```rux pub func FetchXor(self: &Atomic<T>, value: T) -> T ``` Combines the value with `value` by bitwise exclusive or, and returns the value before, with sequential consistency. Only for integer or `bool` `T`. | Name | Type | Description | | ------- | ---- | ---------------- | | `value` | `T` | the bits to flip | **Returns**: the value before [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Atomic/Src/Atomic.rux#L217){rel=""nofollow""} ## Constants ### `Zero` ```rux pub const Zero: Atomic<int8> = Atomic<int8> { value: 0i8 }; ``` An atomic `int8` holding zero, as a constant, so a module variable can start as one through an alias of [`Atomic<int8>`](https://rux-lang.dev/docs/api/atomic/atomic). [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Atomic/Src/Atomic.rux#L230){rel=""nofollow""} ### `Zero` ```rux pub const Zero: Atomic<int16> = Atomic<int16> { value: 0i16 }; ``` An atomic `int16` holding zero, as a constant, so a module variable can start as one through an alias of [`Atomic<int16>`](https://rux-lang.dev/docs/api/atomic/atomic). [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Atomic/Src/Atomic.rux#L237){rel=""nofollow""} ### `Zero` ```rux pub const Zero: Atomic<int32> = Atomic<int32> { value: 0i32 }; ``` An atomic `int32` holding zero, as a constant, so a module variable can start as one through an alias of [`Atomic<int32>`](https://rux-lang.dev/docs/api/atomic/atomic). [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Atomic/Src/Atomic.rux#L244){rel=""nofollow""} ### `Zero` ```rux pub const Zero: Atomic<int64> = Atomic<int64> { value: 0i64 }; ``` An atomic `int64` holding zero, as a constant, so a module variable can start as one through an alias of [`Atomic<int64>`](https://rux-lang.dev/docs/api/atomic/atomic). [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Atomic/Src/Atomic.rux#L251){rel=""nofollow""} ### `Zero` ```rux pub const Zero: Atomic<int> = Atomic<int> { value: 0 }; ``` An atomic `int` holding zero, as a constant, so a module variable can start as one through an alias of [`Atomic<int>`](https://rux-lang.dev/docs/api/atomic/atomic). [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Atomic/Src/Atomic.rux#L258){rel=""nofollow""} ### `Zero` ```rux pub const Zero: Atomic<uint8> = Atomic<uint8> { value: 0u8 }; ``` An atomic `uint8` holding zero, as a constant, so a module variable can start as one through an alias of [`Atomic<uint8>`](https://rux-lang.dev/docs/api/atomic/atomic). [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Atomic/Src/Atomic.rux#L265){rel=""nofollow""} ### `Zero` ```rux pub const Zero: Atomic<uint16> = Atomic<uint16> { value: 0u16 }; ``` An atomic `uint16` holding zero, as a constant, so a module variable can start as one through an alias of [`Atomic<uint16>`](https://rux-lang.dev/docs/api/atomic/atomic). [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Atomic/Src/Atomic.rux#L272){rel=""nofollow""} ### `Zero` ```rux pub const Zero: Atomic<uint32> = Atomic<uint32> { value: 0u32 }; ``` An atomic `uint32` holding zero, as a constant, so a module variable can start as one through an alias of [`Atomic<uint32>`](https://rux-lang.dev/docs/api/atomic/atomic). [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Atomic/Src/Atomic.rux#L279){rel=""nofollow""} ### `Zero` ```rux pub const Zero: Atomic<uint64> = Atomic<uint64> { value: 0u64 }; ``` An atomic `uint64` holding zero, as a constant, so a module variable can start as one through an alias of [`Atomic<uint64>`](https://rux-lang.dev/docs/api/atomic/atomic). [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Atomic/Src/Atomic.rux#L286){rel=""nofollow""} ### `Zero` ```rux pub const Zero: Atomic<uint> = Atomic<uint> { value: 0u }; ``` An atomic `uint` holding zero, as a constant, so a module variable can start as one through an alias of [`Atomic<uint>`](https://rux-lang.dev/docs/api/atomic/atomic). [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Atomic/Src/Atomic.rux#L293){rel=""nofollow""} ### `False` ```rux pub const False: Atomic<bool> = Atomic<bool> { value: false }; ``` An atomic `bool` holding false, as a constant, so a module variable can start as one through an alias of [`Atomic<bool>`](https://rux-lang.dev/docs/api/atomic/atomic). [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Atomic/Src/Atomic.rux#L300){rel=""nofollow""} # Sync Locks, conditions, once-only initialization, semaphores, barriers, wait groups and channels for threads. ## Installation Add `Sync` to the `[Dependencies]` table of your package's `Rux.toml`: ```toml [Dependencies] Sync = { Namespace = "Rux", Version = "0.1.0" } ``` Standard packages are declared by hand: the registry does not serve them, so `rux add Rux/Sync` cannot add them. ## Dependencies - [`Core`](https://rux-lang.dev/docs/api/core) 0.1.0 - [`FreeBSD`](https://rux-lang.dev/docs/api/freebsd) 0.1.0 (FreeBSD only) - [`Linux`](https://rux-lang.dev/docs/api/linux) 0.1.0 (Linux only) - [`macOS`](https://rux-lang.dev/docs/api/macos) 0.1.0 (macOS only) - [`Memory`](https://rux-lang.dev/docs/api/memory) 0.1.0 - [`Time`](https://rux-lang.dev/docs/api/time) 0.1.0 - [`Windows`](https://rux-lang.dev/docs/api/windows) 0.1.0 (Windows only) ## Guide ### What it provides | Module | Covers | | --------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `Lock` | `Lock`, a bare lock, and [`Once`](https://rux-lang.dev/docs/api/sync/lock#once), a once-only initialization; both can be module variables | | [`Mutex`](https://rux-lang.dev/docs/api/sync/mutex#mutex) | [`Mutex<T>`](https://rux-lang.dev/docs/api/sync/mutex#mutex) with its [`MutexGuard<T>`](https://rux-lang.dev/docs/api/sync/mutex#mutex-guard), and [`Condition`](https://rux-lang.dev/docs/api/sync/mutex#condition) to wait on while holding one | | [`RwLock`](https://rux-lang.dev/docs/api/sync/rw-lock#rw-lock) | [`RwLock<T>`](https://rux-lang.dev/docs/api/sync/rw-lock#rw-lock) with [`ReadGuard<T>`](https://rux-lang.dev/docs/api/sync/rw-lock#read-guard) and [`WriteGuard<T>`](https://rux-lang.dev/docs/api/sync/rw-lock#write-guard): many readers or one writer | | `Counters` | [`Semaphore`](https://rux-lang.dev/docs/api/sync/counters#semaphore), [`Barrier`](https://rux-lang.dev/docs/api/sync/counters#barrier) and [`WaitGroup`](https://rux-lang.dev/docs/api/sync/counters#wait-group) | | [`Channel`](https://rux-lang.dev/docs/api/sync/channel#channel) | [`Channel<T>`](https://rux-lang.dev/docs/api/sync/channel#channel), a bounded queue any number of threads send to and receive from | The module names describe where each declaration comes from; they are not part of an import path. ### Example ```rux import Sync::Mutex; import Thread::{ JoinHandle, Spawn }; func AddOne(total: Mutex<uint64>) -> () { let guard = total.Lock(); *guard.Get() = *guard.Get() + 1u64; } func Main() -> int { let total = Mutex<uint64>(0u64); var first = Spawn(AddOne, total.Clone()) catch { else => return 1 }; var second = Spawn(AddOne, total.Clone()) catch { else => return 1 }; first.Join(); second.Join(); let guard = total.Lock(); return *guard.Get() == 2u64 ? 0 : 2; } ``` ### Design Every type here waits the same way: a thread sleeps on a 32-bit word only while the word still holds the value it last saw, and the system checks that as it puts the thread to sleep, so a change that lands just before the sleep is never missed. That is `futex` on Linux, `_umtx_op` on FreeBSD, `__ulock_wait` on macOS and `WaitOnAddress` on Windows. Taking a free lock and releasing one nobody waits for are each one atomic instruction; only contention costs a system call. `Lock` and [`Once`](https://rux-lang.dev/docs/api/sync/lock#once) live where they are declared and need no destroying, so a module variable can be one, starting as [`Lock::Unlocked`](https://rux-lang.dev/docs/api/sync/lock#unlocked) or [`Once::Incomplete`](https://rux-lang.dev/docs/api/sync/lock#incomplete), and every thread names it directly. The other types are handles to storage their clones share: `Clone` gives another handle to move to another thread, and the storage, with the value a [`Mutex<T>`](https://rux-lang.dev/docs/api/sync/mutex#mutex), [`RwLock<T>`](https://rux-lang.dev/docs/api/sync/rw-lock#rw-lock) or [`Channel<T>`](https://rux-lang.dev/docs/api/sync/channel#channel) holds, is destroyed when the last handle and the last guard are gone. A guard is the only way to reach a guarded value, and it releases its lock when it is dropped. The value's address a guard hands out is valid only while the guard holds the lock. None of the locks is reentrant, and none queues its waiters in order: [`RwLock`](https://rux-lang.dev/docs/api/sync/rw-lock#rw-lock) can keep a writer waiting behind a steady stream of readers. A [`Condition`](https://rux-lang.dev/docs/api/sync/mutex#condition) wait can return without a notification, so it is always written in a loop that checks the condition. Running out of memory while creating one of these objects is a program error, as is misuse the type cannot recover from, such as marking a [`WaitGroup`](https://rux-lang.dev/docs/api/sync/counters#wait-group) done more times than work was added. ## Index ### Types | Name | Summary | | ------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | [`Channel<T>`](https://rux-lang.dev/docs/api/sync/channel#channel) | A bounded queue of values passed between threads, any number of which may send and receive. | | [`Semaphore`](https://rux-lang.dev/docs/api/sync/counters#semaphore) | A count of permits that threads take and give back, waiting while none is left. | | [`Barrier`](https://rux-lang.dev/docs/api/sync/counters#barrier) | A meeting point a fixed number of threads wait at until all of them have arrived, then pass together. | | [`WaitGroup`](https://rux-lang.dev/docs/api/sync/counters#wait-group) | A count of unfinished work that threads add to and mark done, and that others wait to see reach zero. | | [`Lock`](https://rux-lang.dev/docs/api/sync/lock#lock) | A lock that guards nothing in particular: whatever the code between [`Acquire`](https://rux-lang.dev/docs/api/sync/lock#acquire) and [`Release`](https://rux-lang.dev/docs/api/sync/lock#release) touches. | | [`Once`](https://rux-lang.dev/docs/api/sync/lock#once) | Runs one initialization once, however many threads ask for it at once. | | [`Mutex<T>`](https://rux-lang.dev/docs/api/sync/mutex#mutex) | A value guarded by a lock, shared between the threads that hold a handle to it. | | [`MutexGuard<T>`](https://rux-lang.dev/docs/api/sync/mutex#mutex-guard) | The lock on a [`Mutex<T>`](https://rux-lang.dev/docs/api/sync/mutex#mutex), held for as long as the guard lives, and the way to reach the value. | | [`Condition`](https://rux-lang.dev/docs/api/sync/mutex#condition) | A condition threads wait on while holding a [`Mutex<T>`](https://rux-lang.dev/docs/api/sync/mutex#mutex), until another thread says it may hold. | | [`RwLock<T>`](https://rux-lang.dev/docs/api/sync/rw-lock#rw-lock) | A value guarded by a lock that many readers or one writer may hold, shared between the threads that hold a handle. | | [`ReadGuard<T>`](https://rux-lang.dev/docs/api/sync/rw-lock#read-guard) | A shared hold on an [`RwLock<T>`](https://rux-lang.dev/docs/api/sync/rw-lock#rw-lock): the value may be read, and other readers may hold it too. | | [`WriteGuard<T>`](https://rux-lang.dev/docs/api/sync/rw-lock#write-guard) | The exclusive hold on an [`RwLock<T>`](https://rux-lang.dev/docs/api/sync/rw-lock#rw-lock): the value may be read and written, and nobody else holds the lock. | # Channels Bounded queues that carry values from thread to thread. ## `Channel<T>` ```rux pub struct Channel<T> { // private fields } ``` A bounded queue of values passed between threads, any number of which may send and receive. Values arrive in the order they were sent. [`Clone`](https://rux-lang.dev/docs/api/sync/channel#clone) gives another handle to the same channel; the values still in it are destroyed when the last handle is gone. A handle is not copied. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Sync/Src/Channel.rux#L32){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | ---------------------- | | `T` | the type of the values | **Constructors** ### `Channel` ```rux pub func Channel(capacity: uint) -> Channel<T> ``` A channel with room for `capacity` values. Zero capacity is a program error, as is running out of memory. | Name | Type | Description | | ---------- | ------ | ----------------------------------------------- | | `capacity` | `uint` | how many values may wait in the channel at once | **Returns**: the first handle to it [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Sync/Src/Channel.rux#L43){rel=""nofollow""} **Methods** ### `Clone` ```rux pub func Clone(self: &Channel<T>) -> Channel<T> ``` Another handle to the same channel. **Returns**: the handle [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Sync/Src/Channel.rux#L58){rel=""nofollow""} ### `Send` ```rux pub func Send(self: &Channel<T>, value: T) -> ! T ``` Sends `value`, waiting while the channel is full. | Name | Type | Description | | ------- | ---- | ----------------- | | `value` | `T` | the value to send | **Returns**: nothing, or fails with the value when the channel is closed [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Sync/Src/Channel.rux#L67){rel=""nofollow""} ### `TrySend` ```rux pub func TrySend(self: &Channel<T>, value: T) -> ! T ``` Sends `value` if there is room, without waiting. | Name | Type | Description | | ------- | ---- | ----------------- | | `value` | `T` | the value to send | **Returns**: nothing, or fails with the value when the channel is full or closed [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Sync/Src/Channel.rux#L87){rel=""nofollow""} ### `Receive` ```rux pub func Receive(self: &Channel<T>) -> T? ``` Receives the oldest value, waiting while the channel is empty. **Returns**: the value, or none once the channel is closed and empty [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Sync/Src/Channel.rux#L100){rel=""nofollow""} ### `TryReceive` ```rux pub func TryReceive(self: &Channel<T>) -> T? ``` Receives the oldest value if there is one, without waiting. **Returns**: the value, or none when the channel is empty [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Sync/Src/Channel.rux#L119){rel=""nofollow""} ### `Close` ```rux pub func Close(self: &Channel<T>) ``` Closes the channel: sends fail from now on, and receivers take what is left and then get none. Closing a closed channel does nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Sync/Src/Channel.rux#L132){rel=""nofollow""} ### `IsClosed` ```rux pub func IsClosed(self: &Channel<T>) -> bool ``` Whether the channel was closed. **Returns**: true once [`Close`](https://rux-lang.dev/docs/api/sync/channel#close) was called on any handle [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Sync/Src/Channel.rux#L146){rel=""nofollow""} ### `Length` ```rux pub func Length(self: &Channel<T>) -> uint ``` How many values wait in the channel right now, which other threads may change at any moment. **Returns**: the number of values [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Sync/Src/Channel.rux#L157){rel=""nofollow""} **Destructor** ### `~Channel` ```rux func ~Channel(self: &var Channel<T>) ``` [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Sync/Src/Channel.rux#L187){rel=""nofollow""} # Counters Semaphores, barriers and wait groups. ## `Semaphore` ```rux pub struct Semaphore { // private fields } ``` A count of permits that threads take and give back, waiting while none is left. [`Clone`](https://rux-lang.dev/docs/api/sync/counters#clone-semaphore) gives another handle to the same permits. A handle is not copied. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Sync/Src/Counters.rux#L18){rel=""nofollow""} **Constructors** ### `Semaphore` ```rux pub func Semaphore(permits: uint32) -> Semaphore ``` A semaphore holding `permits` permits. Running out of memory for it is a program error. | Name | Type | Description | | --------- | -------- | ---------------------------------------- | | `permits` | `uint32` | how many permits there are to start with | **Returns**: the first handle to it [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Sync/Src/Counters.rux#L29){rel=""nofollow""} **Methods** ### `Clone` ```rux pub func Clone(self: &Semaphore) -> Semaphore ``` Another handle to the same permits. **Returns**: the handle [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Sync/Src/Counters.rux#L36){rel=""nofollow""} ### `Acquire` ```rux pub func Acquire(self: &Semaphore) ``` Takes a permit, waiting while none is left. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Sync/Src/Counters.rux#L43){rel=""nofollow""} ### `TryAcquire` ```rux pub func TryAcquire(self: &Semaphore) -> bool ``` Takes a permit if one is left, without waiting. **Returns**: whether a permit was taken [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Sync/Src/Counters.rux#L55){rel=""nofollow""} ### `Release` ```rux pub func Release(self: &Semaphore, count: uint32) ``` Gives back `count` permits, waking threads waiting for them. | Name | Type | Description | | ------- | -------- | ----------------------------- | | `count` | `uint32` | how many permits to give back | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Sync/Src/Counters.rux#L70){rel=""nofollow""} ### `Available` ```rux pub func Available(self: &Semaphore) -> uint32 ``` The permits left right now, which other threads may change at any moment. **Returns**: the number of permits [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Sync/Src/Counters.rux#L80){rel=""nofollow""} **Destructor** ### `~Semaphore` ```rux func ~Semaphore(self: &var Semaphore) ``` [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Sync/Src/Counters.rux#L84){rel=""nofollow""} ## `Barrier` ```rux pub struct Barrier { // private fields } ``` A meeting point a fixed number of threads wait at until all of them have arrived, then pass together. The barrier is reusable: once all have passed, the next [`Wait`](https://rux-lang.dev/docs/api/sync/counters#wait-barrier)s start a new round. [`Clone`](https://rux-lang.dev/docs/api/sync/counters#clone-barrier) gives another handle to the same barrier. A handle is not copied. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Sync/Src/Counters.rux#L102){rel=""nofollow""} **Constructors** ### `Barrier` ```rux pub func Barrier(parties: uint32) -> Barrier ``` A barrier for `parties` threads. Zero parties is a program error. Running out of memory is one too. | Name | Type | Description | | --------- | -------- | ------------------------------------- | | `parties` | `uint32` | how many threads each round waits for | **Returns**: the first handle to it [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Sync/Src/Counters.rux#L113){rel=""nofollow""} **Methods** ### `Clone` ```rux pub func Clone(self: &Barrier) -> Barrier ``` Another handle to the same barrier. **Returns**: the handle [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Sync/Src/Counters.rux#L123){rel=""nofollow""} ### `Wait` ```rux pub func Wait(self: &Barrier) -> bool ``` Waits until every party of this round has arrived. **Returns**: true on exactly one of the round's threads, the last to arrive, for work done once per round [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Sync/Src/Counters.rux#L131){rel=""nofollow""} **Destructor** ### `~Barrier` ```rux func ~Barrier(self: &var Barrier) ``` [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Sync/Src/Counters.rux#L147){rel=""nofollow""} ## `WaitGroup` ```rux pub struct WaitGroup { // private fields } ``` A count of unfinished work that threads add to and mark done, and that others wait to see reach zero. [`Clone`](https://rux-lang.dev/docs/api/sync/counters#clone-wait-group) gives another handle to the same count. A handle is not copied. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Sync/Src/Counters.rux#L162){rel=""nofollow""} **Constructors** ### `WaitGroup` ```rux pub func WaitGroup() -> WaitGroup ``` A wait group with nothing pending. Running out of memory for it is a program error. **Returns**: the first handle to it [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Sync/Src/Counters.rux#L172){rel=""nofollow""} **Methods** ### `Clone` ```rux pub func Clone(self: &WaitGroup) -> WaitGroup ``` Another handle to the same count. **Returns**: the handle [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Sync/Src/Counters.rux#L179){rel=""nofollow""} ### `Add` ```rux pub func Add(self: &WaitGroup, count: uint32) ``` Adds `count` pieces of pending work, before the work is started. | Name | Type | Description | | ------- | -------- | --------------- | | `count` | `uint32` | how many to add | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Sync/Src/Counters.rux#L187){rel=""nofollow""} ### `Done` ```rux pub func Done(self: &WaitGroup) ``` Marks one piece of work done, waking the waiters when it was the last. Marking more done than were added is a program error. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Sync/Src/Counters.rux#L194){rel=""nofollow""} ### `Wait` ```rux pub func Wait(self: &WaitGroup) ``` Waits until no work is pending. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Sync/Src/Counters.rux#L202){rel=""nofollow""} **Destructor** ### `~WaitGroup` ```rux func ~WaitGroup(self: &var WaitGroup) ``` [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Sync/Src/Counters.rux#L210){rel=""nofollow""} # Locks A plain lock, and running an initialization exactly once. ## `Lock` ```rux pub struct Lock { // private fields } ``` A lock that guards nothing in particular: whatever the code between [`Acquire`](https://rux-lang.dev/docs/api/sync/lock#acquire) and [`Release`](https://rux-lang.dev/docs/api/sync/lock#release) touches. Not reentrant: acquiring it again on the thread that holds it waits forever. Releasing it is the holder's job; releasing a lock another thread holds, or one nobody holds, is a program error the lock cannot detect. For data that a lock protects, [`Mutex<T>`](https://rux-lang.dev/docs/api/sync/mutex#mutex) keeps the two together and releases the lock for you. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Sync/Src/Lock.rux#L13){rel=""nofollow""} **Constructors** ### `Lock` ```rux pub func Lock() -> Lock ``` A lock nobody holds. **Returns**: the lock [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Sync/Src/Lock.rux#L25){rel=""nofollow""} **Methods** ### `Acquire` ```rux pub func Acquire(self: &Lock) ``` Takes the lock, waiting while another thread holds it. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Sync/Src/Lock.rux#L31){rel=""nofollow""} ### `TryAcquire` ```rux pub func TryAcquire(self: &Lock) -> bool ``` Takes the lock if nobody holds it, without waiting. **Returns**: whether the lock was taken [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Sync/Src/Lock.rux#L38){rel=""nofollow""} ### `Release` ```rux pub func Release(self: &Lock) ``` Releases the lock this thread holds, letting one waiting thread take it. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Sync/Src/Lock.rux#L44){rel=""nofollow""} **Constants** ### `Unlocked` ```rux pub const Unlocked: Lock = Lock { word: 0 }; ``` A lock nobody holds, as a constant, so a module variable can start as one: `var Guard: Lock = Lock::Unlocked;`. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Sync/Src/Lock.rux#L20){rel=""nofollow""} ## `Once` ```rux pub struct Once { // private fields } ``` Runs one initialization once, however many threads ask for it at once. The first [`Call`](https://rux-lang.dev/docs/api/sync/lock#call) runs its function; every other waits until that has returned and then returns without running its own. Everything the function wrote is visible to every thread [`Call`](https://rux-lang.dev/docs/api/sync/lock#call) returns on. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Sync/Src/Lock.rux#L58){rel=""nofollow""} **Constructors** ### `Once` ```rux pub func Once() -> Once ``` An initialization that has not run. **Returns**: the once [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Sync/Src/Lock.rux#L71){rel=""nofollow""} **Methods** ### `Call` ```rux pub func Call(self: &Once, initialize: func()) ``` Runs `initialize` if no call has run one yet, and returns once an initialization has finished. An initializer that panics ends the process, so a half-finished one is never observed. | Name | Type | Description | | ------------ | -------- | ------------------------ | | `initialize` | `func()` | the function to run once | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Sync/Src/Lock.rux#L79){rel=""nofollow""} ### `IsCompleted` ```rux pub func IsCompleted(self: &Once) -> bool ``` Whether an initialization has finished. **Returns**: true once a [`Call`](https://rux-lang.dev/docs/api/sync/lock#call) has run its function to the end [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Sync/Src/Lock.rux#L97){rel=""nofollow""} **Constants** ### `Incomplete` ```rux pub const Incomplete: Once = Once { state: 0 }; ``` An initialization that has not run, as a constant, so a module variable can start as one: `var Setup: Once = Once::Incomplete;`. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Sync/Src/Lock.rux#L66){rel=""nofollow""} # Mutexes A value one thread at a time may reach, and the conditions threads wait on while holding it. ## `Mutex<T>` ```rux pub struct Mutex<T> { // private fields } ``` A value guarded by a lock, shared between the threads that hold a handle to it. [`Clone`](https://rux-lang.dev/docs/api/sync/mutex#clone) gives another handle to the same value, to move to another thread. The value is destroyed when the last handle and the last guard are gone. A handle is not copied. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Sync/Src/Mutex.rux#L24){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | ----------------------------- | | `T` | the type of the guarded value | **Constructors** ### `Mutex` ```rux pub func Mutex(value: T) -> Mutex<T> ``` A new lock guarding `value`. Running out of memory for it is a program error. | Name | Type | Description | | ------- | ---- | ------------------ | | `value` | `T` | the value to guard | **Returns**: the first handle to it [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Sync/Src/Mutex.rux#L43){rel=""nofollow""} **Methods** ### `Clone` ```rux pub func Clone(self: &Mutex<T>) -> Mutex<T> ``` Another handle to the same value. **Returns**: the handle [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Sync/Src/Mutex.rux#L50){rel=""nofollow""} ### `Lock` ```rux pub func Lock(self: &Mutex<T>) -> MutexGuard<T> ``` Takes the lock, waiting while another thread holds it, and returns the guard that holds it. Not reentrant: locking again on the thread that holds the lock waits forever. **Returns**: the guard [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Sync/Src/Mutex.rux#L59){rel=""nofollow""} ### `TryLock` ```rux pub func TryLock(self: &Mutex<T>) -> MutexGuard<T>? ``` Takes the lock if nobody holds it, without waiting. **Returns**: the guard, or none when another thread holds the lock [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Sync/Src/Mutex.rux#L68){rel=""nofollow""} **Destructor** ### `~Mutex` ```rux func ~Mutex(self: &var Mutex<T>) ``` [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Sync/Src/Mutex.rux#L74){rel=""nofollow""} ## `MutexGuard<T>` ```rux pub struct MutexGuard<T> { // private fields } ``` The lock on a [`Mutex<T>`](https://rux-lang.dev/docs/api/sync/mutex#mutex), held for as long as the guard lives, and the way to reach the value. Dropping the guard, or calling [`Unlock`](https://rux-lang.dev/docs/api/sync/mutex#unlock), releases the lock. A guard is not copied. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Sync/Src/Mutex.rux#L32){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | ----------------------------- | | `T` | the type of the guarded value | **Methods** ### `Get` ```rux pub func Get(self: &MutexGuard<T>) -> *var T ``` The guarded value, which this thread alone may read and write while the guard holds the lock. The address is valid for as long as the guard holds the lock; keeping it longer is a program error. **Returns**: the value's address [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Sync/Src/Mutex.rux#L88){rel=""nofollow""} ### `IsLocked` ```rux pub func IsLocked(self: &MutexGuard<T>) -> bool ``` Whether the guard still holds the lock. **Returns**: false once [`Unlock`](https://rux-lang.dev/docs/api/sync/mutex#unlock) was called [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Sync/Src/Mutex.rux#L95){rel=""nofollow""} ### `Unlock` ```rux pub func Unlock(self: &var MutexGuard<T>) ``` Releases the lock before the guard is dropped. Unlocking a guard twice does nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Sync/Src/Mutex.rux#L101){rel=""nofollow""} **Destructor** ### `~MutexGuard` ```rux func ~MutexGuard(self: &var MutexGuard<T>) ``` [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Sync/Src/Mutex.rux#L111){rel=""nofollow""} ## `Condition` ```rux pub struct Condition { // private fields } ``` A condition threads wait on while holding a [`Mutex<T>`](https://rux-lang.dev/docs/api/sync/mutex#mutex), until another thread says it may hold. A wait releases the lock while it sleeps and takes it again before it returns, so the waiter re-checks the condition under the lock. A wait may also return when nothing notified it, which is why it is always called in a loop that checks the condition. [`Clone`](https://rux-lang.dev/docs/api/sync/mutex#clone-condition) gives another handle to the same condition. A handle is not copied. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Sync/Src/Mutex.rux#L126){rel=""nofollow""} **Constructors** ### `Condition` ```rux pub func Condition() -> Condition ``` A new condition. Running out of memory for it is a program error. **Returns**: the first handle to it [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Sync/Src/Mutex.rux#L136){rel=""nofollow""} **Methods** ### `Clone` ```rux pub func Clone(self: &Condition) -> Condition ``` Another handle to the same condition. **Returns**: the handle [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Sync/Src/Mutex.rux#L143){rel=""nofollow""} ### `Wait` ```rux pub func Wait<T>( self: &Condition, guard: &var MutexGuard<T> ) ``` Releases the guard's lock, sleeps until notified, and takes the lock again. | Type parameter | Description | | -------------- | ----------------------------- | | `T` | the type of the guarded value | | Name | Type | Description | | ------- | -------------------- | --------------------------- | | `guard` | `&var MutexGuard<T>` | a guard that holds its lock | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Sync/Src/Mutex.rux#L152){rel=""nofollow""} ### `WaitFor` ```rux pub func WaitFor<T>( self: &Condition, guard: &var MutexGuard<T>, timeout: Duration ) -> bool ``` Releases the guard's lock, sleeps until notified or until `timeout` has passed, and takes the lock again. | Type parameter | Description | | -------------- | ----------------------------- | | `T` | the type of the guarded value | | Name | Type | Description | | --------- | -------------------- | ------------------------------------------------------ | | `guard` | `&var MutexGuard<T>` | a guard that holds its lock | | `timeout` | `Duration` | how long to wait at most; a negative one does not wait | **Returns**: false when the time ran out without a notification [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Sync/Src/Mutex.rux#L162){rel=""nofollow""} ### `NotifyOne` ```rux pub func NotifyOne(self: &Condition) ``` Wakes one thread waiting on the condition, if any. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Sync/Src/Mutex.rux#L170){rel=""nofollow""} ### `NotifyAll` ```rux pub func NotifyAll(self: &Condition) ``` Wakes every thread waiting on the condition. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Sync/Src/Mutex.rux#L177){rel=""nofollow""} **Destructor** ### `~Condition` ```rux func ~Condition(self: &var Condition) ``` [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Sync/Src/Mutex.rux#L194){rel=""nofollow""} # Reader-writer locks A value many threads may read at once, or one may write. ## `RwLock<T>` ```rux pub struct RwLock<T> { // private fields } ``` A value guarded by a lock that many readers or one writer may hold, shared between the threads that hold a handle. [`Clone`](https://rux-lang.dev/docs/api/sync/rw-lock#clone) gives another handle to the same value. The value is destroyed when the last handle and the last guard are gone. A handle is not copied. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Sync/Src/RwLock.rux#L25){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | ----------------------------- | | `T` | the type of the guarded value | **Constructors** ### `RwLock` ```rux pub func RwLock(value: T) -> RwLock<T> ``` A new lock guarding `value`. Running out of memory for it is a program error. | Name | Type | Description | | ------- | ---- | ------------------ | | `value` | `T` | the value to guard | **Returns**: the first handle to it [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Sync/Src/RwLock.rux#L50){rel=""nofollow""} **Methods** ### `Clone` ```rux pub func Clone(self: &RwLock<T>) -> RwLock<T> ``` Another handle to the same value. **Returns**: the handle [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Sync/Src/RwLock.rux#L59){rel=""nofollow""} ### `Read` ```rux pub func Read(self: &RwLock<T>) -> ReadGuard<T> ``` Takes a shared hold, waiting while a writer holds the lock. **Returns**: the read guard [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Sync/Src/RwLock.rux#L67){rel=""nofollow""} ### `Write` ```rux pub func Write(self: &RwLock<T>) -> WriteGuard<T> ``` Takes the exclusive hold, waiting while any reader or writer holds the lock. **Returns**: the write guard [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Sync/Src/RwLock.rux#L87){rel=""nofollow""} **Destructor** ### `~RwLock` ```rux func ~RwLock(self: &var RwLock<T>) ``` [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Sync/Src/RwLock.rux#L99){rel=""nofollow""} ## `ReadGuard<T>` ```rux pub struct ReadGuard<T> { // private fields } ``` A shared hold on an [`RwLock<T>`](https://rux-lang.dev/docs/api/sync/rw-lock#rw-lock): the value may be read, and other readers may hold it too. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Sync/Src/RwLock.rux#L32){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | ----------------------------- | | `T` | the type of the guarded value | **Methods** ### `Get` ```rux pub func Get(self: &ReadGuard<T>) -> *T ``` The guarded value, to read while the guard holds the lock. **Returns**: the value's address [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Sync/Src/RwLock.rux#L112){rel=""nofollow""} **Destructor** ### `~ReadGuard` ```rux func ~ReadGuard(self: &var ReadGuard<T>) ``` [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Sync/Src/RwLock.rux#L116){rel=""nofollow""} ## `WriteGuard<T>` ```rux pub struct WriteGuard<T> { // private fields } ``` The exclusive hold on an [`RwLock<T>`](https://rux-lang.dev/docs/api/sync/rw-lock#rw-lock): the value may be read and written, and nobody else holds the lock. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Sync/Src/RwLock.rux#L39){rel=""nofollow""} **Type parameters** | Name | Description | | ---- | ----------------------------- | | `T` | the type of the guarded value | **Methods** ### `Get` ```rux pub func Get(self: &WriteGuard<T>) -> *var T ``` The guarded value, which this thread alone may read and write while the guard holds the lock. **Returns**: the value's address [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Sync/Src/RwLock.rux#L133){rel=""nofollow""} **Destructor** ### `~WriteGuard` ```rux func ~WriteGuard(self: &var WriteGuard<T>) ``` [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Sync/Src/RwLock.rux#L137){rel=""nofollow""} # Encoding Hexadecimal, Base64, Base32, Base58 and percent-encoding of byte sequences. ## Installation Add `Encoding` to the `[Dependencies]` table of your package's `Rux.toml`: ```toml [Dependencies] Encoding = { Namespace = "Rux", Version = "0.1.0" } ``` Standard packages are declared by hand: the registry does not serve them, so `rux add Rux/Encoding` cannot add them. ## Dependencies - [`Io`](https://rux-lang.dev/docs/api/io) 0.1.0 - [`Text`](https://rux-lang.dev/docs/api/text) 0.1.0 ## Guide ### What it provides | Module | Covers | | --------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `Hex` | [`HexEncode`](https://rux-lang.dev/docs/api/encoding/hex#hex-encode), [`HexDecode`](https://rux-lang.dev/docs/api/encoding/hex#hex-decode), their length functions, [`HexCase`](https://rux-lang.dev/docs/api/encoding/hex#hex-case), and the [`ViewHex`](https://rux-lang.dev/docs/api/encoding/hex#view-hex) display adapter | | `Base64` | [`Base64Encode`](https://rux-lang.dev/docs/api/encoding/base64#base64-encode), [`Base64Decode`](https://rux-lang.dev/docs/api/encoding/base64#base64-decode), their length functions, the four [`Base64Variant`](https://rux-lang.dev/docs/api/encoding/base64#base64-variant)s, and [`ViewBase64`](https://rux-lang.dev/docs/api/encoding/base64#view-base64) | | `Base32` | [`Base32Encode`](https://rux-lang.dev/docs/api/encoding/base32#base32-encode), [`Base32Decode`](https://rux-lang.dev/docs/api/encoding/base32#base32-decode), their length functions, and the RFC 4648 and Crockford [`Base32Variant`](https://rux-lang.dev/docs/api/encoding/base32#base32-variant)s | | `Base58` | [`Base58Encode`](https://rux-lang.dev/docs/api/encoding/base58#base58-encode), [`Base58Decode`](https://rux-lang.dev/docs/api/encoding/base58#base58-decode) and [`Base58EncodedMaxLength`](https://rux-lang.dev/docs/api/encoding/base58#base58-encoded-max-length), in the Bitcoin alphabet | | `Percent` | [`PercentEncode`](https://rux-lang.dev/docs/api/encoding/percent#percent-encode), [`PercentDecode`](https://rux-lang.dev/docs/api/encoding/percent#percent-decode), their length functions, and the `Component`, `Path` and `Form` sets | | `Stream` | [`EncodingWriter`](https://rux-lang.dev/docs/api/encoding/stream#encoding-writer) and [`DecodingReader`](https://rux-lang.dev/docs/api/encoding/stream#decoding-reader), which encode and decode hexadecimal, Base64 and Base32 through `Io` streams | | `Error` | [`DecodeError`](https://rux-lang.dev/docs/api/encoding/decode-error), shared by every decoder | The module names describe where each declaration comes from; they are not part of an import path. ### Example ```rux import Encoding::{ Base64Decode, Base64DecodedLength, Base64Encode, Base64EncodedLength, Base64Variant }; func RoundTrip() -> bool { let message = "Many hands make light work."; var text: char8[64]; let written = Base64Encode(message, text[..], Base64Variant::UrlUnpadded) catch { else => 0 }; var bytes: byte[64]; let read = Base64Decode(text[..written], bytes[..], Base64Variant::UrlUnpadded) catch { else => 0 }; return read == message.length && written == Base64EncodedLength(message.length, Base64Variant::UrlUnpadded); } ``` ### Design Every function writes into a destination the caller provides and returns how much it wrote, so nothing here allocates. Each scheme has a length function that says exactly how large that destination must be, except Base58, whose length depends on the value and which offers a bound instead. [`ViewHex`](https://rux-lang.dev/docs/api/encoding/hex#view-hex) and [`ViewBase64`](https://rux-lang.dev/docs/api/encoding/base64#view-base64) borrow bytes and render them under a format placeholder, which is the way to get an allocated string: `Render("{}", ViewHex(digest))`. A destination that is too short is refused rather than filled with what fits, because a truncated encoding is a different value rather than a shorter one. Encoders report `FormatError::InsufficientCapacity`; decoders report `DecodeError::InsufficientCapacity` with the length they needed. Decoders check the whole text before writing a byte, so every refusal except Base58's capacity refusal leaves the destination exactly as it was. Decoding is strict, so that each value has one encoded form and two systems cannot read the same text differently. Hexadecimal and Base32 accept either case and nothing else: no prefix, no separators, no whitespace. Base64 accepts only its variant's alphabet, padding only where the variant puts it, and a last character whose unused bits are zero. The exceptions are deliberate: Crockford's Base32 reads `I` and `L` as `1`, `O` as `0` and skips hyphens because its specification asks readers to, and percent-decoding passes through characters an encoder would have escaped because text arrives from many encoders. Each [`DecodeError`](https://rux-lang.dev/docs/api/encoding/decode-error) carries where it was found: the byte offset of the character that is wrong, or the end of the text when the length is. ### Streams [`EncodingWriter`](https://rux-lang.dev/docs/api/encoding/stream#encoding-writer) encodes what is written to it onto another `Io::Writer`, and [`DecodingReader`](https://rux-lang.dev/docs/api/encoding/stream#decoding-reader) decodes text from another `Io::Reader`, for hexadecimal, Base64 and Base32 in every form a [`StreamCodec`](https://rux-lang.dev/docs/api/encoding/stream#stream-codec) names. Both work a group at a time through the slice functions, so the text a stream writes is exactly the text encoding the whole input would give. A writer holds back the bytes of an incomplete group until [`Finish`](https://rux-lang.dev/docs/api/encoding/stream#encoding-writer-finish) ends the text with its last group and padding. A reader decodes the text it has read in whole groups and fails with `InvalidInput` when it reaches text the decoder refuses. Base58 has no streaming form, since every one of its characters depends on the whole input. ### Timing Keys, tokens and secrets travel through these encodings as often as anything else, so hexadecimal, Base64 and RFC 4648 Base32 encode and decode in time that depends only on the length. They map digits with masks built from arithmetic rather than branches or table lookups, which would otherwise make the timing and the cache lines touched depend on the secret. Base58 and Crockford's Base32 are meant for identifiers and do not make that promise. ## Index ### Types | Name | Summary | | --------------------------------------------------------------------------------- | -------------------------------------------------------------------------------- | | [`Base32Variant`](https://rux-lang.dev/docs/api/encoding/base32#base32-variant) | Which Base32 alphabet a text uses, and whether it is padded. | | [`Base64Variant`](https://rux-lang.dev/docs/api/encoding/base64#base64-variant) | Which Base64 alphabet a text uses, and whether it is padded. | | [`Base64View`](https://rux-lang.dev/docs/api/encoding/base64#base64-view) | A borrowed byte sequence that renders as Base64 under a format placeholder. | | [`DecodeError`](https://rux-lang.dev/docs/api/encoding/decode-error) | Why text could not be decoded. | | [`HexCase`](https://rux-lang.dev/docs/api/encoding/hex#hex-case) | Which case hexadecimal digits above nine are written in. | | [`HexView`](https://rux-lang.dev/docs/api/encoding/hex#hex-view) | A borrowed byte sequence that renders as hexadecimal under a format placeholder. | | [`PercentSet`](https://rux-lang.dev/docs/api/encoding/percent#percent-set) | Which characters percent-encoding leaves as they are. | | [`StreamCodec`](https://rux-lang.dev/docs/api/encoding/stream#stream-codec) | Which encoding a stream uses, with the form of it. | | [`EncodingWriter`](https://rux-lang.dev/docs/api/encoding/stream#encoding-writer) | A writer that encodes what is written to it onto another writer. | | [`DecodingReader`](https://rux-lang.dev/docs/api/encoding/stream#decoding-reader) | A reader that decodes text from another reader into bytes. | ### Functions | Name | Summary | | --------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------ | | [`Base32EncodedLength`](https://rux-lang.dev/docs/api/encoding/base32#base32-encoded-length) | How many characters the Base32 form of `length` bytes occupies in `form`. | | [`Base32Encode`](https://rux-lang.dev/docs/api/encoding/base32#base32-encode) | Writes `bytes` as Base32 into `into`. | | [`Base32DecodedLength`](https://rux-lang.dev/docs/api/encoding/base32#base32-decoded-length) | How many bytes the Base32 text decodes to, after checking its length and the placement of its padding. | | [`Base32Decode`](https://rux-lang.dev/docs/api/encoding/base32#base32-decode) | Reads Base32 text in `form` into `into`. | | [`Base58EncodedMaxLength`](https://rux-lang.dev/docs/api/encoding/base58#base58-encoded-max-length) | The most characters the Base58 form of `length` bytes can occupy. | | [`Base58Encode`](https://rux-lang.dev/docs/api/encoding/base58#base58-encode) | Writes `bytes` as Base58 into the front of `into`. | | [`Base58Decode`](https://rux-lang.dev/docs/api/encoding/base58#base58-decode) | Reads Base58 text in the Bitcoin alphabet into the front of `into`. | | [`Base64EncodedLength`](https://rux-lang.dev/docs/api/encoding/base64#base64-encoded-length) | How many characters the Base64 form of `length` bytes occupies in `form`. | | [`Base64Encode`](https://rux-lang.dev/docs/api/encoding/base64#base64-encode) | Writes `bytes` as Base64 into `into`. | | [`Base64DecodedLength`](https://rux-lang.dev/docs/api/encoding/base64#base64-decoded-length) | How many bytes the Base64 text decodes to, after checking its length and the placement of its padding. | | [`Base64Decode`](https://rux-lang.dev/docs/api/encoding/base64#base64-decode) | Reads Base64 text in `form` into `into`. | | [`ViewBase64`](https://rux-lang.dev/docs/api/encoding/base64#view-base64) | Borrows `bytes` for rendering as Base64. | | [`HexEncodedLength`](https://rux-lang.dev/docs/api/encoding/hex#hex-encoded-length) | How many characters the hexadecimal form of `length` bytes occupies: exactly twice as many. | | [`HexEncode`](https://rux-lang.dev/docs/api/encoding/hex#hex-encode) | Writes `bytes` as hexadecimal digits into `into`, two per byte, high nibble first. | | [`HexDecodedLength`](https://rux-lang.dev/docs/api/encoding/hex#hex-decoded-length) | How many bytes the hexadecimal text decodes to, after checking that its length is even. | | [`HexDecode`](https://rux-lang.dev/docs/api/encoding/hex#hex-decode) | Reads hexadecimal digits of either case from `text` into `into`, one byte per pair. | | [`ViewHex`](https://rux-lang.dev/docs/api/encoding/hex#view-hex) | Borrows `bytes` for rendering as hexadecimal. | | [`PercentEncodedLength`](https://rux-lang.dev/docs/api/encoding/percent#percent-encoded-length) | How many characters the percent-encoded form of `bytes` occupies in `set`. | | [`PercentEncode`](https://rux-lang.dev/docs/api/encoding/percent#percent-encode) | Writes the bytes of `text` percent-encoded for `set` into `into`. | | [`PercentDecodedLength`](https://rux-lang.dev/docs/api/encoding/percent#percent-decoded-length) | How many bytes percent-encoded text decodes to, after checking that every escape is well formed. | | [`PercentDecode`](https://rux-lang.dev/docs/api/encoding/percent#percent-decode) | Reads percent-encoded text into `into`, turning each escape back into its byte. | # DecodeError Why text could not be decoded. ```rux pub variant DecodeError { InvalidCharacter(uint), InvalidLength(uint), InvalidPadding(uint), NonCanonical(uint), InvalidEscape(uint), InsufficientCapacity(uint) } ``` Failure-only: success is the other channel of `uint ! DecodeError`, so no case means that nothing went wrong. Copy, carrying one count and owning nothing. A decoder that reports any case except `InsufficientCapacity` has left its destination exactly as it was; see each decoder for what a capacity refusal leaves. ## Cases | Name | Description | | ---------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `InvalidCharacter(uint)` | A character that is not in the scheme's alphabet. The offset is that character. | | `InvalidLength(uint)` | The text has a length no encoder of this scheme produces, such as an odd number of hexadecimal digits. The offset is the text's length, where the missing character would have gone. | | `InvalidPadding(uint)` | A padding character where padding is not allowed: in the middle of the text, too much of it, or any of it in a scheme without padding. The offset is the first padding character that is out of place. | | `NonCanonical(uint)` | The last character carries bits the encoder would have left zero, so two different texts would decode to the same bytes. The offset is that character. Refusing it keeps decoding one-to-one, which is what makes an encoded value safe to compare as text. | | `InvalidEscape(uint)` | A percent sign that is not followed by two hexadecimal digits. The offset is the percent sign. | | `InsufficientCapacity(uint)` | The destination is shorter than the decoded value. The count is the length it needed, in bytes. | ## Methods ### `Offset` ```rux pub func Offset(self: &DecodeError) -> uint? ``` Where in the text the failure was found, or none for a destination that was too short. Borrows the error and leaves it untouched. Cannot fail; runs in constant time and allocates nothing. **Returns**: the zero-based byte offset into the text, or none for `InsufficientCapacity` [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Encoding/Src/Error.rux#L40){rel=""nofollow""} ## Implements Display `DecodeError` conforms to `Display`. ### `WriteDisplay` ```rux pub func WriteDisplay( self: &DecodeError, writer: &var TextWriter, spec: FormatSpec ) -> ! FormatError ``` Writes a short lower-case description, followed by the offset or the length needed. The text is `invalid character at 5` for an input failure and `destination too short, need 12 bytes` for a capacity failure. No style is understood. Reports whatever the writer reported, and `UnsupportedRequest` for a style. | Name | Type | Description | | -------- | ----------------- | ------------------------------ | | `writer` | `&var TextWriter` | the destination | | `spec` | `FormatSpec` | what the placeholder asked for | **Returns**: success when the whole description was accepted [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Encoding/Src/Error.rux#L73){rel=""nofollow""} ## Implements Debug `DecodeError` conforms to `Debug`. ### `WriteDebug` ```rux pub func WriteDebug( self: &DecodeError, writer: &var TextWriter, spec: FormatSpec ) -> ! FormatError ``` The same text as `Display`: the description already names the case and its count. The failures [`WriteDisplay`](https://rux-lang.dev/docs/api/encoding/decode-error#write-display) reports. | Name | Type | Description | | -------- | ----------------- | ------------------------------ | | `writer` | `&var TextWriter` | the destination | | `spec` | `FormatSpec` | what the placeholder asked for | **Returns**: success when the whole description was accepted [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Encoding/Src/Error.rux#L117){rel=""nofollow""} # Streams Encoding and decoding through a writer or a reader, a block at a time. ## `StreamCodec` ```rux pub variant StreamCodec { Hex(HexCase), Base64(Base64Variant), Base32(Base32Variant) } ``` Which encoding a stream uses, with the form of it. `Copy`. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Encoding/Src/Stream.rux#L13){rel=""nofollow""} **Cases** | Name | Description | | ----------------------- | ---------------------------------------- | | `Hex(HexCase)` | Hexadecimal, two characters per byte. | | `Base64(Base64Variant)` | Base64, four characters per three bytes. | | `Base32(Base32Variant)` | Base32, eight characters per five bytes. | ## `EncodingWriter` ```rux pub struct EncodingWriter { // private fields } ``` A writer that encodes what is written to it onto another writer. Not copied. The text is complete only once [`Finish`](https://rux-lang.dev/docs/api/encoding/stream#encoding-writer-finish) has written the last group and its padding. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Encoding/Src/Stream.rux#L75){rel=""nofollow""} **Associated functions** ### `New` ```rux pub func New( sink: Writer, codec: StreamCodec ) -> EncodingWriter ``` A writer encoding with `codec` onto `sink`. | Name | Type | Description | | ------- | ------------- | ------------------------- | | `sink` | `Writer` | where the text goes | | `codec` | `StreamCodec` | the encoding and its form | **Returns**: the writer [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Encoding/Src/Stream.rux#L91){rel=""nofollow""} **Methods** ### `Finish` ```rux pub func Finish(self: &var EncodingWriter) -> ! IoError ``` Ends the text: encodes the bytes of an incomplete last group, with padding where the form uses it, and flushes the writer underneath. Nothing more may be written afterwards. **Returns**: nothing, or why the writer underneath failed [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Encoding/Src/Stream.rux#L106){rel=""nofollow""} **Implements Writer** `EncodingWriter` conforms to `Writer`. ### `Write` ```rux pub func Write( self: &var EncodingWriter, bytes: char8[..] ) -> uint ! IoError ``` Encodes `bytes`, writing every complete group and holding back the rest of an incomplete one. | Name | Type | Description | | ------- | ----------- | ------------------- | | `bytes` | `char8[..]` | the bytes to encode | **Returns**: how many were taken, which is all of them, or fails with `InvalidInput` after [`Finish`](https://rux-lang.dev/docs/api/encoding/stream#encoding-writer-finish) [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Encoding/Src/Stream.rux#L124){rel=""nofollow""} ### `Flush` ```rux pub func Flush(self: &var EncodingWriter) -> ! IoError ``` Flushes the writer underneath. An incomplete group stays held back, since its characters depend on bytes not yet written; [`Finish`](https://rux-lang.dev/docs/api/encoding/stream#encoding-writer-finish) is what writes it. **Returns**: nothing, or why the writer underneath failed [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Encoding/Src/Stream.rux#L162){rel=""nofollow""} ## `DecodingReader` ```rux pub struct DecodingReader { // private fields } ``` A reader that decodes text from another reader into bytes. Not copied. The text is held to the same rules as the slice decoders, so text that would not decode whole fails with `InvalidInput` when the reader reaches it. Crockford Base32 skips its hyphens, as its specification asks. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Encoding/Src/Stream.rux#L171){rel=""nofollow""} **Associated functions** ### `New` ```rux pub func New( source: Reader, codec: StreamCodec ) -> DecodingReader ``` A reader decoding `codec` text from `source`. | Name | Type | Description | | -------- | ------------- | ------------------------- | | `source` | `Reader` | where the text comes from | | `codec` | `StreamCodec` | the encoding and its form | **Returns**: the reader [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Encoding/Src/Stream.rux#L190){rel=""nofollow""} **Implements Reader** `DecodingReader` conforms to `Reader`. ### `Read` ```rux pub func Read( self: &var DecodingReader, into: var char8[..] ) -> uint ! IoError ``` Decodes into `into` as many bytes as are ready, reading more text when none are. | Name | Type | Description | | ------ | --------------- | ------------------ | | `into` | `var char8[..]` | where the bytes go | **Returns**: how many were decoded, or fails with `EndOfStream` after the last, or with `InvalidInput` for text that is not in the form [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Encoding/Src/Stream.rux#L253){rel=""nofollow""} # Base32 Base32 in the RFC 4648 and Crockford alphabets. ## `Base32Variant` ```rux pub enum Base32Variant { Standard, StandardUnpadded, Crockford } ``` Which Base32 alphabet a text uses, and whether it is padded. Copy, carrying no payload. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Encoding/Src/Base32.rux#L19){rel=""nofollow""} **Cases** | Name | Description | | ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `Standard` | The RFC 4648 alphabet, `A` through `Z` then `2` through `7`, padded with `=` to a multiple of eight characters. | | `StandardUnpadded` | The RFC 4648 alphabet without padding, which is how one-time-password secrets are usually written. | | `Crockford` | Crockford's alphabet, `0` through `9` then the letters except `I`, `L`, `O` and `U`, without padding. Read leniently, as its specification asks: either case, `I` and `L` as `1`, `O` as `0`, and hyphens skipped. | ## `Base32EncodedLength` ```rux pub func Base32EncodedLength( length: uint, form: Base32Variant ) -> uint ``` How many characters the Base32 form of `length` bytes occupies in `form`. Eight characters for every five bytes, with a final partial group taking two, four, five or seven characters, or eight with padding. Cannot fail for any length a slice in memory can have; runs in constant time and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Encoding/Src/Base32.rux#L48){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | --------------- | --------------------------------------- | | `length` | `uint` | the number of bytes to encode | | `form` | `Base32Variant` | the alphabet and padding to encode with | **Returns**: the number of characters [`Base32Encode`](https://rux-lang.dev/docs/api/encoding/base32#base32-encode) writes ## `Base32Encode` ```rux pub func Base32Encode( bytes: byte[..], into: var char8[..], form: Base32Variant ) -> uint ! FormatError pub func Base32Encode( text: char8[..], into: var char8[..], form: Base32Variant ) -> uint ! FormatError ``` Writes `bytes` as Base32 into `into`. Letters are written in upper case in both alphabets. The RFC 4648 variants run in time that depends only on the length of `bytes`. Reports `InsufficientCapacity` when `into` is shorter than `Base32EncodedLength(bytes.length, form)`, leaving it exactly as it was; room past the encoded form is not touched. | Overload | Summary | | -------------------------------------------------------------------------------------------------------- | ------------------------------------------------- | | `pub func Base32Encode(bytes: byte[..], into: var char8[..], form: Base32Variant) -> uint ! FormatError` | Writes `bytes` as Base32 into `into`. | | `pub func Base32Encode(text: char8[..], into: var char8[..], form: Base32Variant) -> uint ! FormatError` | Writes the bytes of `text` as Base32 into `into`. | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Encoding/Src/Base32.rux#L122){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------- | --------------- | ------------------------------------------------------------------------------ | | `bytes` | `byte[..]` | the bytes to encode | | `into` | `var char8[..]` | the destination, at least `Base32EncodedLength(bytes.length, form)` characters | | `form` | `Base32Variant` | the alphabet and padding to encode with | | `text` | `char8[..]` | the text whose bytes to encode | **Returns**: the number of characters written ## `Base32DecodedLength` ```rux pub func Base32DecodedLength( text: char8[..], form: Base32Variant ) -> uint ! DecodeError ``` How many bytes the Base32 text decodes to, after checking its length and the placement of its padding. Only the shape is checked; the characters are checked by [`Base32Decode`](https://rux-lang.dev/docs/api/encoding/base32#base32-decode). The padded variant needs a multiple of eight characters; every variant needs the data characters to leave a final group of zero, two, four, five or seven. Hyphens in Crockford text are not counted. Reports `InvalidLength` at the end of the text, or `InvalidPadding` at the first `=` that is out of place. Runs in time linear in the length and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Encoding/Src/Base32.rux#L219){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------ | --------------- | ---------------------------------------------------- | | `text` | `char8[..]` | the Base32 text | | `form` | `Base32Variant` | the alphabet and padding the text is expected to use | **Returns**: the number of bytes [`Base32Decode`](https://rux-lang.dev/docs/api/encoding/base32#base32-decode) writes for it ## `Base32Decode` ```rux pub func Base32Decode( text: char8[..], into: var byte[..], form: Base32Variant ) -> uint ! DecodeError ``` Reads Base32 text in `form` into `into`. The RFC 4648 variants run in time that depends only on the length of `text` when the text is valid. Reports, in this order of precedence, `InvalidLength` or `InvalidPadding` for a text of the wrong shape, `InvalidCharacter` at the first character outside the alphabet, `NonCanonical` at a last character whose unused bits are not zero, and `InsufficientCapacity` with the length needed when `into` is too short. Every refusal leaves `into` untouched, because the whole text is checked before anything is written. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Encoding/Src/Base32.rux#L235){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------ | --------------- | ----------------------------------------------------------------- | | `text` | `char8[..]` | the Base32 text to decode | | `into` | `var byte[..]` | the destination, at least `Base32DecodedLength(text, form)` bytes | | `form` | `Base32Variant` | the alphabet and padding the text is expected to use | **Returns**: the number of bytes written # Base58 Base58 in the Bitcoin alphabet, which leaves out look-alike characters. ## `Base58EncodedMaxLength` ```rux pub func Base58EncodedMaxLength(length: uint) -> uint ``` The most characters the Base58 form of `length` bytes can occupy. Each byte needs at most log 256 / log 58, about 1.366, digits, so this is a bound rather than the exact length, which depends on the value. A destination of this length is always enough. Cannot fail for any length a slice in memory can have; runs in constant time and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Encoding/Src/Base58.rux#L51){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | ------ | ----------------------------- | | `length` | `uint` | the number of bytes to encode | **Returns**: an upper bound on the number of characters [`Base58Encode`](https://rux-lang.dev/docs/api/encoding/base58#base58-encode) writes ## `Base58Encode` ```rux pub func Base58Encode( bytes: byte[..], into: var char8[..] ) -> uint ! FormatError pub func Base58Encode( text: char8[..], into: var char8[..] ) -> uint ! FormatError ``` Writes `bytes` as Base58 into the front of `into`. Runs in time quadratic in the length of `bytes`, and not in constant time. Reports `InsufficientCapacity` when the encoded form does not fit `into`; `Base58EncodedMaxLength(bytes.length)` characters always fit. A refusal leaves `into` filled with zero bytes, because the conversion used it as scratch space. Room past the encoded form is not touched on success. | Overload | Summary | | ----------------------------------------------------------------------------------- | -------------------------------------------------------------- | | `pub func Base58Encode(bytes: byte[..], into: var char8[..]) -> uint ! FormatError` | Writes `bytes` as Base58 into the front of `into`. | | `pub func Base58Encode(text: char8[..], into: var char8[..]) -> uint ! FormatError` | Writes the bytes of `text` as Base58 into the front of `into`. | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Encoding/Src/Base58.rux#L64){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------- | --------------- | ------------------------------ | | `bytes` | `byte[..]` | the bytes to encode | | `into` | `var char8[..]` | the destination | | `text` | `char8[..]` | the text whose bytes to encode | **Returns**: the number of characters written ## `Base58Decode` ```rux pub func Base58Decode( text: char8[..], into: var byte[..] ) -> uint ! DecodeError ``` Reads Base58 text in the Bitcoin alphabet into the front of `into`. Each leading `1` becomes a zero byte. Runs in time quadratic in the length of `text`, and not in constant time. Reports `InvalidCharacter` at the first character outside the alphabet, leaving `into` untouched, and `InsufficientCapacity` when the decoded value does not fit `into`, leaving it filled with zero bytes because the conversion used it as scratch space. The count carried by that refusal is a lower bound on the length needed, not the exact length; `text.length` bytes are always enough. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Encoding/Src/Base58.rux#L141){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------ | -------------- | ------------------------- | | `text` | `char8[..]` | the Base58 text to decode | | `into` | `var byte[..]` | the destination | **Returns**: the number of bytes written # Base64 Base64 in its standard and URL-safe alphabets, with or without padding, and a view that prints it. ## `Base64Variant` ```rux pub enum Base64Variant { Standard, StandardUnpadded, Url, UrlUnpadded } ``` Which Base64 alphabet a text uses, and whether it is padded. Copy, carrying no payload. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Encoding/Src/Base64.rux#L17){rel=""nofollow""} **Cases** | Name | Description | | ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `Standard` | The standard alphabet ending in `+` and `/`, padded with `=` to a multiple of four characters. RFC 4648 section 4, and what MIME, PEM and most protocols mean by Base64. | | `StandardUnpadded` | The standard alphabet without padding. | | `Url` | The URL- and file-name-safe alphabet ending in `-` and `_`, padded. RFC 4648 section 5. | | `UrlUnpadded` | The URL-safe alphabet without padding, which is what JSON Web Tokens and most URL parameters use. | ## `Base64EncodedLength` ```rux pub func Base64EncodedLength( length: uint, form: Base64Variant ) -> uint ``` How many characters the Base64 form of `length` bytes occupies in `form`. Four characters for every three bytes, with a final partial group taking two or three characters, or four with padding. Cannot fail for any length a slice in memory can have; runs in constant time and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Encoding/Src/Base64.rux#L46){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | --------------- | --------------------------------------- | | `length` | `uint` | the number of bytes to encode | | `form` | `Base64Variant` | the alphabet and padding to encode with | **Returns**: the number of characters [`Base64Encode`](https://rux-lang.dev/docs/api/encoding/base64#base64-encode) writes ## `Base64Encode` ```rux pub func Base64Encode( bytes: byte[..], into: var char8[..], form: Base64Variant ) -> uint ! FormatError pub func Base64Encode( text: char8[..], into: var char8[..], form: Base64Variant ) -> uint ! FormatError ``` Writes `bytes` as Base64 into `into`. Runs in time that depends only on the length of `bytes`. Reports `InsufficientCapacity` when `into` is shorter than `Base64EncodedLength(bytes.length, form)`, leaving it exactly as it was; room past the encoded form is not touched. | Overload | Summary | | -------------------------------------------------------------------------------------------------------- | ------------------------------------------------- | | `pub func Base64Encode(bytes: byte[..], into: var char8[..], form: Base64Variant) -> uint ! FormatError` | Writes `bytes` as Base64 into `into`. | | `pub func Base64Encode(text: char8[..], into: var char8[..], form: Base64Variant) -> uint ! FormatError` | Writes the bytes of `text` as Base64 into `into`. | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Encoding/Src/Base64.rux#L63){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------- | --------------- | ------------------------------------------------------------------------------ | | `bytes` | `byte[..]` | the bytes to encode | | `into` | `var char8[..]` | the destination, at least `Base64EncodedLength(bytes.length, form)` characters | | `form` | `Base64Variant` | the alphabet and padding to encode with | | `text` | `char8[..]` | the text whose bytes to encode | **Returns**: the number of characters written ## `Base64DecodedLength` ```rux pub func Base64DecodedLength( text: char8[..], form: Base64Variant ) -> uint ! DecodeError ``` How many bytes the Base64 text decodes to, after checking its length and the placement of its padding. Only the shape is checked; the characters are checked by [`Base64Decode`](https://rux-lang.dev/docs/api/encoding/base64#base64-decode). A padded variant needs a multiple of four characters with at most two `=` at the end; an unpadded one any length except one more than a multiple of four, and no `=` at all. Reports `InvalidLength` at the end of the text, or `InvalidPadding` at the first `=` that is out of place. Runs in time linear in the length and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Encoding/Src/Base64.rux#L144){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------ | --------------- | ---------------------------------------------------- | | `text` | `char8[..]` | the Base64 text | | `form` | `Base64Variant` | the alphabet and padding the text is expected to use | **Returns**: the number of bytes [`Base64Decode`](https://rux-lang.dev/docs/api/encoding/base64#base64-decode) writes for it ## `Base64Decode` ```rux pub func Base64Decode( text: char8[..], into: var byte[..], form: Base64Variant ) -> uint ! DecodeError ``` Reads Base64 text in `form` into `into`. Runs in time that depends only on the length of `text` when the text is valid. Reports, in this order of precedence, `InvalidLength` or `InvalidPadding` for a text of the wrong shape, `InvalidCharacter` at the first character outside the variant's alphabet, `NonCanonical` at a last character whose unused bits are not zero, and `InsufficientCapacity` with the length needed when `into` is too short. Every refusal leaves `into` untouched, because the whole text is checked before anything is written. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Encoding/Src/Base64.rux#L171){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------ | --------------- | ----------------------------------------------------------------- | | `text` | `char8[..]` | the Base64 text to decode | | `into` | `var byte[..]` | the destination, at least `Base64DecodedLength(text, form)` bytes | | `form` | `Base64Variant` | the alphabet and padding the text is expected to use | **Returns**: the number of bytes written ## `Base64View` ```rux pub struct Base64View { // private fields } ``` A borrowed byte sequence that renders as Base64 under a format placeholder. Lets a caller write `Render("{}", ViewBase64(key))` instead of sizing a buffer first. The view borrows the bytes and must not outlive them. Copy, owning nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Encoding/Src/Base64.rux#L234){rel=""nofollow""} **Implements Display** `Base64View` conforms to `Display`. ### `WriteDisplay` ```rux pub func WriteDisplay( self: &Base64View, writer: &var TextWriter, spec: FormatSpec ) -> ! FormatError ``` Writes the bytes as Base64, padded to the placeholder's width. The text is produced in blocks, so rendering allocates nothing however long the bytes are. Reports whatever the writer reported, and `UnsupportedRequest` for a precision or a style. | Name | Type | Description | | -------- | ----------------- | ------------------------------ | | `writer` | `&var TextWriter` | the destination | | `spec` | `FormatSpec` | what the placeholder asked for | **Returns**: success when the whole rendering was accepted [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Encoding/Src/Base64.rux#L257){rel=""nofollow""} ## `ViewBase64` ```rux pub func ViewBase64( bytes: byte[..], form: Base64Variant ) -> Base64View ``` Borrows `bytes` for rendering as Base64. Cannot fail and allocates nothing; the view reads `bytes` each time it is rendered, so it must not outlive them. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Encoding/Src/Base64.rux#L245){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------- | --------------- | --------------------------------------- | | `bytes` | `byte[..]` | the bytes to render | | `form` | `Base64Variant` | the alphabet and padding to render with | **Returns**: a view that renders `bytes` as Base64 # Hexadecimal Bytes as hexadecimal digits in either case, and a view that prints them. ## `HexCase` ```rux pub enum HexCase { Lower, Upper } ``` Which case hexadecimal digits above nine are written in. Copy, carrying no payload. Decoding accepts both regardless. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Encoding/Src/Hex.rux#L15){rel=""nofollow""} **Cases** | Name | Description | | ------- | ------------------------------------------------------------------------------------ | | `Lower` | `a` through `f`, the form most text formats and every cryptographic test vector use. | | `Upper` | `A` through `F`, the form RFC 4648 prints its alphabet in. | ## `HexEncodedLength` ```rux pub func HexEncodedLength(length: uint) -> uint ``` How many characters the hexadecimal form of `length` bytes occupies: exactly twice as many. Cannot fail for any length a slice in memory can have. Runs in constant time and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Encoding/Src/Hex.rux#L27){rel=""nofollow""} **Parameters** | Name | Type | Description | | -------- | ------ | ----------------------------- | | `length` | `uint` | the number of bytes to encode | **Returns**: the number of characters [`HexEncode`](https://rux-lang.dev/docs/api/encoding/hex#hex-encode) writes ## `HexEncode` ```rux pub func HexEncode( bytes: byte[..], into: var char8[..], letterCase: HexCase ) -> uint ! FormatError pub func HexEncode( text: char8[..], into: var char8[..], letterCase: HexCase ) -> uint ! FormatError ``` Writes `bytes` as hexadecimal digits into `into`, two per byte, high nibble first. Runs in time that depends only on the length of `bytes`. Reports `InsufficientCapacity` when `into` is shorter than `HexEncodedLength(bytes.length)`, leaving it exactly as it was; room past the encoded form is not touched. | Overload | Summary | | ----------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------- | | `pub func HexEncode(bytes: byte[..], into: var char8[..], letterCase: HexCase) -> uint ! FormatError` | Writes `bytes` as hexadecimal digits into `into`, two per byte, high nibble first. | | `pub func HexEncode(text: char8[..], into: var char8[..], letterCase: HexCase) -> uint ! FormatError` | Writes the bytes of `text` as hexadecimal digits into `into`, two per byte. | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Encoding/Src/Hex.rux#L39){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------------ | --------------- | --------------------------------------------------------------------- | | `bytes` | `byte[..]` | the bytes to encode | | `into` | `var char8[..]` | the destination, at least `HexEncodedLength(bytes.length)` characters | | `letterCase` | `HexCase` | which case the digits above nine are written in | | `text` | `char8[..]` | the text whose bytes to encode | **Returns**: the number of characters written ## `HexDecodedLength` ```rux pub func HexDecodedLength(text: char8[..]) -> uint ! DecodeError ``` How many bytes the hexadecimal text decodes to, after checking that its length is even. Only the length is checked; the digits themselves are checked by [`HexDecode`](https://rux-lang.dev/docs/api/encoding/hex#hex-decode). Reports `InvalidLength` at the end of the text when it has an odd number of characters. Runs in constant time and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Encoding/Src/Hex.rux#L71){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------ | ----------- | -------------------- | | `text` | `char8[..]` | the hexadecimal text | **Returns**: the number of bytes [`HexDecode`](https://rux-lang.dev/docs/api/encoding/hex#hex-decode) writes for it ## `HexDecode` ```rux pub func HexDecode( text: char8[..], into: var byte[..] ) -> uint ! DecodeError ``` Reads hexadecimal digits of either case from `text` into `into`, one byte per pair. Runs in time that depends only on the length of `text` when the text is valid. Reports `InvalidLength` for an odd number of characters and `InvalidCharacter` at the first character that is not a hexadecimal digit, leaving `into` untouched in both cases, because the whole text is checked before anything is written. Reports `InsufficientCapacity` with the length needed when `into` is too short, also leaving it untouched. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Encoding/Src/Hex.rux#L85){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------ | -------------- | -------------------------------------------------------- | | `text` | `char8[..]` | the hexadecimal text to decode | | `into` | `var byte[..]` | the destination, at least `HexDecodedLength(text)` bytes | **Returns**: the number of bytes written ## `HexView` ```rux pub struct HexView { // private fields } ``` A borrowed byte sequence that renders as hexadecimal under a format placeholder. Lets a caller write `Render("{}", ViewHex(digest))` instead of sizing a buffer first. The view borrows the bytes and must not outlive them. Copy, owning nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Encoding/Src/Hex.rux#L124){rel=""nofollow""} **Implements Display** `HexView` conforms to `Display`. ### `WriteDisplay` ```rux pub func WriteDisplay( self: &HexView, writer: &var TextWriter, spec: FormatSpec ) -> ! FormatError ``` Writes the bytes as hexadecimal digits, padded to the placeholder's width. The style `x` selects lower case and `X` upper case; with neither, the view's own case is used. The digits are produced in blocks, so rendering allocates nothing however long the bytes are. Reports whatever the writer reported, and `UnsupportedRequest` for a precision or any other style. | Name | Type | Description | | -------- | ----------------- | ------------------------------ | | `writer` | `&var TextWriter` | the destination | | `spec` | `FormatSpec` | what the placeholder asked for | **Returns**: success when the whole rendering was accepted [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Encoding/Src/Hex.rux#L148){rel=""nofollow""} ## `ViewHex` ```rux pub func ViewHex( bytes: byte[..], letterCase: HexCase ) -> HexView ``` Borrows `bytes` for rendering as hexadecimal. Cannot fail and allocates nothing; the view reads `bytes` each time it is rendered, so it must not outlive them. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Encoding/Src/Hex.rux#L135){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------------ | ---------- | ---------------------------------------------------- | | `bytes` | `byte[..]` | the bytes to render | | `letterCase` | `HexCase` | the case used when the placeholder does not name one | **Returns**: a view that renders `bytes` as hexadecimal # Percent-encoding Percent-encoding bytes for URLs, with the set of characters left as they are. ## `PercentSet` ```rux pub enum PercentSet { Component, Path, Form } ``` Which characters percent-encoding leaves as they are. Copy, carrying no payload. Every set leaves the unreserved characters of RFC 3986 alone, apart from `Form`, which escapes `~` as HTML requires. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Encoding/Src/Percent.rux#L18){rel=""nofollow""} **Cases** | Name | Description | | ----------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `Component` | Only the unreserved characters: letters, digits, `-`, `.`, `_` and `~`. Right for a single query name or value, a single path segment, or any value placed between delimiters, since every delimiter is escaped. | | `Path` | The unreserved characters, the sub-delimiters `!$&'()*+,;=`, and `:`, `@` and `/`. Right for a whole path that is already split into segments the way it should be. | | `Form` | The `application/x-www-form-urlencoded` serialization: letters, digits, `*`, `-`, `.` and `_` stay, a space becomes `+`, and everything else is escaped. Decoding in this set reads `+` as a space. | ## `PercentEncodedLength` ```rux pub func PercentEncodedLength( bytes: byte[..], set: PercentSet ) -> uint pub func PercentEncodedLength( text: char8[..], set: PercentSet ) -> uint ``` How many characters the percent-encoded form of `bytes` occupies in `set`. Exact rather than a bound: one character for each byte the set leaves alone, or for a space in the form set, and three for every other byte. Runs in time linear in the length and allocates nothing. | Overload | Summary | | ------------------------------------------------------------------------- | -------------------------------------------------------------------------------------- | | `pub func PercentEncodedLength(bytes: byte[..], set: PercentSet) -> uint` | How many characters the percent-encoded form of `bytes` occupies in `set`. | | `pub func PercentEncodedLength(text: char8[..], set: PercentSet) -> uint` | How many characters the percent-encoded form of the bytes of `text` occupies in `set`. | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Encoding/Src/Percent.rux#L54){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------- | ------------ | --------------------------------- | | `bytes` | `byte[..]` | the bytes to encode | | `set` | `PercentSet` | which characters stay as they are | | `text` | `char8[..]` | the text whose bytes to encode | **Returns**: the number of characters [`PercentEncode`](https://rux-lang.dev/docs/api/encoding/percent#percent-encode) writes ## `PercentEncode` ```rux pub func PercentEncode( bytes: byte[..], into: var char8[..], set: PercentSet ) -> uint ! FormatError pub func PercentEncode( text: char8[..], into: var char8[..], set: PercentSet ) -> uint ! FormatError ``` Writes the bytes of `text` percent-encoded for `set` into `into`. The byte form, reached without the caller reinterpreting the text first: each UTF-8 code unit is one byte, so a character outside ASCII becomes one escape per byte of its UTF-8 form, as URIs require. The failure the byte form reports, with the same guarantee. | Overload | Summary | | ----------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------- | | `pub func PercentEncode(bytes: byte[..], into: var char8[..], set: PercentSet) -> uint ! FormatError` | Writes `bytes` percent-encoded for `set` into `into`. | | `pub func PercentEncode(text: char8[..], into: var char8[..], set: PercentSet) -> uint ! FormatError` | Writes the bytes of `text` percent-encoded for `set` into `into`. | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Encoding/Src/Percent.rux#L89){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------- | --------------- | ----------------------------------------------------------------------- | | `bytes` | `byte[..]` | the bytes to encode | | `into` | `var char8[..]` | the destination, at least `PercentEncodedLength(bytes, set)` characters | | `set` | `PercentSet` | which characters stay as they are | | `text` | `char8[..]` | the text whose bytes to encode | **Returns**: the number of characters written ## `PercentDecodedLength` ```rux pub func PercentDecodedLength(text: char8[..]) -> uint ! DecodeError ``` How many bytes percent-encoded text decodes to, after checking that every escape is well formed. Each `%` followed by two hexadecimal digits of either case counts as one byte, and every other character as one. Reports `InvalidEscape` at the first `%` that is not followed by two hexadecimal digits. Runs in time linear in the length and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Encoding/Src/Percent.rux#L137){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------ | ----------- | ------------------------ | | `text` | `char8[..]` | the percent-encoded text | **Returns**: the number of bytes [`PercentDecode`](https://rux-lang.dev/docs/api/encoding/percent#percent-decode) writes for it ## `PercentDecode` ```rux pub func PercentDecode( text: char8[..], into: var byte[..], set: PercentSet ) -> uint ! DecodeError ``` Reads percent-encoded text into `into`, turning each escape back into its byte. Characters outside an escape are copied as they are, except that `+` becomes a space when `set` is `Form`; the other sets give `+` no special meaning. Reports `InvalidEscape` at the first `%` that is not followed by two hexadecimal digits, and `InsufficientCapacity` with the length needed when `into` is too short; both leave `into` untouched, because the whole text is checked before anything is written. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Encoding/Src/Percent.rux#L166){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------ | -------------- | --------------------------------------------------------------- | | `text` | `char8[..]` | the percent-encoded text to decode | | `into` | `var byte[..]` | the destination, at least `PercentDecodedLength(text)` bytes | | `set` | `PercentSet` | the set the text was encoded for, which decides how `+` is read | **Returns**: the number of bytes written # Url URLs: parsing, normalizing and resolving them, and reading and building their queries. ## Installation Add `Url` to the `[Dependencies]` table of your package's `Rux.toml`: ```toml [Dependencies] Url = { Namespace = "Rux", Version = "0.1.0" } ``` Standard packages are declared by hand: the registry does not serve them, so `rux add Rux/Url` cannot add them. ## Dependencies - [`Allocator`](https://rux-lang.dev/docs/api/allocator) 0.1.0 - [`Core`](https://rux-lang.dev/docs/api/core) 0.1.0 - [`Memory`](https://rux-lang.dev/docs/api/memory) 0.1.0 - [`Text`](https://rux-lang.dev/docs/api/text) 0.1.0 ## Guide ### What it provides | Module | Covers | | ------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | [`Url`](https://rux-lang.dev/docs/api/url/url#url) | [`Url`](https://rux-lang.dev/docs/api/url/url#url) with [`Parse`](https://rux-lang.dev/docs/api/url/url#parse), [`Resolve`](https://rux-lang.dev/docs/api/url/url#resolve), component accessors, [`SetPath`](https://rux-lang.dev/docs/api/url/url#set-path), [`SetQuery`](https://rux-lang.dev/docs/api/url/url#set-query) and [`SetFragment`](https://rux-lang.dev/docs/api/url/url#set-fragment), and `HostKind` | | [`Query`](https://rux-lang.dev/docs/api/url/url#query) | [`Pairs`](https://rux-lang.dev/docs/api/url/query#pairs) for walking a query's [`QueryPair`](https://rux-lang.dev/docs/api/url/query#query-pair)s, [`Decode`](https://rux-lang.dev/docs/api/url/query#decode) for turning a component into text, and [`QueryBuilder`](https://rux-lang.dev/docs/api/url/query#query-builder) | | `Error` | [`UrlError`](https://rux-lang.dev/docs/api/url/error#url-error), why text is not a URL | The module names describe where each declaration comes from; they are not part of an import path. ### Example ```rux import Allocator::SystemAllocator; import Url::{ Pairs, Url, UrlError }; func SearchTerm(link: char8[..]) -> bool ! UrlError { let page = Url::Parse(SystemAllocator(), "https://example.com/docs/index.html")?; let target = page.Resolve(link)?; for pair in Pairs(target.Query() ?? "") { if pair.name.length == 1 && pair.name[0] == 'q' { return true; } } return false; } ``` ### Design A URL is read by RFC 3986 and kept as one normalized ASCII text with the place of each component in it, so every accessor is a view and two URLs the RFC calls equivalent under syntax-based normalization are equal as text. Normalizing lower-cases the scheme and a registered host name, writes percent-encoding with upper-case hexadecimal and decodes the escapes of unreserved characters, removes dot segments from the path, leaves out a scheme's default port, and gives an `http`-like URL with an empty path the path `/`. An IPv4 host keeps its dotted form and an IPv6 host is written in the canonical form of RFC 5952. A character a component cannot hold as itself, such as a space or a non-ASCII byte, is percent-encoded rather than refused, as browsers do; a host is the exception, and refuses one, since escaping it would name a different machine. Internationalized host names are not converted to their ASCII form, so a non-ASCII host is refused. [`Resolve`](https://rux-lang.dev/docs/api/url/url#resolve) follows section 5 of RFC 3986, and gives the results of its examples, except that a resolved `http` URL with an empty path is written with `/`. Components stay percent-encoded; [`Decode`](https://rux-lang.dev/docs/api/url/query#decode) turns one into text, reading `+` as a space when asked to, as a query is read. [`QueryBuilder`](https://rux-lang.dev/docs/api/url/query#query-builder) writes pairs with the encoding HTML forms use, ready for [`SetQuery`](https://rux-lang.dev/docs/api/url/url#set-query). ## Index ### Types | Name | Summary | | --------------------------------------------------------------------------- | ---------------------------------------------------------------------------- | | [`UrlError`](https://rux-lang.dev/docs/api/url/error#url-error) | Why text could not be read or resolved as a URL. | | [`QueryPair`](https://rux-lang.dev/docs/api/url/query#query-pair) | One `name=value` pair of a query, both still percent-encoded. | | [`QueryPairs`](https://rux-lang.dev/docs/api/url/query#query-pairs) | A walk over a query's pairs, in order, skipping empty ones. | | [`QueryBuilder`](https://rux-lang.dev/docs/api/url/query#query-builder) | Builds a query from `name=value` pairs, encoding each the way HTML forms do. | | [`HostKind`](https://rux-lang.dev/docs/api/url/url#host-kind) | What a URL's host is. | | [`Url`](https://rux-lang.dev/docs/api/url/url#url) | An absolute URL in normalized form. | | [`SegmentIterator`](https://rux-lang.dev/docs/api/url/url#segment-iterator) | A walk over a path's segments, between its `/`s. | ### Functions | Name | Summary | | ---------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------- | | [`Pairs`](https://rux-lang.dev/docs/api/url/query#pairs) | The pairs of `query`, a query without its `?`, such as the one [`Url::Query`](https://rux-lang.dev/docs/api/url/url#query) returns. | | [`Decode`](https://rux-lang.dev/docs/api/url/query#decode) | Decodes a percent-encoded component into text. | # Errors Why a URL could not be parsed. ## `UrlError` ```rux pub enum UrlError: uint8 { MissingScheme = 1, InvalidScheme = 2, InvalidHost = 3, InvalidPort = 4, InvalidPercentEncoding = 5, OutOfMemory = 6, InvalidText = 7 } ``` Why text could not be read or resolved as a URL. `Copy`. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Url/Src/Error.rux#L5){rel=""nofollow""} **Cases** | Name | Value | Description | | ------------------------ | ----- | --------------------------------------------------------------------------------------------------------- | | `MissingScheme` | `1` | The text has no scheme, so it is a relative reference that needs a base to resolve against. | | `InvalidScheme` | `2` | The scheme does not start with a letter or holds a character a scheme cannot. | | `InvalidHost` | `3` | The host is empty where one is required, holds a character a host cannot, or is a malformed IPv6 address. | | `InvalidPort` | `4` | The port is not a number from 0 to 65535. | | `InvalidPercentEncoding` | `5` | A `%` is not followed by two hexadecimal digits. | | `OutOfMemory` | `6` | The allocator could not supply the storage. | | `InvalidText` | `7` | Decoded bytes are not UTF-8 text. | # Query strings Reading and building the name-value pairs of a query. ## `QueryPair` ```rux pub struct QueryPair { pub name: char8[..]; pub value: char8[..]; } ``` One `name=value` pair of a query, both still percent-encoded. `Copy`. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Url/Src/Query.rux#L12){rel=""nofollow""} **Fields** | Name | Type | Description | | ------- | ----------- | -------------------------------------------------------------- | | `name` | `char8[..]` | The name, before the first `=`. | | `value` | `char8[..]` | The value, after the first `=`, or empty when there is no `=`. | ## `QueryPairs` ```rux pub struct QueryPairs { // private fields } ``` A walk over a query's pairs, in order, skipping empty ones. `Copy`. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Url/Src/Query.rux#L21){rel=""nofollow""} **Methods** ### `Iterate` ```rux pub func Iterate(self: &QueryPairs) -> QueryPairs ``` The walk itself, so that `for pair in Pairs(query)` reads every pair. **Returns**: a copy of this walk [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Url/Src/Query.rux#L37){rel=""nofollow""} **Implements Iterator** `QueryPairs` conforms to `Iterator`. ### `Next` ```rux pub func Next(self: &var QueryPairs) -> QueryPair? ``` The next pair, or none after the last. **Returns**: the pair [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Url/Src/Query.rux#L46){rel=""nofollow""} ## `Pairs` ```rux pub func Pairs(query: char8[..]) -> QueryPairs ``` The pairs of `query`, a query without its `?`, such as the one [`Url::Query`](https://rux-lang.dev/docs/api/url/url#query) returns. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Url/Src/Query.rux#L29){rel=""nofollow""} **Parameters** | Name | Type | Description | | ------- | ----------- | ----------- | | `query` | `char8[..]` | the query | **Returns**: a walk over its pairs ## `Decode` ```rux pub func Decode( allocator: Allocator, encoded: char8[..], form: bool ) -> String ! UrlError ``` Decodes a percent-encoded component into text. With `form`, a `+` is read as a space, as in a query. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Url/Src/Query.rux#L68){rel=""nofollow""} **Parameters** | Name | Type | Description | | ----------- | ----------- | ------------------------------------------------------ | | `allocator` | `Allocator` | what the text is kept in | | `encoded` | `char8[..]` | the component, such as a path segment or a query value | | `form` | `bool` | whether `+` stands for a space | **Returns**: the text, or fails when an escape is malformed or the bytes are not UTF-8 ## `QueryBuilder` ```rux pub struct QueryBuilder { // private fields } ``` Builds a query from `name=value` pairs, encoding each the way HTML forms do. Not copied. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Url/Src/Query.rux#L90){rel=""nofollow""} **Constructors** ### `QueryBuilder` ```rux pub func QueryBuilder(allocator: Allocator) -> QueryBuilder ``` An empty query. | Name | Type | Description | | ----------- | ----------- | ------------------------- | | `allocator` | `Allocator` | what the query is kept in | **Returns**: the builder [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Url/Src/Query.rux#L99){rel=""nofollow""} **Methods** ### `Append` ```rux pub func Append( self: &var QueryBuilder, name: char8[..], value: char8[..] ) -> ! UrlError ``` Appends a pair, encoding the name and the value: letters, digits, `*`, `-`, `.` and `_` stay, a space becomes `+`, and every other byte is percent-encoded. | Name | Type | Description | | ------- | ----------- | ------------------ | | `name` | `char8[..]` | the name, as text | | `value` | `char8[..]` | the value, as text | **Returns**: nothing, or fails when the allocator refused [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Url/Src/Query.rux#L109){rel=""nofollow""} ### `Text` ```rux pub func Text(self: &QueryBuilder) -> char8[..] ``` The query built so far, without a `?`, ready for [`Url::SetQuery`](https://rux-lang.dev/docs/api/url/url#set-query). **Returns**: the query [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Url/Src/Query.rux#L119){rel=""nofollow""} # URLs Parsing a URL into its parts and reading them back. ## `HostKind` ```rux pub enum HostKind: uint8 { None = 0, Domain = 1, Ipv4 = 2, Ipv6 = 3 } ``` What a URL's host is. `Copy`. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Url/Src/Url.rux#L17){rel=""nofollow""} **Cases** | Name | Value | Description | | -------- | ----- | ----------------------------------------------------------- | | `None` | `0` | The URL has no authority, so no host. | | `Domain` | `1` | A registered name, such as `example.com`, or an empty host. | | `Ipv4` | `2` | A dotted-decimal IPv4 address. | | `Ipv6` | `3` | An IPv6 address, written between brackets in the URL. | ## `Url` ```rux pub struct Url { // private fields } ``` An absolute URL in normalized form. Read it with [`Parse`](https://rux-lang.dev/docs/api/url/url#parse) and resolve references against it with [`Resolve`](https://rux-lang.dev/docs/api/url/url#resolve). Every component is a view of the URL's own text, still percent-encoded; [`Decode`](https://rux-lang.dev/docs/api/url/query#decode) turns one into text. Copying a URL copies its text. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Url/Src/Url.rux#L32){rel=""nofollow""} **Associated functions** ### `Parse` ```rux pub func Parse( allocator: Allocator, text: char8[..] ) -> Url ! UrlError ``` Reads `text` as an absolute URL and puts it in normalized form. Spaces and control characters around the text are ignored. A character a component cannot hold as itself, such as a space or a non-ASCII byte, is percent-encoded; a host is not, and refuses one. | Name | Type | Description | | ----------- | ----------- | ------------------------------ | | `allocator` | `Allocator` | what the URL's text is kept in | | `text` | `char8[..]` | the URL | **Returns**: the URL, or fails with what is wrong with it; a relative reference fails with `MissingScheme` [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Url/Src/Url.rux#L218){rel=""nofollow""} **Methods** ### `Resolve` ```rux pub func Resolve( self: &Url, reference: char8[..] ) -> Url ! UrlError ``` Resolves `reference` against this URL, as a browser resolves a link on a page, following section 5 of RFC 3986. An absolute reference stands on its own; `//host/path`, `/path`, `path`, `?query` and `#fragment` replace what they name and keep the rest of this URL. | Name | Type | Description | | ----------- | ----------- | --------------------------------------- | | `reference` | `char8[..]` | an absolute URL or a relative reference | **Returns**: the resolved URL, kept with this URL's allocator [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Url/Src/Url.rux#L229){rel=""nofollow""} ### `Text` ```rux pub func Text(self: &Url) -> char8[..] ``` The whole URL, in normalized form. **Returns**: the text [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Url/Src/Url.rux#L260){rel=""nofollow""} ### `Scheme` ```rux pub func Scheme(self: &Url) -> char8[..] ``` The scheme, in lower case, without its `:`. **Returns**: the scheme [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Url/Src/Url.rux#L267){rel=""nofollow""} ### `HasAuthority` ```rux pub func HasAuthority(self: &Url) -> bool ``` Whether the URL has an authority: a `//` with a host, as `http:` URLs do and `mailto:` URLs do not. **Returns**: true when it has one [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Url/Src/Url.rux#L274){rel=""nofollow""} ### `Username` ```rux pub func Username(self: &Url) -> char8[..] ``` The user name before `@`, percent-encoded, or the empty text when there is none. **Returns**: the user name [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Url/Src/Url.rux#L281){rel=""nofollow""} ### `Password` ```rux pub func Password(self: &Url) -> char8[..]? ``` The password after the user name's `:`, percent-encoded, or none when there is none. **Returns**: the password [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Url/Src/Url.rux#L289){rel=""nofollow""} ### `Host` ```rux pub func Host(self: &Url) -> char8[..]? ``` The host: a lower-case name, a dotted IPv4 address, or an IPv6 address without its brackets. None when the URL has no authority. **Returns**: the host [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Url/Src/Url.rux#L298){rel=""nofollow""} ### `HostKind` ```rux pub func HostKind(self: &Url) -> HostKind ``` What kind of host the URL has. **Returns**: the kind [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Url/Src/Url.rux#L306){rel=""nofollow""} ### `Port` ```rux pub func Port(self: &Url) -> uint16? ``` The port written in the URL, or none when there is none or it is the scheme's default, which normalizing leaves out. **Returns**: the port [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Url/Src/Url.rux#L314){rel=""nofollow""} ### `PortOrDefault` ```rux pub func PortOrDefault(self: &Url) -> uint16? ``` The port a connection uses: the one written, or the scheme's default, or none for a scheme without one. **Returns**: the port [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Url/Src/Url.rux#L322){rel=""nofollow""} ### `Path` ```rux pub func Path(self: &Url) -> char8[..] ``` The path, percent-encoded, without dot segments. A URL with an `http`-like scheme always has at least `/`. **Returns**: the path [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Url/Src/Url.rux#L330){rel=""nofollow""} ### `PathSegments` ```rux pub func PathSegments(self: &Url) -> SegmentIterator ``` The path's segments, between its `/`s. **Returns**: a walk over the segments [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Url/Src/Url.rux#L337){rel=""nofollow""} ### `Query` ```rux pub func Query(self: &Url) -> char8[..]? ``` The query after `?`, percent-encoded, or none when there is no `?`. **Returns**: the query [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Url/Src/Url.rux#L346){rel=""nofollow""} ### `Fragment` ```rux pub func Fragment(self: &Url) -> char8[..]? ``` The fragment after `#`, percent-encoded, or none when there is no `#`. **Returns**: the fragment [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Url/Src/Url.rux#L354){rel=""nofollow""} ### `SetPath` ```rux pub func SetPath( self: &var Url, path: char8[..] ) -> ! UrlError ``` Replaces the path. A relative path is made absolute when the URL has an authority. | Name | Type | Description | | ------ | ----------- | ------------------------------------ | | `path` | `char8[..]` | the new path, percent-encoded or not | **Returns**: nothing, or fails when the path cannot be normalized [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Url/Src/Url.rux#L363){rel=""nofollow""} ### `SetQuery` ```rux pub func SetQuery( self: &var Url, query: char8[..]? ) -> ! UrlError ``` Replaces the query, or removes it with none. | Name | Type | Description | | ------- | ------------ | ----------------------------------------------------- | | `query` | `char8[..]?` | the new query without its `?`, percent-encoded or not | **Returns**: nothing, or fails when the query cannot be normalized [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Url/Src/Url.rux#L376){rel=""nofollow""} ### `SetFragment` ```rux pub func SetFragment( self: &var Url, fragment: char8[..]? ) -> ! UrlError ``` Replaces the fragment, or removes it with none. | Name | Type | Description | | ---------- | ------------ | -------------------------------------------------------- | | `fragment` | `char8[..]?` | the new fragment without its `#`, percent-encoded or not | **Returns**: nothing, or fails when the fragment cannot be normalized [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Url/Src/Url.rux#L386){rel=""nofollow""} ### `Equals` ```rux pub func Equals(self: &Url, other: &Url) -> bool ``` Whether two URLs are the same, which after normalization means the same text. | Name | Type | Description | | ------- | ------ | ----------------------- | | `other` | `&Url` | the URL to compare with | **Returns**: true when they are equal [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Url/Src/Url.rux#L396){rel=""nofollow""} ## `SegmentIterator` ```rux pub struct SegmentIterator { // private fields } ``` A walk over a path's segments, between its `/`s. `Copy`. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Url/Src/Url.rux#L424){rel=""nofollow""} **Methods** ### `Iterate` ```rux pub func Iterate(self: &SegmentIterator) -> SegmentIterator ``` The walk itself, so that `for segment in url.PathSegments()` reads every segment. **Returns**: a copy of this walk [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Url/Src/Url.rux#L433){rel=""nofollow""} **Implements Iterator** `SegmentIterator` conforms to `Iterator`. ### `Next` ```rux pub func Next(self: &var SegmentIterator) -> char8[..]? ``` The next segment, still percent-encoded, or none after the last. **Returns**: the segment [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Url/Src/Url.rux#L442){rel=""nofollow""} # Compress Deflate compression in the raw, zlib and gzip formats, as streams and for whole buffers. ## Installation Add `Compress` to the `[Dependencies]` table of your package's `Rux.toml`: ```toml [Dependencies] Compress = { Namespace = "Rux", Version = "0.1.0" } ``` Standard packages are declared by hand: the registry does not serve them, so `rux add Rux/Compress` cannot add them. ## Dependencies - [`Allocator`](https://rux-lang.dev/docs/api/allocator) 0.1.0 - [`Collections`](https://rux-lang.dev/docs/api/collections) 0.1.0 - [`Core`](https://rux-lang.dev/docs/api/core) 0.1.0 - [`Hash`](https://rux-lang.dev/docs/api/hash) 0.1.0 - [`Io`](https://rux-lang.dev/docs/api/io) 0.1.0 - [`Memory`](https://rux-lang.dev/docs/api/memory) 0.1.0 ## Guide ### What it provides | Module | Covers | | ---------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `Inflate` | [`DecompressReader`](https://rux-lang.dev/docs/api/compress/inflate#decompress-reader), an `Io::Reader` that decompresses another reader | | `Deflate` | [`CompressWriter`](https://rux-lang.dev/docs/api/compress/deflate#compress-writer), an `Io::Writer` that compresses into another writer, with [`Flush`](https://rux-lang.dev/docs/api/compress/deflate#flush) and [`Finish`](https://rux-lang.dev/docs/api/compress/deflate#finish) | | `Buffers` | [`Compress`](https://rux-lang.dev/docs/api/compress/buffers#compress) and [`Decompress`](https://rux-lang.dev/docs/api/compress/buffers#decompress) for data already in memory, as bytes or as the `char8` text the Io streams carry | | [`Format`](https://rux-lang.dev/docs/api/compress/format#format) | [`Format`](https://rux-lang.dev/docs/api/compress/format#format) (`Raw`, `Zlib`, `Gzip`) and [`Level`](https://rux-lang.dev/docs/api/compress/format#level) (`Store`, `Fastest`, `Default`, `Best`) | The module names describe where each declaration comes from; they are not part of an import path. ### Example ```rux import Allocator::SystemAllocator; import Compress::{ Compress, Decompress, Format }; import Io::IoError; func RoundTrip(data: byte[..]) -> bool ! IoError { let packed = Compress(SystemAllocator(), data, Format::Gzip)?; let unpacked = Decompress(SystemAllocator(), packed.AsSlice(), Format::Gzip)?; return unpacked.Length() == data.length; } ``` ### Design A Deflate stream is RFC 1951; the zlib format of RFC 1950 adds a two-byte header and an Adler-32 of the data, and the gzip format of RFC 1952 a header and a CRC-32 and length. The checksums come from `Rux/Hash`. [`DecompressReader`](https://rux-lang.dev/docs/api/compress/inflate#decompress-reader) pulls compressed bytes from its source as it needs them and stops only when the caller's buffer is full, keeping the last 32 KiB it produced for the matches that reach back into them. It checks the container's header and trailer, reports the end of the data only after the checksum agreed, and reads a gzip file of several members as their data in order. Damaged or truncated input fails with `InvalidInput`, and so does every read after it. [`CompressWriter`](https://rux-lang.dev/docs/api/compress/deflate#compress-writer) gathers data until its buffer is full and encodes it as one block, keeping 32 KiB of history so matches reach into earlier blocks. Repeats are found through hash chains on three-byte prefixes, as zlib finds them; `Default` and `Best` follow longer chains and look one byte ahead before taking a match. Each block is written whichever way is smallest: stored, with the fixed codes, or with codes built from that block's frequencies, limited to fifteen bits the way zlib limits them. `Best` compresses about as well as zlib's default level. Nothing is complete until [`Finish`](https://rux-lang.dev/docs/api/compress/deflate#finish) writes the final block and the trailer; [`Flush`](https://rux-lang.dev/docs/api/compress/deflate#flush) makes everything so far readable without ending the stream, as zlib's sync flush does. ## Index ### Types | Name | Summary | | -------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------ | | [`CompressWriter`](https://rux-lang.dev/docs/api/compress/deflate#compress-writer) | A writer that compresses what is written to it into another writer, in any of the three formats. | | [`Format`](https://rux-lang.dev/docs/api/compress/format#format) | The container around a Deflate stream. | | [`Level`](https://rux-lang.dev/docs/api/compress/format#level) | How hard the compressor looks for repeated data. | | [`DecompressReader`](https://rux-lang.dev/docs/api/compress/inflate#decompress-reader) | A reader that decompresses what it reads from another, in any of the three formats. | ### Functions | Name | Summary | | ------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------- | | [`Compress`](https://rux-lang.dev/docs/api/compress/buffers#compress) | Compresses text in `format` at `level`: its UTF-8 bytes, as the Io streams carry them, so text needs no cast to bytes first. | | [`Decompress`](https://rux-lang.dev/docs/api/compress/buffers#decompress) | Decompresses `data`, a whole stream in `format` held as `char8` units, such as bytes read from an Io stream. | # Compressing A writer that compresses what is written through it. ## `CompressWriter` ```rux pub struct CompressWriter { // private fields } ``` A writer that compresses what is written to it into another writer, in any of the three formats. Call [`Finish`](https://rux-lang.dev/docs/api/compress/deflate#finish) when done: it writes the rest of the data and the container's trailer, and nothing written is complete before it. [`Flush`](https://rux-lang.dev/docs/api/compress/deflate#flush) writes everything so far in a form a decompressor can read up to, without ending the stream. Not copied. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Compress/Src/Deflate.rux#L31){rel=""nofollow""} **Associated functions** ### `New` ```rux pub func New( allocator: Allocator, sink: Writer, format: Format, level: Level ) -> CompressWriter ! IoError ``` A writer that compresses into `sink` in `format`, at `level`. | Name | Type | Description | | ----------- | ----------- | -------------------------------------------------------- | | `allocator` | `Allocator` | what the writer's buffers are kept in, about 750 KiB | | `sink` | `Writer` | where the compressed stream goes, which the writer takes | | `format` | `Format` | the container to write | | `level` | `Level` | how hard to compress | **Returns**: the writer, or fails when the allocator refused [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Compress/Src/Deflate.rux#L77){rel=""nofollow""} **Methods** ### `Finish` ```rux pub func Finish(self: &var CompressWriter) -> ! IoError ``` Compresses everything written so far, writes the end of the stream and the container's trailer, and flushes the sink. Writing after finishing fails; finishing twice does nothing. **Returns**: nothing, or fails with the sink's error [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Compress/Src/Deflate.rux#L101){rel=""nofollow""} **Implements Writer** `CompressWriter` conforms to `Writer`. ### `Write` ```rux pub func Write( self: &var CompressWriter, bytes: char8[..] ) -> uint ! IoError ``` Takes `bytes` to compress. They are encoded as enough of them gather, and all of them by [`Flush`](https://rux-lang.dev/docs/api/compress/deflate#flush) or [`Finish`](https://rux-lang.dev/docs/api/compress/deflate#finish). | Name | Type | Description | | ------- | ----------- | ----------- | | `bytes` | `char8[..]` | the data | **Returns**: how many bytes were taken, which is all of them, or fails after [`Finish`](https://rux-lang.dev/docs/api/compress/deflate#finish) or with the sink's error [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Compress/Src/Deflate.rux#L508){rel=""nofollow""} ### `Flush` ```rux pub func Flush(self: &var CompressWriter) -> ! IoError ``` Encodes everything written so far and ends it with an empty stored block, so a decompressor can read all of it, then flushes the sink. The stream continues afterwards. **Returns**: nothing, or fails with the sink's error [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Compress/Src/Deflate.rux#L541){rel=""nofollow""} **Destructor** ### `~CompressWriter` ```rux func ~CompressWriter(self: &var CompressWriter) ``` [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Compress/Src/Deflate.rux#L494){rel=""nofollow""} # Formats and levels The raw, zlib and gzip formats, and the compression levels. ## `Format` ```rux pub enum Format: uint8 { Raw = 0, Zlib = 1, Gzip = 2 } ``` The container around a Deflate stream. `Copy`. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Compress/Src/Format.rux#L7){rel=""nofollow""} **Cases** | Name | Value | Description | | ------ | ----- | ------------------------------------------------------------------------------------------------------------ | | `Raw` | `0` | A bare Deflate stream, RFC 1951, with no header and no checksum. | | `Zlib` | `1` | The zlib format, RFC 1950: a two-byte header, the stream, and an Adler-32 of the data. | | `Gzip` | `2` | The gzip format, RFC 1952: a header that may name the file, the stream, a CRC-32 of the data and its length. | ## `Level` ```rux pub enum Level: uint8 { Store = 0, Fastest = 1, Default = 2, Best = 3 } ``` How hard the compressor looks for repeated data. `Copy`. Higher levels find longer and more matches and so write less, and take longer to. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Compress/Src/Format.rux#L19){rel=""nofollow""} **Cases** | Name | Value | Description | | --------- | ----- | ------------------------------------------------------------------------------------------ | | `Store` | `0` | No compression: the data is stored as it is, in blocks a decompressor copies straight out. | | `Fastest` | `1` | The quickest search: the first match found is taken. | | `Default` | `2` | A balance of speed and size, close to zlib's default. | | `Best` | `3` | The most thorough search this package does. | # Decompressing A reader that decompresses a stream as it is read. ## `DecompressReader` ```rux pub struct DecompressReader { // private fields } ``` A reader that decompresses what it reads from another, in any of the three formats. Reading it to the end fails with `EndOfStream` once the data and its checksum have been read; damaged or truncated input fails with `InvalidInput`, and so does every read after. A gzip stream of several members reads as their data one after another. Not copied. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Compress/Src/Inflate.rux#L30){rel=""nofollow""} **Associated functions** ### `New` ```rux pub func New( allocator: Allocator, source: Reader, format: Format ) -> DecompressReader ! IoError ``` A reader of the data `source` holds compressed in `format`. | Name | Type | Description | | ----------- | ----------- | ------------------------------------------------------ | | `allocator` | `Allocator` | what the reader's input buffer and history are kept in | | `source` | `Reader` | the compressed stream, which the reader takes | | `format` | `Format` | the container the stream is in | **Returns**: the reader, or fails when the allocator refused [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Compress/Src/Inflate.rux#L64){rel=""nofollow""} **Implements Reader** `DecompressReader` conforms to `Reader`. ### `Read` ```rux pub func Read( self: &var DecompressReader, into: var char8[..] ) -> uint ! IoError ``` Decompresses into `into` until it is full or the data ends. | Name | Type | Description | | ------ | --------------- | --------------------- | | `into` | `var char8[..]` | where to put the data | **Returns**: how many bytes were produced, or fails with `EndOfStream` after the last, or with `InvalidInput` for damaged or truncated input [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Compress/Src/Inflate.rux#L404){rel=""nofollow""} **Destructor** ### `~DecompressReader` ```rux func ~DecompressReader(self: &var DecompressReader) ``` [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Compress/Src/Inflate.rux#L385){rel=""nofollow""} # Whole buffers Compressing and decompressing a whole buffer in one call. ## `Compress` ```rux pub func Compress( allocator: Allocator, data: byte[..], format: Format, level: Level ) -> Vector<byte> ! IoError pub func Compress( allocator: Allocator, data: char8[..], format: Format, level: Level ) -> Vector<byte> ! IoError ``` Compresses text in `format` at `level`: its UTF-8 bytes, as the Io streams carry them, so text needs no cast to bytes first. | Overload | Summary | | ------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------- | | `pub func Compress(allocator: Allocator, data: byte[..], format: Format, level: Level) -> Vector<byte> ! IoError` | Compresses `data` in `format` at `level`. | | `pub func Compress(allocator: Allocator, data: char8[..], format: Format, level: Level) -> Vector<byte> ! IoError` | Compresses text in `format` at `level`: its UTF-8 bytes, as the Io streams carry them, so text needs no cast to bytes first. | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Compress/Src/Buffers.rux#L102){rel=""nofollow""} **Parameters** | Name | Type | Description | | ----------- | ------------------------ | -------------------------------------------------------- | | `allocator` | `Allocator` | what the result and the compressor's buffers are kept in | | `data` | `byte[..]` / `char8[..]` | the data | | `format` | `Format` | the container to write | | `level` | `Level` | how hard to compress | **Returns**: the compressed bytes, or fails when the allocator refused ## `Decompress` ```rux pub func Decompress( allocator: Allocator, data: byte[..], format: Format ) -> Vector<byte> ! IoError pub func Decompress( allocator: Allocator, data: char8[..], format: Format ) -> Vector<byte> ! IoError ``` Decompresses `data`, a whole stream in `format` held as `char8` units, such as bytes read from an Io stream. | Overload | Summary | | ------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------ | | `pub func Decompress(allocator: Allocator, data: byte[..], format: Format) -> Vector<byte> ! IoError` | Decompresses `data`, a whole stream in `format`. | | `pub func Decompress(allocator: Allocator, data: char8[..], format: Format) -> Vector<byte> ! IoError` | Decompresses `data`, a whole stream in `format` held as `char8` units, such as bytes read from an Io stream. | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/Compress/Src/Buffers.rux#L134){rel=""nofollow""} **Parameters** | Name | Type | Description | | ----------- | ------------------------ | ---------------------------------------------------------- | | `allocator` | `Allocator` | what the result and the decompressor's buffers are kept in | | `data` | `byte[..]` / `char8[..]` | the compressed stream | | `format` | `Format` | the container it is in | **Returns**: the data, or fails with `InvalidInput` for damaged or truncated input # NanoId Short, URL-safe, unpredictable identifiers in the Nano ID format. ## Installation Add `NanoId` to the `[Dependencies]` table of your package's `Rux.toml`: ```toml [Dependencies] NanoId = { Namespace = "Rux", Version = "0.1.0" } ``` Standard packages are declared by hand: the registry does not serve them, so `rux add Rux/NanoId` cannot add them. ## Dependencies - [`Core`](https://rux-lang.dev/docs/api/core) 0.1.0 - [`Entropy`](https://rux-lang.dev/docs/api/entropy) 0.1.0 - [`Memory`](https://rux-lang.dev/docs/api/memory) 0.1.0 - [`Text`](https://rux-lang.dev/docs/api/text) 0.1.0 ## Guide ### What it provides | Module | Covers | | ------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | [`NanoId`](https://rux-lang.dev/docs/api/nanoid/nano-id) | the [`NanoId`](https://rux-lang.dev/docs/api/nanoid/nano-id) value: [`Generate`](https://rux-lang.dev/docs/api/nanoid/nano-id#generate), [`Parse`](https://rux-lang.dev/docs/api/nanoid/nano-id#parse), [`Text`](https://rux-lang.dev/docs/api/nanoid/nano-id#text), [`Equals`](https://rux-lang.dev/docs/api/nanoid/nano-id#equals), [`Compare`](https://rux-lang.dev/docs/api/nanoid/nano-id#compare), `Display` and `Debug` | | [`Generate`](https://rux-lang.dev/docs/api/nanoid/nano-id#generate) | [`GenerateNanoId`](https://rux-lang.dev/docs/api/nanoid/generate#generate-nano-id) and [`GenerateNanoIdFrom`](https://rux-lang.dev/docs/api/nanoid/generate#generate-nano-id-from), which fill a buffer of any length from any alphabet | | `Alphabet` | [`NanoIdAlphabet`](https://rux-lang.dev/docs/api/nanoid/alphabet#nano-id-alphabet), [`NanoIdLength`](https://rux-lang.dev/docs/api/nanoid/alphabet#nano-id-length), [`NanoIdError`](https://rux-lang.dev/docs/api/nanoid/nano-id-error) and [`ValidateAlphabet`](https://rux-lang.dev/docs/api/nanoid/alphabet#validate-alphabet) | The module names describe where each declaration comes from; they are not part of an import path. ### Example ```rux import NanoId::{ GenerateNanoId, NanoId }; func NewSessionToken() -> bool { let id = NanoId::Generate() catch { else => return false }; var code: char8[8]; GenerateNanoId(code[..], "0123456789") catch { else => return false }; return id.Text().length == 21; } ``` ### Design A standard identifier is twenty-one characters from the sixty-four URL-safe characters `A`–`Z`, `a`–`z`, `0`–`9`, `_` and `-`, which is 126 random bits: more than a version 4 UUID carries, in fewer characters, and safe unescaped in a URL or a file name. [`NanoId`](https://rux-lang.dev/docs/api/nanoid/nano-id) holds one inline as a `Copy` value. [`GenerateNanoId`](https://rux-lang.dev/docs/api/nanoid/generate#generate-nano-id) fills a buffer of any length instead, from the default alphabet or a custom one. Every character of the alphabet is equally likely at every position. Each character is a random byte masked down to the smallest power of two that covers the alphabet, and a masked value past the end of the alphabet is thrown away rather than folded back with a remainder, which would favour the first characters. A custom alphabet must have between two and 256 distinct ASCII characters; [`ValidateAlphabet`](https://rux-lang.dev/docs/api/nanoid/alphabet#validate-alphabet) says which rule it broke, before any entropy is spent. Random bytes come from the operating system through `Rux/Entropy`. Generation fails rather than producing a predictable identifier when the system has none, and leaves the destination zeroized rather than holding the start of an identifier. [`GenerateNanoIdFrom`](https://rux-lang.dev/docs/api/nanoid/generate#generate-nano-id-from) takes any `EntropySource`, which is how a test gets reproducible identifiers. The default alphabet is listed in the reference implementation's order, so the same random bytes give the same identifier here as in other implementations. [`Equals`](https://rux-lang.dev/docs/api/nanoid/nano-id#equals) compares every byte whatever it finds, so comparing a guessed identifier with a real one takes the same time however much of the guess was right. ## Index ### Types | Name | Summary | | -------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- | | [`NanoIdError`](https://rux-lang.dev/docs/api/nanoid/nano-id-error) | Why an identifier could not be generated. | | [`NanoId`](https://rux-lang.dev/docs/api/nanoid/nano-id) | A Nano ID of the standard form: twenty-one characters from [`NanoIdAlphabet`](https://rux-lang.dev/docs/api/nanoid/alphabet#nano-id-alphabet). | | [`NanoIdParseError`](https://rux-lang.dev/docs/api/nanoid/nano-id#nano-id-parse-error) | Why text could not be read as a standard Nano ID. | ### Functions | Name | Summary | | ------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------- | | [`ValidateAlphabet`](https://rux-lang.dev/docs/api/nanoid/alphabet#validate-alphabet) | Checks that `alphabet` can be drawn from without bias. | | [`GenerateNanoId`](https://rux-lang.dev/docs/api/nanoid/generate#generate-nano-id) | Fills the whole of `into` with an identifier from the default alphabet, using the operating system's generator. | | [`GenerateNanoIdFrom`](https://rux-lang.dev/docs/api/nanoid/generate#generate-nano-id-from) | Fills the whole of `into` with an identifier drawn from `alphabet`, using random bytes from `source`. | ### Constants | Name | Summary | | ---------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------ | | [`NanoIdAlphabet`](https://rux-lang.dev/docs/api/nanoid/alphabet#nano-id-alphabet) | Nano ID's default alphabet: the sixty-four URL-safe characters `A`–`Z`, `a`–`z`, `0`–`9`, `_` and `-`. | | [`NanoIdLength`](https://rux-lang.dev/docs/api/nanoid/alphabet#nano-id-length) | The default identifier length, in characters: twenty-one. | # NanoId A Nano ID of the standard form: twenty-one characters from [`NanoIdAlphabet`](https://rux-lang.dev/docs/api/nanoid/alphabet#nano-id-alphabet). ```rux pub struct NanoId { // private fields } ``` Copy, holding its text inline and owning nothing. Equality and ordering compare the text byte by byte. ## Associated functions ### `Generate` ```rux pub func Generate() -> NanoId ! EntropyError ``` A new identifier from the operating system's generator. Costs twenty-one bytes of entropy and allocates nothing. Reports what the system reported when it could not supply random bytes, and produces no identifier in that case. **Returns**: the identifier, or why none could be made [Source](https://github.com/rux-lang/Rux/blob/main/Packages/NanoId/Src/NanoId.rux#L57){rel=""nofollow""} ### `Parse` ```rux pub func Parse(text: char8[..]) -> NanoId ! NanoIdParseError ``` Reads a standard identifier from its text. Reports `WrongLength` unless the text is exactly twenty-one bytes, and `InvalidCharacter` at the first byte outside the default alphabet. A refused parse produces no value. Runs in constant time for a text of the right length and allocates nothing. | Name | Type | Description | | ------ | ----------- | ---------------- | | `text` | `char8[..]` | the text to read | **Returns**: the identifier, or why the text is not one [Source](https://github.com/rux-lang/Rux/blob/main/Packages/NanoId/Src/NanoId.rux#L70){rel=""nofollow""} ## Methods ### `Text` ```rux pub func Text(self: &NanoId) -> char8[..] ``` The identifier's twenty-one characters. Borrows the value: the slice reads the value's own storage and must not outlive it. Cannot fail and allocates nothing. **Returns**: the text, always [`NanoIdLength`](https://rux-lang.dev/docs/api/nanoid/alphabet#nano-id-length) bytes of the default alphabet [Source](https://github.com/rux-lang/Rux/blob/main/Packages/NanoId/Src/NanoId.rux#L89){rel=""nofollow""} ### `Equals` ```rux pub func Equals(self: &NanoId, other: &NanoId) -> bool ``` Whether two identifiers are the same. Compares every byte whatever it finds, so the time taken does not reveal how much of a guessed identifier was right. Cannot fail and allocates nothing. | Name | Type | Description | | ------- | --------- | --------------------------------- | | `other` | `&NanoId` | the identifier to compare against | **Returns**: whether the two have the same text [Source](https://github.com/rux-lang/Rux/blob/main/Packages/NanoId/Src/NanoId.rux#L99){rel=""nofollow""} ### `Compare` ```rux pub func Compare(self: &NanoId, other: &NanoId) -> Ordering ``` The order of two identifiers' texts, byte by byte. Identifiers are random, so this order means nothing beyond being total and stable, which is what a sorted container needs. Cannot fail and allocates nothing. | Name | Type | Description | | ------- | --------- | --------------------------------- | | `other` | `&NanoId` | the identifier to compare against | **Returns**: how this identifier orders against `other` [Source](https://github.com/rux-lang/Rux/blob/main/Packages/NanoId/Src/NanoId.rux#L115){rel=""nofollow""} ## Implements Display `NanoId` conforms to `Display`. ### `WriteDisplay` ```rux pub func WriteDisplay( self: &NanoId, writer: &var TextWriter, spec: FormatSpec ) -> ! FormatError ``` Writes the identifier's twenty-one characters. No style is understood. Reports whatever the writer reported, and `UnsupportedRequest` for a style. | Name | Type | Description | | -------- | ----------------- | ------------------------------ | | `writer` | `&var TextWriter` | the destination | | `spec` | `FormatSpec` | what the placeholder asked for | **Returns**: success when the whole identifier was accepted [Source](https://github.com/rux-lang/Rux/blob/main/Packages/NanoId/Src/NanoId.rux#L133){rel=""nofollow""} ## Implements Debug `NanoId` conforms to `Debug`. ### `WriteDebug` ```rux pub func WriteDebug( self: &NanoId, writer: &var TextWriter, spec: FormatSpec ) -> ! FormatError ``` The same text as `Display`: an identifier has one reading. The failures [`WriteDisplay`](https://rux-lang.dev/docs/api/nanoid/nano-id#write-display) reports. | Name | Type | Description | | -------- | ----------------- | ------------------------------ | | `writer` | `&var TextWriter` | the destination | | `spec` | `FormatSpec` | what the placeholder asked for | **Returns**: success when the whole identifier was accepted [Source](https://github.com/rux-lang/Rux/blob/main/Packages/NanoId/Src/NanoId.rux#L147){rel=""nofollow""} ## Related ### `NanoIdParseError` ```rux pub variant NanoIdParseError { WrongLength(uint), InvalidCharacter(uint) } ``` Why text could not be read as a standard Nano ID. Failure-only, carrying the zero-based byte offset where the problem was found. Copy, owning nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/NanoId/Src/NanoId.rux#L23){rel=""nofollow""} **Cases** | Name | Description | | ------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------- | | `WrongLength(uint)` | The text is not twenty-one bytes long. The offset is the text's length when it is too short, and the first byte past the form when it is too long. | | `InvalidCharacter(uint)` | A character that is not in the default alphabet. The offset is that character. | **Implements ParseFailure** `NanoIdParseError` conforms to `ParseFailure`. #### `Offset` ```rux pub func Offset(self: &NanoIdParseError) -> uint ``` Where in the input the failure was found. Borrows the error and leaves it untouched. Cannot fail; runs in constant time and allocates nothing. **Returns**: the zero-based UTF-8 byte offset, which is the text's length at end of input [Source](https://github.com/rux-lang/Rux/blob/main/Packages/NanoId/Src/NanoId.rux#L36){rel=""nofollow""} # NanoIdError Why an identifier could not be generated. ```rux pub variant NanoIdError { AlphabetTooSmall, AlphabetTooLarge, DuplicateCharacter(uint), NonAsciiCharacter(uint), Entropy(EntropyError) } ``` Failure-only: a filled destination is the success channel of `! NanoIdError`. Copy, owning nothing. The alphabet cases are found before any random bytes are requested, so they never consume entropy. ## Cases | Name | Description | | -------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- | | `AlphabetTooSmall` | The alphabet has fewer than two characters, so an identifier from it carries no information. | | `AlphabetTooLarge` | The alphabet has more than 256 characters, more than one random byte can choose between. | | `DuplicateCharacter(uint)` | A character appears twice, which would make it twice as likely as the rest. The offset is the second occurrence. | | `NonAsciiCharacter(uint)` | A byte outside ASCII. The offset is that byte. Each character of an identifier is one byte, which a character that takes several bytes in UTF-8 cannot be. | | `Entropy(EntropyError)` | The operating system could not supply random bytes, for the reason carried. | # Generating Generating an identifier into a buffer of your own, from any alphabet and entropy source. ## `GenerateNanoId` ```rux pub func GenerateNanoId(into: var char8[..]) -> ! EntropyError pub func GenerateNanoId( into: var char8[..], alphabet: char8[..] ) -> ! NanoIdError ``` Fills the whole of `into` with an identifier from the default alphabet, using the operating system's generator. The identifier is as long as `into`; [`NanoIdLength`](https://rux-lang.dev/docs/api/nanoid/alphabet#nano-id-length) characters is the standard length. Each character is one random byte, so a twenty-one-character identifier costs twenty-one bytes of entropy. Reports what the system reported when it could not supply random bytes, leaving `into` zeroized. An empty `into` succeeds and requests nothing. | Overload | Summary | | ------------------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------- | | `pub func GenerateNanoId(into: var char8[..]) -> ! EntropyError` | Fills the whole of `into` with an identifier from the default alphabet, using the operating system's generator. | | `pub func GenerateNanoId(into: var char8[..], alphabet: char8[..]) -> ! NanoIdError` | Fills the whole of `into` with an identifier drawn from `alphabet`, using the operating system's generator. | [Source](https://github.com/rux-lang/Rux/blob/main/Packages/NanoId/Src/Generate.rux#L56){rel=""nofollow""} **Parameters** | Name | Type | Description | | ---------- | --------------- | --------------------------------------------- | | `into` | `var char8[..]` | the destination, filled completely | | `alphabet` | `char8[..]` | between two and 256 distinct ASCII characters | **Returns**: success when every character was written ## `GenerateNanoIdFrom` ```rux pub func GenerateNanoIdFrom( source: &var EntropySource, into: var char8[..], alphabet: char8[..] ) -> ! NanoIdError ``` Fills the whole of `into` with an identifier drawn from `alphabet`, using random bytes from `source`. The seam for a test, or for a caller with its own generator: the identifier is exactly as unpredictable as the bytes `source` supplies, so a deterministic source gives deterministic identifiers. Reports an alphabet failure from [`ValidateAlphabet`](https://rux-lang.dev/docs/api/nanoid/alphabet#validate-alphabet) before using `source`, leaving `into` untouched, and `Entropy` with what `source` reported, leaving `into` zeroized. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/NanoId/Src/Generate.rux#L84){rel=""nofollow""} **Parameters** | Name | Type | Description | | ---------- | -------------------- | --------------------------------------------- | | `source` | `&var EntropySource` | where the random bytes come from | | `into` | `var char8[..]` | the destination, filled completely | | `alphabet` | `char8[..]` | between two and 256 distinct ASCII characters | **Returns**: success when every character was written # Alphabets The default alphabet and length, and checking a custom alphabet. ## `NanoIdAlphabet` ```rux pub const NanoIdAlphabet = "useandom-26T198340PX75pxJACKVERYMINDBUSHWOLF_GQZbfghjklqvwyzrict"; ``` Nano ID's default alphabet: the sixty-four URL-safe characters `A`–`Z`, `a`–`z`, `0`–`9`, `_` and `-`. Listed in the reference implementation's order, so the same random bytes give the same identifier here as there. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/NanoId/Src/Alphabet.rux#L16){rel=""nofollow""} ## `NanoIdLength` ```rux pub const NanoIdLength: uint = 21; ``` The default identifier length, in characters: twenty-one. Twenty-one characters of the default alphabet carry 126 random bits, more than the 122 of a version 4 UUID, in twenty-one characters where the UUID takes thirty-six. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/NanoId/Src/Alphabet.rux#L22){rel=""nofollow""} ## `ValidateAlphabet` ```rux pub func ValidateAlphabet(alphabet: char8[..]) -> ! NanoIdError ``` Checks that `alphabet` can be drawn from without bias. It must hold between two and 256 characters, all ASCII and all distinct. Reports `AlphabetTooSmall`, `AlphabetTooLarge`, `NonAsciiCharacter` or `DuplicateCharacter`, the last two with the offset of the offending byte. Runs in time linear in the alphabet's length and allocates nothing. [Source](https://github.com/rux-lang/Rux/blob/main/Packages/NanoId/Src/Alphabet.rux#L50){rel=""nofollow""} **Parameters** | Name | Type | Description | | ---------- | ----------- | ------------------------------------------------ | | `alphabet` | `char8[..]` | the characters an identifier would be drawn from | **Returns**: success when the alphabet is usable # API Reference This reference documents the packages that ship with Rux: every public type, interface, function and constant, what it does and where it lives in the source. It is for looking things up rather than learning — if you are new to the language, start with [Learn Rux](https://rux-lang.dev/docs/learn) or the [Rux Language Reference](https://rux-lang.dev/docs/lang). Rux has no monolithic runtime. Each package below is a dependency a project declares in its [manifest](https://rux-lang.dev/docs/packaging/manifest), and a program depends only on what it asks for. ::warning **Unstable API**:br None of these packages has a stable API yet. Names, signatures and behaviour may change between releases, and this reference changes with them. :: :api-packages ## Reading this reference Each package has an overview page listing everything it exports, and each type, interface or function has a page of its own. A type's members — constructors, methods, operators and constants — are sections of that page, so every one has a link of its own, such as `/docs/api/allocator/arena#reset`. - **Header** — the declaration's kind, the package version it describes, and a **Source** button that opens the declaration on GitHub. - **Sidebar** — inside a package, the sidebar lists that package only, grouped into interfaces, types, functions and constants. The menu above it switches to another package. - **Platform badges** — Linux, FreeBSD, macOS and Windows each bind one operating system's own entry points, with no portability layer, and build only for that platform. Guard every call to them with [conditional compilation](https://rux-lang.dev/docs/lang/comptime/conditional).